lib/gorillib/model/field.rb in gorillib-0.4.1pre vs lib/gorillib/model/field.rb in gorillib-0.4.2pre

- old
+ new

@@ -13,11 +13,11 @@ # [Gorillib::Model] Model owning this field attr_reader :model # [Hash] all options passed to the field not recognized by one of its own current fields - attr_reader :extra_attributes + attr_reader :_extra_attributes # Note: `Gorillib::Model::Field` is assembled in two pieces, so that it # can behave as a model itself. Defining `name` here, along with some # fudge in #initialize, provides enough functionality to bootstrap. # The fields are then defined properly at the end of the file. @@ -26,25 +26,27 @@ attr_reader :type class_attribute :visibilities, :instance_writer => false self.visibilities = { :reader => :public, :writer => :public, :receiver => :public, :tester => false } - # @param [#to_sym] name Field name # @param [#receive] type Factory for field values. To accept any object as-is, specify `Object` as the type. # @param [Gorillib::Model] model Field's owner # @param [Hash{Symbol => Object}] options Extended attributes # @option options [String] doc Description of the field's purpose # @option options [true, false, :public, :protected, :private] :reader Visibility for the reader (`#foo`) method; `false` means don't create one. # @option options [true, false, :public, :protected, :private] :writer Visibility for the writer (`#foo=`) method; `false` means don't create one. # @option options [true, false, :public, :protected, :private] :receiver Visibility for the receiver (`#receive_foo`) method; `false` means don't create one. # - def initialize(name, type, model, options={}) + def initialize(model, name, type, options={}) Validate.identifier!(name) + type_opts = options.extract!(:blankish, :empty_product, :items, :keys, :of) + type_opts[:items] = type_opts.delete(:of) if type_opts.has_key?(:of) + # @model = model @name = name.to_sym - @type = self.factory_for(type) + @type = Gorillib::Factory.factory_for(type, type_opts) default_visabilities = visibilities @visibilities = default_visabilities.merge( options.extract!(*default_visabilities.keys) ) @doc = options.delete(:name){ "#{name} field" } receive!(options) end @@ -54,33 +56,32 @@ # @return [String] the field name def to_s name.to_s end - def factory_for(type) - Gorillib::Factory(type) - end - # @return [String] Human-readable presentation of the field definition def inspect - args = [name.inspect, type.to_s] - "field(#{args.join(", ")})" + args = [name.inspect, type.to_s, attributes.reject{|k,v| k =~ /^(name|type)$/}.inspect] + "field(#{args.join(",")})" end + def inspect_compact + "field(#{name})" + end def to_hash - attributes.merge!(@visibility).merge!(@extra_attributes) + attributes.merge!(@visibility).merge!(@_extra_attributes) end def ==(val) - super && (val.extra_attributes == self.extra_attributes) && (val.model == self.model) + super && (val._extra_attributes == self._extra_attributes) && (val.model == self.model) end def self.receive(hsh) name = hsh.fetch(:name) type = hsh.fetch(:type) model = hsh.fetch(:model) - new(name, type, model, hsh) + new(model, name, type, hsh) end # # returns the visibility # @@ -108,25 +109,46 @@ # # Now we can construct the actual fields. # + field :position, Integer, :tester => true, :doc => "Indicates this is a positional initialization arg -- you can pass it as a plain value in the given slot to #initialize" + # Name of this field. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required) # @macro [attach] field # @attribute $1 # @return [$2] the $1 field $* - field :name, String, :writer => false, :doc => "The field name. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required)" + field :name, String, position: 0, writer: false, doc: "The field name. Must start with `[A-Za-z_]` and subsequently contain only `[A-Za-z0-9_]` (required)" - # Factory for the field's values - field :type, Class + field :type, Class, position: 1, doc: "Factory to generate field's values" - # Field's description - field :doc, String + field :doc, String, doc: "Field's description" # remove the attr_reader method (needed for scaffolding), leaving the meta_module method to remain remove_possible_method(:name) end + + + class SimpleCollectionField < Gorillib::Model::Field + field :item_type, Class, default: Whatever, doc: "Factory for collection items" + # field :collection_attrs, Hash, default: Hash.new, doc: "Extra attributes to pass to the collection on creation -- eg. key_method" + + def initialize(model, name, type, options={}) + super + collection_type = self.type + item_type = self.item_type + key_method = options[:key_method] if options[:key_method] + raise "Please supply an item type for #{self.inspect} -- eg 'collection #{name.inspect}, of: FooClass'" unless item_type + self.default ||= ->{ collection_type.new(item_type: item_type, belongs_to: self, key_method: key_method) } + end + + def inscribe_methods(model) + super + model.__send__(:define_collection_receiver, self) + end + end + end end # * aliases # * order