representable 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.textile +7 -0
- data/README.rdoc +60 -36
- data/lib/representable.rb +46 -23
- data/lib/representable/binding.rb +47 -0
- data/lib/representable/bindings/json_bindings.rb +19 -21
- data/lib/representable/bindings/xml_bindings.rb +13 -18
- data/lib/representable/definition.rb +8 -7
- data/lib/representable/json.rb +12 -11
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml.rb +10 -10
- data/test/definition_test.rb +10 -3
- data/test/json_test.rb +88 -52
- data/test/representable_test.rb +55 -46
- data/test/test_helper.rb +13 -0
- data/test/xml_test.rb +103 -55
- metadata +4 -3
    
        data/CHANGES.textile
    CHANGED
    
    | @@ -1,6 +1,13 @@ | |
| 1 | 
            +
            h2. 0.12.0
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * @:as@ is now @:class@.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
             | 
| 1 6 | 
             
            h2. 0.11.0
         | 
| 2 7 |  | 
| 3 8 | 
             
            * Representer modules can now be injected into objects using @#extend@.
         | 
| 9 | 
            +
            * The @:extend@ option allows setting a representer module for a typed property. This will extend the contained object at runtime roughly following the DCI pattern.
         | 
| 10 | 
            +
            * Renamed @#representable_property@ and @#representable_collection@ to @#property@ and @#collection@ as we don't have to fear namespace collisions in modules.
         | 
| 4 11 |  | 
| 5 12 | 
             
            h2. 0.10.3
         | 
| 6 13 |  | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -14,7 +14,7 @@ This keeps your representation knowledge in one place when implementing REST ser | |
| 14 14 |  | 
| 15 15 | 
             
            * Bidirectional - rendering and parsing
         | 
| 16 16 | 
             
            * OOP documents
         | 
| 17 | 
            -
            * Support for JSON and  | 
| 17 | 
            +
            * Support for JSON, XML and MessagePack
         | 
| 18 18 |  | 
| 19 19 |  | 
| 20 20 | 
             
            == Example
         | 
| @@ -26,33 +26,40 @@ Since you keep forgetting the heroes of your childhood you decide to implement a | |
| 26 26 |  | 
| 27 27 | 
             
            == Defining Representations
         | 
| 28 28 |  | 
| 29 | 
            +
            Representations are usually defined using a module. This makes them super flexibly, you'll see.
         | 
| 30 | 
            +
             | 
| 29 31 | 
             
              require 'representable/json'
         | 
| 30 32 |  | 
| 31 | 
            -
               | 
| 33 | 
            +
              module HeroRepresenter
         | 
| 32 34 | 
             
                include Representable::JSON
         | 
| 33 35 |  | 
| 34 | 
            -
                 | 
| 35 | 
            -
                 | 
| 36 | 
            +
                property :forename
         | 
| 37 | 
            +
                property :surename
         | 
| 36 38 | 
             
              end
         | 
| 37 39 |  | 
| 38 | 
            -
             | 
| 40 | 
            +
            By using #property we declare two simple attributes. Representable will automatically add accessors to the module.
         | 
| 39 41 |  | 
| 40 | 
            -
             | 
| 42 | 
            +
            To use your representer include it in the matching class. Note that you could reuse a representer in multiple classes. 
         | 
| 41 43 |  | 
| 42 | 
            -
               | 
| 43 | 
            -
             | 
| 44 | 
            -
                
         | 
| 45 | 
            -
                representable_property :forename
         | 
| 46 | 
            -
                representable_property :surename
         | 
| 44 | 
            +
              class Hero
         | 
| 45 | 
            +
              	include Representable
         | 
| 46 | 
            +
                include HeroRepresenter
         | 
| 47 47 | 
             
              end
         | 
| 48 48 |  | 
| 49 | 
            -
             | 
| 49 | 
            +
            Many people dislike including representers on class layer. You might also extend an object at runtime.
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              Hero.new.extend(HeroRepresenter)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            Alternatively, if you don't like modules (which you shouldn't),  declarations can be put into classes directly.
         | 
| 50 54 |  | 
| 51 55 | 
             
              class Hero
         | 
| 52 56 | 
             
                include Representable::JSON
         | 
| 53 | 
            -
                 | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                property :forename
         | 
| 59 | 
            +
                property :surename
         | 
| 54 60 | 
             
              end
         | 
| 55 61 |  | 
| 62 | 
            +
             | 
| 56 63 | 
             
            == Rendering
         | 
| 57 64 |  | 
| 58 65 | 
             
            Now let's create and render our first hero.
         | 
| @@ -77,12 +84,12 @@ See how easy this is? You can use an object-oriented method to read from the doc | |
| 77 84 |  | 
| 78 85 | 
             
            == Nesting
         | 
| 79 86 |  | 
| 80 | 
            -
            You need a second domain object. Every hero has a place  | 
| 87 | 
            +
            You need a second domain object. Every hero has a place it comes from.
         | 
| 81 88 |  | 
| 82 89 | 
             
              class Location
         | 
| 83 90 | 
             
                include Representable::JSON
         | 
| 84 91 |  | 
| 85 | 
            -
                 | 
| 92 | 
            +
                property :title
         | 
| 86 93 | 
             
              end
         | 
| 87 94 |  | 
| 88 95 | 
             
            Peter, where ya' from?
         | 
| @@ -92,11 +99,11 @@ Peter, where ya' from? | |
| 92 99 |  | 
| 93 100 | 
             
            It makes sense to embed the location in the hero's document.
         | 
| 94 101 |  | 
| 95 | 
            -
               | 
| 96 | 
            -
                 | 
| 102 | 
            +
              module HeroRepresenter
         | 
| 103 | 
            +
                property :origin, :class => Location
         | 
| 97 104 | 
             
              end
         | 
| 98 105 |  | 
| 99 | 
            -
            Using the +: | 
| 106 | 
            +
            Using the +:class+ option allows you to include other representable objects.
         | 
| 100 107 |  | 
| 101 108 | 
             
              peter.origin = neverland
         | 
| 102 109 | 
             
              peter.to_json
         | 
| @@ -117,26 +124,26 @@ Representable just creates objects from the parsed document - nothing more and n | |
| 117 124 |  | 
| 118 125 | 
             
            Heroes have features, special abilities that make 'em a superhero.
         | 
| 119 126 |  | 
| 120 | 
            -
               | 
| 121 | 
            -
                 | 
| 127 | 
            +
              module HeroRepresenter
         | 
| 128 | 
            +
                collection :features
         | 
| 122 129 | 
             
              end
         | 
| 123 130 |  | 
| 124 | 
            -
            The second API method is + | 
| 131 | 
            +
            The second representable API method is +collection+ and, well, declares a collection.
         | 
| 125 132 |  | 
| 126 133 | 
             
              peter.features = ["stays young", "can fly"]
         | 
| 127 134 | 
             
              peter.to_json
         | 
| 128 | 
            -
            #=> {"forename":"Peter","surename":"Pan","origin":{"title":"Neverland"},"features":["stays young","can fly"]}
         | 
| 135 | 
            +
              #=> {"forename":"Peter","surename":"Pan","origin":{"title":"Neverland"},"features":["stays young","can fly"]}
         | 
| 129 136 |  | 
| 130 137 |  | 
| 131 138 | 
             
            == Typed Collections
         | 
| 132 139 |  | 
| 133 | 
            -
            Ok, things start working out. Your hero has a name, an origin and a list of features so far. Why not  | 
| 140 | 
            +
            Ok, things start working out. Your hero has a name, an origin and a list of features so far. Why not allow adding buddies to Peter - nobody wants to be alone!
         | 
| 134 141 |  | 
| 135 | 
            -
               | 
| 136 | 
            -
                 | 
| 142 | 
            +
              module HeroRepresenter
         | 
| 143 | 
            +
                collection :friends, :class => Hero
         | 
| 137 144 | 
             
              end
         | 
| 138 145 |  | 
| 139 | 
            -
            Again, we type the collection by using the +: | 
| 146 | 
            +
            Again, we type the collection by using the +:class+ option.
         | 
| 140 147 |  | 
| 141 148 | 
             
              nick = Hero.new
         | 
| 142 149 | 
             
              nick.forename = "Nick"
         | 
| @@ -158,7 +165,7 @@ I always wanted to be Peter's bro... in this example it is possible! | |
| 158 165 |  | 
| 159 166 | 
             
            Representable is designed to be very simple. However, a few tweaks are available. What if you want to wrap your document?
         | 
| 160 167 |  | 
| 161 | 
            -
               | 
| 168 | 
            +
              module HeroRepresenter
         | 
| 162 169 | 
             
                self.representation_wrap = true
         | 
| 163 170 | 
             
              end
         | 
| 164 171 |  | 
| @@ -166,7 +173,7 @@ Representable is designed to be very simple. However, a few tweaks are available | |
| 166 173 |  | 
| 167 174 | 
             
            You can also provide a custom wrapper.
         | 
| 168 175 |  | 
| 169 | 
            -
               | 
| 176 | 
            +
              module HeroRepresenter
         | 
| 170 177 | 
             
                self.representation_wrap = :boy
         | 
| 171 178 | 
             
              end
         | 
| 172 179 |  | 
| @@ -177,23 +184,40 @@ You can also provide a custom wrapper. | |
| 177 184 |  | 
| 178 185 | 
             
            If your accessor name doesn't match the attribute name in the document, use the +:from+ matcher.
         | 
| 179 186 |  | 
| 180 | 
            -
               | 
| 181 | 
            -
                 | 
| 187 | 
            +
              module HeroRepresenter
         | 
| 188 | 
            +
                property :forename, :from => :i_am_called
         | 
| 182 189 | 
             
              end
         | 
| 183 190 |  | 
| 184 | 
            -
              peter.to_json #=> {" | 
| 191 | 
            +
              peter.to_json #=> {"i_am_called":"Peter","surename":"Pan"}
         | 
| 185 192 |  | 
| 186 193 |  | 
| 187 194 | 
             
            === Filtering
         | 
| 188 195 |  | 
| 189 | 
            -
            Representable allows you to skip properties when rendering or parsing.
         | 
| 190 | 
            -
             | 
| 191 | 
            -
              peter.to_json do |name|
         | 
| 192 | 
            -
                name == :forename
         | 
| 193 | 
            -
              end
         | 
| 196 | 
            +
            Representable allows you to skip and include properties when rendering or parsing.
         | 
| 194 197 |  | 
| 198 | 
            +
              peter.to_json(:include => :forename)
         | 
| 195 199 | 
             
              #=> {"forename":"Peter"}
         | 
| 196 200 |  | 
| 201 | 
            +
            It gives you convenient +:exclude+ and +:include+ options.
         | 
| 202 | 
            +
             | 
| 203 | 
            +
             | 
| 204 | 
            +
            == DCI
         | 
| 205 | 
            +
             | 
| 206 | 
            +
            Representers roughly follow the {DCI}[http://en.wikipedia.org/wiki/Data,_context_and_interaction] pattern when used on objects, only.
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              Hero.new.extend(HeroRepresenter)
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            The only difference is that you have to define which representers to use for typed properties.
         | 
| 211 | 
            +
             | 
| 212 | 
            +
            	module HeroRepresenter
         | 
| 213 | 
            +
            	  property :forename
         | 
| 214 | 
            +
            	  property :surename
         | 
| 215 | 
            +
            	  collection :features
         | 
| 216 | 
            +
            	  property :origin, :class => Location
         | 
| 217 | 
            +
            	  collection :friends, :class => Hero, :extend => HeroRepresenter
         | 
| 218 | 
            +
            	end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
            There's no need to specify a representer for the +origin+ property since the +Location+ class statically includes its representation. For +friends+, we can use +:extend+ to tell representable which module to mix in dynamically.
         | 
| 197 221 |  | 
| 198 222 | 
             
            == XML support
         | 
| 199 223 |  | 
    
        data/lib/representable.rb
    CHANGED
    
    | @@ -3,6 +3,7 @@ require 'representable/definition' | |
| 3 3 | 
             
            module Representable
         | 
| 4 4 | 
             
              def self.included(base)
         | 
| 5 5 | 
             
                base.class_eval do
         | 
| 6 | 
            +
                  extend ClassMethods
         | 
| 6 7 | 
             
                  extend ClassMethods::Declarations
         | 
| 7 8 | 
             
                  extend ClassMethods::Accessors
         | 
| 8 9 |  | 
| @@ -21,9 +22,9 @@ module Representable | |
| 21 22 | 
             
              end
         | 
| 22 23 |  | 
| 23 24 | 
             
              # Reads values from +doc+ and sets properties accordingly.
         | 
| 24 | 
            -
              def update_properties_from(doc, &block)
         | 
| 25 | 
            +
              def update_properties_from(doc, options, &block)
         | 
| 25 26 | 
             
                representable_bindings.each do |bin|
         | 
| 26 | 
            -
                  next if  | 
| 27 | 
            +
                  next if skip_property?(bin, options)
         | 
| 27 28 |  | 
| 28 29 | 
             
                  value = bin.read(doc) || bin.definition.default
         | 
| 29 30 | 
             
                  send(bin.definition.setter, value)
         | 
| @@ -33,9 +34,9 @@ module Representable | |
| 33 34 |  | 
| 34 35 | 
             
            private
         | 
| 35 36 | 
             
              # Compiles the document going through all properties.
         | 
| 36 | 
            -
              def create_representation_with(doc, &block)
         | 
| 37 | 
            +
              def create_representation_with(doc, options, &block)
         | 
| 37 38 | 
             
                representable_bindings.each do |bin|
         | 
| 38 | 
            -
                  next if  | 
| 39 | 
            +
                  next if skip_property?(bin, options)
         | 
| 39 40 |  | 
| 40 41 | 
             
                  value = send(bin.definition.getter) || bin.definition.default # DISCUSS: eventually move back to Ref.
         | 
| 41 42 | 
             
                  bin.write(doc, value) if value
         | 
| @@ -43,11 +44,11 @@ private | |
| 43 44 | 
             
                doc
         | 
| 44 45 | 
             
              end
         | 
| 45 46 |  | 
| 46 | 
            -
              #  | 
| 47 | 
            -
               | 
| 48 | 
            -
             | 
| 49 | 
            -
                 | 
| 50 | 
            -
                 | 
| 47 | 
            +
              # Checks and returns if the property should be included.
         | 
| 48 | 
            +
              def skip_property?(binding, options)
         | 
| 49 | 
            +
                return unless props = options[:except] || options[:include]
         | 
| 50 | 
            +
                res = props.include?(binding.definition.name.to_sym)
         | 
| 51 | 
            +
                options[:include] ? !res : res
         | 
| 51 52 | 
             
              end
         | 
| 52 53 |  | 
| 53 54 | 
             
              def representable_attrs
         | 
| @@ -65,6 +66,13 @@ private | |
| 65 66 |  | 
| 66 67 |  | 
| 67 68 | 
             
              module ClassMethods # :nodoc:
         | 
| 69 | 
            +
                # Create and yield object and options. Called in .from_json and friends. 
         | 
| 70 | 
            +
                def create_represented(document, *args)
         | 
| 71 | 
            +
                  new.tap do |represented|
         | 
| 72 | 
            +
                    yield represented, *args if block_given?
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
                
         | 
| 68 76 | 
             
                module Declarations
         | 
| 69 77 | 
             
                  def definition_class
         | 
| 70 78 | 
             
                    Definition
         | 
| @@ -74,13 +82,13 @@ private | |
| 74 82 | 
             
                  #
         | 
| 75 83 | 
             
                  # Examples:
         | 
| 76 84 | 
             
                  #
         | 
| 77 | 
            -
                  #    | 
| 78 | 
            -
                  #    | 
| 79 | 
            -
                  #    | 
| 80 | 
            -
                  #    | 
| 81 | 
            -
                  #    | 
| 82 | 
            -
                  def  | 
| 83 | 
            -
                    attr =  | 
| 85 | 
            +
                  #   property :name
         | 
| 86 | 
            +
                  #   property :name, :from => :title
         | 
| 87 | 
            +
                  #   property :name, :class => Name
         | 
| 88 | 
            +
                  #   property :name, :accessors => false
         | 
| 89 | 
            +
                  #   property :name, :default => "Mike"
         | 
| 90 | 
            +
                  def property(name, options={})
         | 
| 91 | 
            +
                    attr = add_property(name, options)
         | 
| 84 92 |  | 
| 85 93 | 
             
                    attr_reader(attr.getter) unless options[:accessors] == false
         | 
| 86 94 | 
             
                    attr_writer(attr.getter) unless options[:accessors] == false
         | 
| @@ -90,22 +98,23 @@ private | |
| 90 98 | 
             
                  #
         | 
| 91 99 | 
             
                  # Examples:
         | 
| 92 100 | 
             
                  #
         | 
| 93 | 
            -
                  #    | 
| 94 | 
            -
                  #    | 
| 95 | 
            -
                  #    | 
| 96 | 
            -
                  def  | 
| 101 | 
            +
                  #   collection :products
         | 
| 102 | 
            +
                  #   collection :products, :from => :item
         | 
| 103 | 
            +
                  #   collection :products, :class => Product
         | 
| 104 | 
            +
                  def collection(name, options={})
         | 
| 97 105 | 
             
                    options[:collection] = true
         | 
| 98 | 
            -
                     | 
| 106 | 
            +
                    property(name, options)
         | 
| 99 107 | 
             
                  end
         | 
| 100 108 |  | 
| 101 109 | 
             
                private
         | 
| 102 | 
            -
                  def  | 
| 110 | 
            +
                  def add_property(*args)
         | 
| 103 111 | 
             
                    definition_class.new(*args).tap do |attr|
         | 
| 104 112 | 
             
                      representable_attrs << attr
         | 
| 105 113 | 
             
                    end
         | 
| 106 114 | 
             
                  end
         | 
| 107 115 | 
             
                end
         | 
| 108 | 
            -
             | 
| 116 | 
            +
                
         | 
| 117 | 
            +
                
         | 
| 109 118 | 
             
                module Accessors
         | 
| 110 119 | 
             
                  def representable_attrs
         | 
| 111 120 | 
             
                    @representable_attrs ||= Config.new
         | 
| @@ -117,6 +126,7 @@ private | |
| 117 126 | 
             
                end
         | 
| 118 127 | 
             
              end
         | 
| 119 128 |  | 
| 129 | 
            +
              
         | 
| 120 130 | 
             
              class Config < Array
         | 
| 121 131 | 
             
                attr_accessor :wrap
         | 
| 122 132 |  | 
| @@ -135,4 +145,17 @@ private | |
| 135 145 | 
             
                   downcase
         | 
| 136 146 | 
             
                end
         | 
| 137 147 | 
             
              end
         | 
| 148 | 
            +
              
         | 
| 149 | 
            +
              
         | 
| 150 | 
            +
              # Allows mapping formats to representer classes.
         | 
| 151 | 
            +
              # DISCUSS: this module might be removed soon.
         | 
| 152 | 
            +
              module Represents
         | 
| 153 | 
            +
                def represents(format, options)
         | 
| 154 | 
            +
                  representer[format] = options[:with]
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
                
         | 
| 157 | 
            +
                def representer
         | 
| 158 | 
            +
                  @represents_map ||= {}
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
              end
         | 
| 138 161 | 
             
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            module Representable
         | 
| 2 | 
            +
              class Binding
         | 
| 3 | 
            +
                attr_reader :definition
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(definition)
         | 
| 6 | 
            +
                  @definition = definition
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                # Usually called in concrete ObjectBinding in #write and #read. 
         | 
| 11 | 
            +
                module Hooks
         | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
                  # Must be called in serialization of concrete ObjectBinding.
         | 
| 14 | 
            +
                  def write_object(object)
         | 
| 15 | 
            +
                    object
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  
         | 
| 18 | 
            +
                  # Creates a typed property instance.
         | 
| 19 | 
            +
                  def create_object
         | 
| 20 | 
            +
                    definition.sought_type.new
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                # Hooks into #write_object and #create_object to extend typed properties
         | 
| 26 | 
            +
                # at runtime.
         | 
| 27 | 
            +
                module Extend
         | 
| 28 | 
            +
                private
         | 
| 29 | 
            +
                  # Extends the object with its representer before serialization.
         | 
| 30 | 
            +
                  def write_object(object)
         | 
| 31 | 
            +
                    extend_for(super)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  
         | 
| 34 | 
            +
                  def create_object
         | 
| 35 | 
            +
                    extend_for(super)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                  def extend_for(object)  # TODO: test me.
         | 
| 39 | 
            +
                    if mod = definition.representer_module
         | 
| 40 | 
            +
                      object.extend(mod)
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    
         | 
| 43 | 
            +
                    object
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
| @@ -1,16 +1,8 @@ | |
| 1 | 
            +
            require 'representable/binding'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Representable
         | 
| 2 4 | 
             
              module JSON
         | 
| 3 | 
            -
                class Binding
         | 
| 4 | 
            -
                  attr_reader :definition
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                  def initialize(definition)
         | 
| 7 | 
            -
                    @definition = definition
         | 
| 8 | 
            -
                  end
         | 
| 9 | 
            -
                  
         | 
| 10 | 
            -
                  def read(hash)
         | 
| 11 | 
            -
                    value_from_hash(hash)
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
                  
         | 
| 5 | 
            +
                class Binding < Representable::Binding
         | 
| 14 6 | 
             
                private
         | 
| 15 7 | 
             
                  def collect_for(hash)
         | 
| 16 8 | 
             
                    nodes = hash[definition.from] or return
         | 
| @@ -27,9 +19,8 @@ module Representable | |
| 27 19 | 
             
                  def write(hash, value)
         | 
| 28 20 | 
             
                    hash[definition.from] = value
         | 
| 29 21 | 
             
                  end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
                  def value_from_hash(hash)
         | 
| 22 | 
            +
                  
         | 
| 23 | 
            +
                  def read(hash)
         | 
| 33 24 | 
             
                    collect_for(hash) do |value|
         | 
| 34 25 | 
             
                      value
         | 
| 35 26 | 
             
                    end
         | 
| @@ -38,20 +29,27 @@ module Representable | |
| 38 29 |  | 
| 39 30 | 
             
                # Represents a tag with object binding.
         | 
| 40 31 | 
             
                class ObjectBinding < Binding
         | 
| 41 | 
            -
                   | 
| 32 | 
            +
                  include Representable::Binding::Hooks # includes #create_object and #write_object.
         | 
| 33 | 
            +
                  include Representable::Binding::Extend
         | 
| 34 | 
            +
                  
         | 
| 35 | 
            +
                  def write(hash, object)
         | 
| 42 36 | 
             
                    if definition.array?
         | 
| 43 | 
            -
                      hash[definition.from] =  | 
| 37 | 
            +
                      hash[definition.from] = object.collect { |obj| serialize(obj) }
         | 
| 44 38 | 
             
                    else
         | 
| 45 | 
            -
                      hash[definition.from] =  | 
| 39 | 
            +
                      hash[definition.from] = serialize(object)
         | 
| 46 40 | 
             
                    end
         | 
| 47 41 | 
             
                  end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
                  def value_from_hash(hash)
         | 
| 42 | 
            +
                  
         | 
| 43 | 
            +
                  def read(hash)
         | 
| 51 44 | 
             
                    collect_for(hash) do |node|
         | 
| 52 | 
            -
                       | 
| 45 | 
            +
                      create_object.from_hash(node)
         | 
| 53 46 | 
             
                    end
         | 
| 54 47 | 
             
                  end
         | 
| 48 | 
            +
                  
         | 
| 49 | 
            +
                private
         | 
| 50 | 
            +
                  def serialize(object)
         | 
| 51 | 
            +
                    write_object(object).to_hash(:wrap => false)
         | 
| 52 | 
            +
                  end
         | 
| 55 53 | 
             
                end
         | 
| 56 54 | 
             
              end
         | 
| 57 55 | 
             
            end
         |