lib/representable/binding.rb in representable-1.3.4 vs lib/representable/binding.rb in representable-1.3.5

- old
+ new

@@ -9,11 +9,11 @@ def self.build(definition, *args) # DISCUSS: move #create_binding to this class? return definition.create_binding(*args) if definition.binding build_for(definition, *args) end - + def definition # TODO: remove in 1.4. raise "Binding#definition is no longer supported as all Definition methods are now delegated automatically." end def initialize(definition, represented, user_options={}) # TODO: remove default arg. @@ -21,35 +21,50 @@ @represented = represented @user_options = user_options end attr_reader :user_options, :represented # TODO: make private/remove. - + # Main entry point for rendering/parsing a property object. def serialize(value) value end - + def deserialize(fragment) fragment end - + # Retrieve value and write fragment to the doc. + def compile_fragment(doc) + return represented_exec_for(:writer, doc) if options[:writer] + + write_fragment(doc, get) + end + + # Parse value from doc and update the model property. + def uncompile_fragment(doc) + return represented_exec_for(:reader, doc) if options[:reader] + + read_fragment(doc) do |value| + set(value) + end + end + def write_fragment(doc, value) value = default_for(value) - + write_fragment_for(value, doc) end def write_fragment_for(value, doc) return if skipable_nil_value?(value) write(doc, value) end def read_fragment(doc) value = read_fragment_for(doc) - + if value == FragmentNotFound return unless has_default? value = default end @@ -59,65 +74,73 @@ def read_fragment_for(doc) read(doc) end def get - return represented.instance_exec(user_options, &options[:getter]) if options[:getter] + return represented_exec_for(:getter) if options[:getter] represented.send(getter) end def set(value) - value = represented.instance_exec(value, user_options, &options[:setter]) if options[:setter] + value = represented_exec_for(:setter, value) if options[:setter] represented.send(setter, value) end - - + + private + # Execute the block for +option_name+ on the represented object. + def represented_exec_for(option_name, *args) + return unless options[option_name] + represented.instance_exec(*args+[user_options], &options[option_name]) + end + + # Hooks into #serialize and #deserialize to extend typed properties # at runtime. module Extend # Extends the object with its representer before serialization. def serialize(*) extend_for(super) end - + def deserialize(*) extend_for(super) end - + def extend_for(object) if mod = representer_module_for(object) # :extend. object.extend(*mod) end object end - + private def representer_module_for(object, *args) call_proc_for(representer_module, object) # TODO: how to pass additional data to the computing block?` end def call_proc_for(proc, *args) return proc unless proc.is_a?(Proc) + # DISCUSS: use represented_exec_for here? @represented.instance_exec(*args, &proc) end end - + module Object include Binding::Extend # provides #serialize/#deserialize with extend. - + def serialize(object) return object if object.nil? - + super.send(serialize_method, @user_options.merge!({:wrap => false})) # TODO: pass :binding => self end - + def deserialize(data) # DISCUSS: does it make sense to skip deserialization of nil-values here? super(create_object(data)).send(deserialize_method, data, @user_options) end - + def create_object(fragment) instance_for(fragment) or class_for(fragment) end private @@ -129,10 +152,10 @@ def class_from(fragment, *args) call_proc_for(sought_type, fragment) end def instance_for(fragment, *args) - return unless options[:instance] + return unless options[:instance] call_proc_for(options[:instance], fragment) end end end end