module Gorillib::Model::ClassMethods

Attributes

_own_fields[R]

Public Instance Methods

assemble_positionals() click to toggle source
# File lib/gorillib/model/schema_magic.rb, line 57
def assemble_positionals
  positionals = fields.values.keep_if{|fld| fld.position? }.sort_by!{|fld| fld.position }
  return [] if positionals.empty?
  if (positionals.map(&:position) != (0..positionals.length-1).to_a) then raise ConflictingPositionError, "field positions #{positionals.map(&:position).join(",")} for #{positionals.map(&:name).join(",")} aren't in strict minimal order"  ; end
  positionals.map!(&:name)
end
attrs_hash_from_args(args) click to toggle source

turn model constructor args (‘*positional_args, {attrs}`) into a combined attrs hash. positional_args are mapped to the set of attribute names in order – by default, the class’ field names.

Notes:

  • Positional args always clobber elements of the attribute hash.

  • Nil positional args are treated as present-and-nil (this might change).

  • Raises an error if positional args

@param [Array] args list of attributes, in order, to map.

@return [Hash] a combined, reconciled hash of attributes to set

# File lib/gorillib/model/schema_magic.rb, line 77
def attrs_hash_from_args(args)
  attrs = args.extract_options!
  if args.present?
    ArgumentError.check_arity!(args, 0..positionals.length){ "extracting args #{args} for #{self}" }
    positionals_to_map = positionals[0..(args.length-1)]
    attrs = attrs.merge(Hash[positionals_to_map.zip(args)])
  end
  attrs
end
collection(field_name, collection_type, options={}) click to toggle source
# File lib/gorillib/model/schema_magic.rb, line 31
def collection(field_name, collection_type, options={})
  options[:item_type] = options[:of] if options.has_key?(:of)
  field(field_name, collection_type, {
      field_type: ::Gorillib::Model::SimpleCollectionField}.merge(options))
end
field(field_name, type, options={}) click to toggle source

Defines a new field

For each field that is defined, a getter and setter will be added as an instance method to the model. An Field instance will be added to result of the fields class method.

@example

field :height, Integer

@param [Symbol] field_name The field name. Must start with ‘[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` @param [Class] type The field’s type (required) @option options [String] doc Documentation string for the field (optional) @option options [Proc, Object] default Default value, or proc that instance can evaluate to find default value

@return Gorillib::Model::Field

# File lib/gorillib/model/schema_magic.rb, line 21
def field(field_name, type, options={})
  options = options.symbolize_keys
  field_type = options.delete(:field_type){ ::Gorillib::Model::Field }
  fld = field_type.new(self, field_name, type, options)
  @_own_fields[fld.name] = fld
  _reset_descendant_fields
  fld.send(:inscribe_methods, self)
  fld
end
field_names() click to toggle source

@return [Array<Symbol>] The attribute names

# File lib/gorillib/model/schema_magic.rb, line 49
def field_names
  @_field_names ||= fields.keys
end
fields() click to toggle source

@return [{Symbol => Gorillib::Model::Field}]

# File lib/gorillib/model/schema_magic.rb, line 38
def fields
  return @_fields if defined?(@_fields)
  @_fields = ancestors.reverse.inject({}){|acc, ancestor| acc.merge!(ancestor.try(:_own_fields) || {}) }
end
from_tuple(*vals) click to toggle source
# File lib/gorillib/model/serialization.rb, line 35
def from_tuple(*vals)
  receive Hash[field_names[0..vals.length-1].zip(vals)]
end
has_field?(field_name) click to toggle source

@return [true, false] true if the field is defined on this class

# File lib/gorillib/model/schema_magic.rb, line 44
def has_field?(field_name)
  fields.has_key?(field_name)
end
inspect() click to toggle source

@return Class name and its attributes

@example Inspect the model’s definition.

Person.inspect #=> Person[first_name, last_name]
# File lib/gorillib/model/base.rb, line 256
def inspect
  "#{self.name || 'anon'}[#{ field_names.join(",") }]"
end
inspect_compact() click to toggle source
# File lib/gorillib/model/base.rb, line 259
def inspect_compact() self.name || inspect ; end
native?(obj) click to toggle source

A ‘native` object does not need any transformation; it is accepted directly. By default, an object is native if it `is_a?` this class

@param obj [Object] the object that will be received @return [true, false] true if the item does not need conversion

# File lib/gorillib/model/base.rb, line 248
def native?(obj)
  obj.is_a?(self)
end
positionals() click to toggle source
# File lib/gorillib/model/schema_magic.rb, line 53
def positionals
  @_positionals ||= assemble_positionals
end
receive(attrs={}, &block) click to toggle source

Receive external data, type-converting and creating contained models as necessary

@return [Gorillib::Model] the new object

# File lib/gorillib/model/base.rb, line 232
def receive(attrs={}, &block)
  return nil if attrs.nil?
  return attrs if native?(attrs)
  #
  Gorillib::Model::Validate.hashlike!(attrs){ "attributes for #{self.inspect}" }
  klass = attrs.has_key?(:_type) ? Gorillib::Factory(attrs[:_type]) : self
  warn "factory #{klass} is not a type of #{self} as specified in #{attrs}" unless klass <= self
  #
  klass.new(attrs, &block)
end
typename() click to toggle source

A readable handle for this field

# File lib/gorillib/model/base.rb, line 224
def typename
  @typename ||= ActiveSupport::Inflector.underscore(self.name||'anon').gsub(%r{/}, '.')
end

Protected Instance Methods

_reset_descendant_fields() click to toggle source

Ensure that classes inherit all their parents’ fields, even if fields are added after the child class is defined.

# File lib/gorillib/model/schema_magic.rb, line 93
def _reset_descendant_fields
  ObjectSpace.each_object(::Class) do |klass|
    klass.__send__(:remove_instance_variable, '@_fields')      if (klass <= self) && klass.instance_variable_defined?('@_fields')
    klass.__send__(:remove_instance_variable, '@_field_names') if (klass <= self) && klass.instance_variable_defined?('@_field_names')
    klass.__send__(:remove_instance_variable, '@_positionals') if (klass <= self) && klass.instance_variable_defined?('@_positionals')
  end
end
define_attribute_reader(field_name, field_type, visibility) click to toggle source

define the reader method ‘#foo` for a field named `:foo`

# File lib/gorillib/model/schema_magic.rb, line 102
def define_attribute_reader(field_name, field_type, visibility)
  define_meta_module_method(field_name, visibility) do
    begin
      read_attribute(field_name)
    rescue StandardError => err ; err.polish("#{self.class}.#{field_name}") rescue nil ; raise ; end
  end
end
define_attribute_receiver(field_name, field_type, visibility) click to toggle source
# File lib/gorillib/model/schema_magic.rb, line 125
def define_attribute_receiver(field_name, field_type, visibility)
  # @param  [Object] val the raw value to type-convert and adopt
  # @return [Object] the attribute's new value
  define_meta_module_method("receive_#{field_name}", visibility) do |val|
    begin
      val = field_type.receive(val)
      write_attribute(field_name, val)
    rescue StandardError => err ; err.polish("#{self.class}.#{field_name} type #{type} on #{val}") rescue nil ; raise ; end
  end
end
define_attribute_tester(field_name, field_type, visibility) click to toggle source

define the present method ‘#foo?` for a field named `:foo`

# File lib/gorillib/model/schema_magic.rb, line 118
def define_attribute_tester(field_name, field_type, visibility)
  field = fields[field_name]
  define_meta_module_method("#{field_name}?", visibility) do
    attribute_set?(field_name) || field.has_default?
  end
end
define_attribute_writer(field_name, field_type, visibility) click to toggle source

define the writer method ‘#foo=` for a field named `:foo`

# File lib/gorillib/model/schema_magic.rb, line 111
def define_attribute_writer(field_name, field_type, visibility)
  define_meta_module_method("#{field_name}=", visibility) do |val|
    write_attribute(field_name, val)
  end
end
define_collection_receiver(field) click to toggle source

Collection receiver –

# File lib/gorillib/model/schema_magic.rb, line 139
def define_collection_receiver(field)
  collection_field_name = field.name; collection_type = field.type
  # @param  [Array[Object],Hash[Object]] the collection to merge
  # @return [Gorillib::Collection] the updated collection
  define_meta_module_method("receive_#{collection_field_name}", true) do |coll, &block|
    begin
      if collection_type.native?(coll)
        write_attribute(collection_field_name, coll)
      else
        read_attribute(collection_field_name).receive!(coll, &block)
      end
    rescue StandardError => err ; err.polish("#{self.class} #{collection_field_name} collection on #{args}'") rescue nil ; raise ; end
  end
end
inherited(base) click to toggle source
Calls superclass method
# File lib/gorillib/model/schema_magic.rb, line 154
def inherited(base)
  base.instance_eval do
    self.meta_module
    @_own_fields ||= {}
  end
  super
end