lib/representable.rb in representable-0.11.0 vs lib/representable.rb in representable-0.12.0

- old
+ new

@@ -1,10 +1,11 @@ require 'representable/definition' module Representable def self.included(base) base.class_eval do + extend ClassMethods extend ClassMethods::Declarations extend ClassMethods::Accessors def self.included(base) base.representable_attrs.push(*representable_attrs) # "inherit". @@ -19,37 +20,37 @@ end end end # Reads values from +doc+ and sets properties accordingly. - def update_properties_from(doc, &block) + def update_properties_from(doc, options, &block) representable_bindings.each do |bin| - next if eval_property_block(bin, &block) # skip if block is false. + next if skip_property?(bin, options) value = bin.read(doc) || bin.definition.default send(bin.definition.setter, value) end self end private # Compiles the document going through all properties. - def create_representation_with(doc, &block) + def create_representation_with(doc, options, &block) representable_bindings.each do |bin| - next if eval_property_block(bin, &block) # skip if block is false. + next if skip_property?(bin, options) value = send(bin.definition.getter) || bin.definition.default # DISCUSS: eventually move back to Ref. bin.write(doc, value) if value end doc end - # Returns true unless a eventually given block returns false. Yields the symbolized - # property name. - def eval_property_block(binding) - # TODO: no magic symbol conversion! - block_given? and not yield binding.definition.name.to_sym + # Checks and returns if the property should be included. + def skip_property?(binding, options) + return unless props = options[:except] || options[:include] + res = props.include?(binding.definition.name.to_sym) + options[:include] ? !res : res end def representable_attrs @representable_attrs ||= self.class.representable_attrs # DISCUSS: copy, or better not? end @@ -63,51 +64,59 @@ representable_attrs.wrap_for(self.class.name) end module ClassMethods # :nodoc: + # Create and yield object and options. Called in .from_json and friends. + def create_represented(document, *args) + new.tap do |represented| + yield represented, *args if block_given? + end + end + module Declarations def definition_class Definition end # Declares a represented document node, which is usually a XML tag or a JSON key. # # Examples: # - # representable_property :name - # representable_property :name, :from => :title - # representable_property :name, :as => Name - # representable_property :name, :accessors => false - # representable_property :name, :default => "Mike" - def representable_property(name, options={}) - attr = add_representable_property(name, options) + # property :name + # property :name, :from => :title + # property :name, :class => Name + # property :name, :accessors => false + # property :name, :default => "Mike" + def property(name, options={}) + attr = add_property(name, options) attr_reader(attr.getter) unless options[:accessors] == false attr_writer(attr.getter) unless options[:accessors] == false end # Declares a represented document node collection. # # Examples: # - # representable_collection :products - # representable_collection :products, :from => :item - # representable_collection :products, :as => Product - def representable_collection(name, options={}) + # collection :products + # collection :products, :from => :item + # collection :products, :class => Product + def collection(name, options={}) options[:collection] = true - representable_property(name, options) + property(name, options) end private - def add_representable_property(*args) + def add_property(*args) definition_class.new(*args).tap do |attr| representable_attrs << attr end end end - + + module Accessors def representable_attrs @representable_attrs ||= Config.new end @@ -115,10 +124,11 @@ representable_attrs.wrap = name end end end + class Config < Array attr_accessor :wrap # Computes the wrap string or returns false. def wrap_for(name) @@ -131,8 +141,21 @@ def infer_name_for(name) name.to_s.split('::').last. gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). downcase + end + end + + + # Allows mapping formats to representer classes. + # DISCUSS: this module might be removed soon. + module Represents + def represents(format, options) + representer[format] = options[:with] + end + + def representer + @represents_map ||= {} end end end