Class: MetaHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/metaheader.rb,
lib/metaheader/version.rb

Overview

Parser for metadata header in plain-text files

Examples:

mh = MetaHeader.parse '@hello world'
puts mh[:hello]

Constant Summary collapse

OPTIONAL =

Allow a tag to be omitted when validating in strict mode.

Object.new.freeze
REQUIRED =

Ensure a tag exists during validation.

Object.new.freeze
BOOLEAN =

The tag cannot hold a value beside true or false during validation.

Object.new.freeze
VALUE =

The tag must have a string value (non-boolean tag) during validation.

Object.new.freeze
SINGLELINE =

Don't allow multiline values during validation.

Object.new.freeze
VERSION =

MetaHeader's version

'2.0.0'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMetaHeader

Construct a blank MetaHeader object


41
42
43
# File 'lib/metaheader.rb', line 41

def initialize
  @data = {}
end

Class Method Details

.from_file(path) ⇒ MetaHeader

Create a new instance from the contents of a file.

Parameters:

  • path (String)

    path to the file to be read

Returns:


26
27
28
# File 'lib/metaheader.rb', line 26

def self.from_file(path)
  File.open(path) {|file| self.parse file }
end

.parse(input) ⇒ MetaHeader

Construct a MetaHeader object and parse every tags found in the input up to the first newline.

Parameters:

  • input (String, IO, StringIO)

Returns:


34
35
36
37
38
# File 'lib/metaheader.rb', line 34

def self.parse(input)
  mh = MetaHeader.new
  mh.parse input
  mh
end

Instance Method Details

#[](key, default = nil) ⇒ Object?

Returns the value of a tag by its name, or nil if not found.

Parameters:

  • key (Symbol)

    tag name

  • default (Object) (defaults to: nil)

    value to return if key doesn't exist

Returns:

  • (Object, nil)

71
72
73
74
75
76
77
# File 'lib/metaheader.rb', line 71

def [](key, default = nil)
  if tag = @data[key]
    tag.value
  else
    default
  end
end

#[]=(key, value) ⇒ Object

Replaces the value of a tag.

Parameters:

  • value

    the new value

Returns:

  • (Object)

    value

Raises:

  • (ArgumentError)

82
83
84
85
86
87
# File 'lib/metaheader.rb', line 82

def []=(key, value)
  raise ArgumentError, 'value cannot be nil' if value.nil?

  @data[key] ||= Tag.new key
  @data[key].value = value
end

#alias(old, new = nil) ⇒ Object

Rename one or more tags.

Examples:

mh.alias :old, :new
mh.alias [:old1, :old2], :new
mh.alias old1: :new1, old2: :new2

Parameters:

  • old (Symbol, Array<Symbol>, Hash<Symbol, Symbol>)
  • new (Symbol) (defaults to: nil)

    Ignored if old is a Hash


167
168
169
170
171
172
173
174
175
# File 'lib/metaheader.rb', line 167

def alias(old, new = nil)
  if old.is_a? Hash
    old.each {|k, v| self.alias k, v }
  else
    Array(old).each {|tag|
      @data[new] = delete tag if has? tag
    }
  end
end

#delete(tag) ⇒ Object

Removes a given tag from the list.

Parameters:

  • tag (Symbol)

    the tag to remove


110
111
112
# File 'lib/metaheader.rb', line 110

def delete(tag)
  @data.delete tag
end

#empty?Boolean

Whether any tags were found in the input.

Returns:

  • (Boolean)

97
98
99
# File 'lib/metaheader.rb', line 97

def empty?
  @data.empty?
end

#has?(tag) ⇒ Boolean

Whether a tag was found in the input.

Parameters:

  • tag (Symbol)

    the tag to lookup

Returns:

  • (Boolean)

104
105
106
# File 'lib/metaheader.rb', line 104

def has?(tag)
  @data.has_key? tag
end

#inspectString

Makes a human-readable representation of the current instance.

Returns:

  • (String)

122
123
124
# File 'lib/metaheader.rb', line 122

def inspect
  "#<#{self.class} #{to_h}>"
end

#parse(input) ⇒ Integer

Parse every tags found in the input up to the first newline. data following the header.

Parameters:

  • input (String, IO, StringIO)

Returns:

  • (Integer)

    Character position of the first content line in the input


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/metaheader.rb', line 49

def parse(input)
  if input.is_a? String
    input = StringIO.new input.encode universal_newline: true
  end

  @last_tag = nil
  @empty_lines = 0

  content_offset = 0
  input.each_line do |line|
    full_line_size = line.size # parse_line can trim the line
    continue = parse_line line
    content_offset += full_line_size if continue || line.empty?
    break unless continue
  end
  content_offset
end

#sizeInteger

Returns how many tags were found in the input.

Returns:

  • (Integer)

91
92
93
# File 'lib/metaheader.rb', line 91

def size
  @data.size
end

#to_hHash<Symbol, Object>

Make a hash from the parsed data

Returns:

  • (Hash<Symbol, Object>)

116
117
118
# File 'lib/metaheader.rb', line 116

def to_h
  Hash[@data.map {|name, tag| [name, tag.value] }]
end

#validate(rules, strict = false) ⇒ Array<String>

Validates parsed data according to a custom set of rules. A rule can be one of the predefined constants, a regex, a proc or a method (returing nil if the tag is valid or an error string otherwise).

Examples:

mh = MetaHeader.new "@hello world\[email protected] bacon"
mh.validate \
  hello: [MetaHeader::REQUIRED, MetaHeader::SINGLELINE, /\d/],
  chunky: proc {|value| 'not bacon' unless value == 'bacon' }

Parameters:

  • rules (Hash)

    :tag_name => rule or [rule1, rule2, …]

  • strict (Boolean) (defaults to: false)

    Whether to report unknown tags as errors

Returns:

  • (Array<String>)

    List of error messasges

See Also:


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/metaheader.rb', line 142

def validate(rules, strict = false)
  errors = []

  if strict
    @data.each {|key, tag|
      errors << "unknown tag '%s'" % tag.name unless rules.has_key? key
    }
  end

  rules.each_pair {|key, rule|
    if key_error = validate_key(key, rule)
      errors << key_error
    end
  }

  errors
end