Module: HashObject::ClassMethods

Defined in:
lib/hash_object.rb

Overview

Include the given class methods that will be used to create associated element mappings.

Instance Method Summary collapse

Instance Method Details

#boolean(sym, options = {}) ⇒ nil

Maps an element to a boolean value using the BooleanConverter.

Parameters:

  • sym (Symbol)

    The name of the boolean property

  • options (Hash) (defaults to: {})

    The configuration options (see #element)

Returns:

  • (nil)


197
198
199
# File 'lib/hash_object.rb', line 197

def boolean(sym, options={})
  element(sym, {:type => BooleanConverter, :single => true, :reader => false}.merge(options))
end

#element(sym, options = {}) ⇒ nil

Creates a new element mapping with the given name. This mapping can be highly customized by the options passed in. In fact, the other mapping methods on this class (see #boolean #has_many) simply delegate to this method.

Parameters:

  • sym (Symbol)

    The name of the new property for this object.

  • options (Hash) (defaults to: {})

    The options that alter how the element is mapped.

Options Hash (options):

  • :reader (Boolean)

    Whether we support only an attr_writer. This is a bit weird, as it essentially hides the element from outside objects, but it can be useful when going for information hiding, since the ‘@sym’ name is still visible inside the object.

  • :single (Boolean)

    Whether we map only a single element. Otherwise, we map many elements (see #has_many).

  • :qname (Symbol)

    The “question” type name for the method. Since all of the method definitions create a ‘element?’ method in addition to the standard ‘element’ methods, to see if the property is set, you can customize the name of the question mark method here. Leave off the ‘?’ at the end, though.

  • :required (Boolean)

    Whether this element is required. Default is true.

  • :default (Object, Proc)

    The default value for the element, if not seen.

  • :name (String, Symbol)

    The actual key in the hash that we are mapping to, if it is not the actual ‘sym’ that we passed in.

  • :builder (Proc)

    A builder proc that will do the actual parsing, circumventing the standard #parse method.

  • :type (Class)

    The type that will be used to parse this element.

Returns:

  • (nil)


157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/hash_object.rb', line 157

def element(sym, options={})
  if options[:reader] == false
    attr_writer sym
  else
    attr_accessor sym
  end
  if options[:single].nil?
    options[:single] ||= true
  end
  if options[:single]
    self.class_eval <<EOF, __FILE__, __LINE__
      def #{options[:qname] || sym}?
        !!@#{sym}
      end
EOF
  else
    self.class_eval <<EOF, __FILE__, __LINE__
      def #{options[:qname] || sym}?
        if @#{sym}.nil?
          false
        else
          !@#{sym}.empty?
        end
      end
EOF
  end

  elem = Element.new(sym, options)
  @_elements[sym.to_s] = elem
  if options[:name]
    @_elements[options[:name]] = elem
  end
  nil
end

#has_many(sym, options = {}) ⇒ Object

Maps an array of child elements into a property.

Parameters:

  • sym (Symbol)

    The name of the many property mappings

  • options (Hash) (defaults to: {})

    The configuration options (see #element)



205
206
207
# File 'lib/hash_object.rb', line 205

def has_many(sym, options={})
  element(sym, {:single => false}.merge(options))
end

#parse(hash) ⇒ Object

The parse method is what actually unpacks the hash object into a reified object. It does require that the object be a hash. If you have nested mappings, this method will be called when the child hash objects are parsed into reified objects. The only time that isn’t the case is when you have a builder that handles that object construction for you.

Parameters:

  • The (Hash)

    hash that we are going to unpack.

Returns:

  • (Object)

    The object that got built.

Raises:

  • (ArgumentError)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/hash_object.rb', line 218

def parse(hash)
  raise ArgumentError, "Requires a hash to read in" unless hash.is_a?(Hash)
  obj = new

  # Exclude from checking elements we've already matched
  matching_names = []

  hash.each do |key, value|
    if elem = @_elements[key]
      elem.set(obj, value)
      matching_names << elem.sym.to_s if elem.name == key
    elsif @_strict
      raise ConfigurationError, "Unsupported attribute '#{key}: #{value}' for #{self.name}"
    end
  end

  @_elements.each do |key, elem|
    next if hash.has_key?(key)
    next if matching_names.include?(key)
    elem.set_default(obj) 
  end

  obj
end

#strict(bool) ⇒ nil

Whether we will strictly enforce the mapping – i.e., will we fail if there are elements in the hash that we don’t understand. The default is false.

Parameters:

  • bool (Boolean)

    Whether to make this mapping strict.

Returns:

  • (nil)


127
128
129
# File 'lib/hash_object.rb', line 127

def strict(bool)
  @_strict = !!bool
end