representable 0.0.1.alpha1 → 0.0.1

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.
Files changed (102) hide show
  1. data/README.rdoc +58 -153
  2. data/lib/representable.rb +18 -42
  3. data/lib/representable/bindings/json_bindings.rb +69 -0
  4. data/lib/representable/bindings/xml_bindings.rb +152 -0
  5. data/lib/representable/definition.rb +1 -12
  6. data/lib/representable/json.rb +66 -0
  7. data/lib/representable/version.rb +1 -1
  8. data/lib/representable/xml.rb +32 -38
  9. data/representable.gemspec +3 -2
  10. data/test/bindings_test.rb +110 -0
  11. data/test/json_test.rb +130 -0
  12. data/test/{roxml_test.rb → representable_test.rb} +28 -9
  13. data/test/test_helper.rb +2 -0
  14. data/test/xml_test.rb +192 -0
  15. metadata +32 -105
  16. data/History.txt +0 -354
  17. data/TODO +0 -37
  18. data/VERSION +0 -1
  19. data/examples/amazon.rb +0 -35
  20. data/examples/current_weather.rb +0 -27
  21. data/examples/dashed_elements.rb +0 -20
  22. data/examples/library.rb +0 -40
  23. data/examples/posts.rb +0 -27
  24. data/examples/rails.rb +0 -70
  25. data/examples/twitter.rb +0 -37
  26. data/examples/xml/active_record.xml +0 -70
  27. data/examples/xml/amazon.xml +0 -133
  28. data/examples/xml/current_weather.xml +0 -89
  29. data/examples/xml/dashed_elements.xml +0 -52
  30. data/examples/xml/posts.xml +0 -23
  31. data/examples/xml/twitter.xml +0 -422
  32. data/lib/representable/references.rb +0 -153
  33. data/spec/definition_spec.rb +0 -495
  34. data/spec/examples/active_record_spec.rb +0 -41
  35. data/spec/examples/amazon_spec.rb +0 -54
  36. data/spec/examples/current_weather_spec.rb +0 -37
  37. data/spec/examples/dashed_elements_spec.rb +0 -20
  38. data/spec/examples/library_spec.rb +0 -46
  39. data/spec/examples/post_spec.rb +0 -24
  40. data/spec/examples/twitter_spec.rb +0 -32
  41. data/spec/roxml_integration_test.rb +0 -289
  42. data/spec/roxml_spec.rb +0 -372
  43. data/spec/shared_specs.rb +0 -15
  44. data/spec/spec_helper.rb +0 -5
  45. data/spec/support/libxml.rb +0 -3
  46. data/spec/support/nokogiri.rb +0 -3
  47. data/spec/xml/array_spec.rb +0 -36
  48. data/spec/xml/attributes_spec.rb +0 -71
  49. data/spec/xml/encoding_spec.rb +0 -53
  50. data/spec/xml/namespace_spec.rb +0 -270
  51. data/spec/xml/namespaces_spec.rb +0 -67
  52. data/spec/xml/object_spec.rb +0 -82
  53. data/spec/xml/parser_spec.rb +0 -21
  54. data/spec/xml/text_spec.rb +0 -71
  55. data/test/fixtures/book_malformed.xml +0 -5
  56. data/test/fixtures/book_pair.xml +0 -8
  57. data/test/fixtures/book_text_with_attribute.xml +0 -5
  58. data/test/fixtures/book_valid.xml +0 -5
  59. data/test/fixtures/book_with_authors.xml +0 -7
  60. data/test/fixtures/book_with_contributions.xml +0 -9
  61. data/test/fixtures/book_with_contributors.xml +0 -7
  62. data/test/fixtures/book_with_contributors_attrs.xml +0 -7
  63. data/test/fixtures/book_with_default_namespace.xml +0 -9
  64. data/test/fixtures/book_with_depth.xml +0 -6
  65. data/test/fixtures/book_with_octal_pages.xml +0 -4
  66. data/test/fixtures/book_with_publisher.xml +0 -7
  67. data/test/fixtures/book_with_wrapped_attr.xml +0 -3
  68. data/test/fixtures/dictionary_of_attr_name_clashes.xml +0 -8
  69. data/test/fixtures/dictionary_of_attrs.xml +0 -6
  70. data/test/fixtures/dictionary_of_guarded_names.xml +0 -6
  71. data/test/fixtures/dictionary_of_mixeds.xml +0 -4
  72. data/test/fixtures/dictionary_of_name_clashes.xml +0 -10
  73. data/test/fixtures/dictionary_of_names.xml +0 -4
  74. data/test/fixtures/dictionary_of_texts.xml +0 -10
  75. data/test/fixtures/library.xml +0 -30
  76. data/test/fixtures/library_uppercase.xml +0 -30
  77. data/test/fixtures/muffins.xml +0 -3
  78. data/test/fixtures/nameless_ageless_youth.xml +0 -2
  79. data/test/fixtures/node_with_attr_name_conflicts.xml +0 -1
  80. data/test/fixtures/node_with_name_conflicts.xml +0 -4
  81. data/test/fixtures/numerology.xml +0 -4
  82. data/test/fixtures/person.xml +0 -1
  83. data/test/fixtures/person_with_guarded_mothers.xml +0 -13
  84. data/test/fixtures/person_with_mothers.xml +0 -10
  85. data/test/mocks/dictionaries.rb +0 -57
  86. data/test/mocks/mocks.rb +0 -279
  87. data/test/support/fixtures.rb +0 -11
  88. data/test/unit/definition_test.rb +0 -235
  89. data/test/unit/deprecations_test.rb +0 -24
  90. data/test/unit/to_xml_test.rb +0 -81
  91. data/test/unit/xml_attribute_test.rb +0 -39
  92. data/test/unit/xml_block_test.rb +0 -81
  93. data/test/unit/xml_bool_test.rb +0 -122
  94. data/test/unit/xml_convention_test.rb +0 -150
  95. data/test/unit/xml_hash_test.rb +0 -115
  96. data/test/unit/xml_initialize_test.rb +0 -49
  97. data/test/unit/xml_name_test.rb +0 -141
  98. data/test/unit/xml_namespace_test.rb +0 -31
  99. data/test/unit/xml_object_test.rb +0 -206
  100. data/test/unit/xml_required_test.rb +0 -94
  101. data/test/unit/xml_text_test.rb +0 -71
  102. data/website/index.html +0 -98
@@ -1,186 +1,91 @@
1
- ROXML Ruby Object to XML mapping library.
1
+ = Representable
2
2
 
3
- For more information visit:
3
+ <em>Maps representation documents from and to Ruby objects.</em>
4
4
 
5
- http://rdoc.info/projects/Empact/roxml
6
- http://empact.github.com/roxml/
7
- http://rubyforge.org/projects/roxml/
8
5
 
9
- Please submit bugs here:
6
+ == Introduction
10
7
 
11
- http://github.com/Empact/roxml/issues
8
+ _Representable_ maps fragments in documents to attributes in Ruby objects and back. It allows parsing representations and gives an object-oriented interface to the document. But that's only half of it! Representable can also render documents from an object instance.
12
9
 
13
- =Quick Start Guide
10
+ This is especially helpful when implementing REST services and clients and keeps your representation knowledge in one place.
14
11
 
15
- This is a short usage example. See ROXML::ClassMethods::Declarations and packaged test cases for more information.
12
+ == Example
16
13
 
17
- ==Basic Mapping
14
+ When writing a REST service you'd have to parse and extract data from an incoming representation document manually. Given the following XML document which represents an order.
18
15
 
19
- Consider an XML document representing a Library containing a number of Books. You
20
- can map this structure to Ruby classes that provide addition useful behavior. With
21
- ROXML, you can annotate the Ruby classes as follows:
16
+ <order>
17
+ <id>1</id>
18
+ <item>
19
+ <name>Chocolate Cookie</name>
20
+ </item>
21
+ <item>
22
+ <name>Vanilla Muffin</name>
23
+ </item>
24
+ </order>
22
25
 
23
- class Book
24
- include ROXML
26
+ Now, parsing manually starts simple but gets complex soon. In the end, you have a nested hash data structure. Try this with Representable.
25
27
 
26
- xml_accessor :isbn, :from => "@ISBN" # attribute with name 'ISBN'
27
- xml_accessor :title
28
- xml_accessor :description, :cdata => true # text node with cdata protection
29
- xml_accessor :author
28
+ class Order
29
+ include Representable::XML
30
+
31
+ representable_property :id
32
+ representable_collection :items, :tag => :item, :as => Item
30
33
  end
31
-
32
- class Library
33
- include ROXML
34
-
35
- xml_accessor :name, :from => "NAME", :cdata => true
36
- xml_accessor :books, :as => [Book] # by default roxml searches for books for in <book> child nodes, then, if none are present, in ./books/book children
37
- end
38
-
39
- To create a library and put a number of books in it we could run the following code:
40
-
41
- book = Book.new
42
- book.isbn = "0201710897"
43
- book.title = "The PickAxe"
44
- book.description = "Best Ruby book out there!"
45
- book.author = "David Thomas, Andrew Hunt, Dave Thomas"
46
-
47
- lib = Library.new
48
- lib.name = "Favorite Books"
49
- lib.books = [book]
50
-
51
- To save this information to an XML file:
52
-
53
- doc = Nokogiri::XML::Document.new
54
- doc.root = lib.to_xml
55
- open("library.xml", 'w') do |file|
56
- file << doc.serialize
57
- end
58
-
59
- or
60
-
61
- doc = LibXML::XML::Document.new
62
- doc.root = lib.to_xml
63
- doc.save("library.xml")
64
-
65
- To later populate the library object from the XML file:
66
-
67
- lib = Library.from_xml(File.read("library.xml"))
68
-
69
- Similarly, to do a one-to-one mapping between XML objects, such as book and publisher,
70
- you would add a reference to another ROXML class. For example:
71
-
72
- <book isbn="0974514055">
73
- <title>Programming Ruby - 2nd Edition</title>
74
- <description>Second edition of the great book.</description>
75
- <publisher>
76
- <name>Pragmatic Bookshelf</name>
77
- </publisher>
78
- </book>
79
-
80
- can be mapped using the following code:
81
-
82
- class Publisher
83
- include ROXML
84
-
85
- xml_accessor :name
86
-
87
- # other important functionality
34
+
35
+ class Item
36
+ include Representable::XML
37
+
38
+ representable_property :name
88
39
  end
40
+
41
+ == Consuming Representations
89
42
 
90
- class BookWithPublisher
91
- include ROXML
43
+ Representable gives you easy access for consuming incoming representation documents. It maps the appropriate content to objects' attributes.
92
44
 
93
- xml_name 'book'
94
- xml_reader :publisher, :as => Publisher
45
+ @order = Order.from_xml(xml)
46
+ @order.id # => "1"
47
+ @order.items # => [<item>, <item>]
48
+ @order.items.first.name # => "Chocolate Cookie"
95
49
 
96
- # or, alternatively, if no class is needed to hang functionality on:
97
- # xml_reader :publisher, :from => 'name', :in => 'publisher'
98
- end
99
-
100
- Note: In the above example, _xml_name_ annotation tells ROXML to set the element
101
- name to "book" for mapping to XML. The default is XML element name is the class name in lowercase; "bookwithpublisher"
102
- in this case.
103
-
104
- === Namespace Support
105
-
106
- Namespaced nodes are supported via the xml_namespace and xml_namespaces declarations and the :from and :namespace attr options. See spec/xml/namespace_spec.rb for usage.
107
-
108
- Note that ROXML does not currently support outputting namespaced nodes. This is planned for a future version.
109
50
 
110
- == Manipulation
51
+ == Extendability
111
52
 
112
- Extending the above examples, say you want to parse a book's page count and have it available as an Integer.
113
- In such a case, you can extend any object with a block to manipulate it's value at parse time. For example:
53
+ The cool thing with object-oriented representations is: you can treat them just like any other object in Ruby and extend them dynamically - which is impossible with plain hashes.
114
54
 
115
- class Dog
116
- include ROXML
117
-
118
- xml_reader(:age, :from => '@human_years', :as => Integer) {|years| years * 7 }
55
+ class Order
56
+ # ...
57
+
58
+ def sort_items
59
+ items.sort! do |a,b|
60
+ a.name <=> b.name
61
+ end
62
+ end
119
63
  end
120
64
 
121
- The result of the block above is stored, rather than the actual value parsed from the document.
122
65
 
123
- == Construction
66
+ == Generating Representations
124
67
 
125
- Object life-cycle is as follows: .from_xml is called with a first argument representing the xml
126
- in file, string, or path form, and with optional initialization_args following.
68
+ Usually you have two places that share knowledge about a representation and its syntax and semantics: the parser <em>and</em> the renderer. With Representable, this is kept in one place.
127
69
 
128
- Firt .new and thus #initialize, is called with those same initialization_args, or no args if none
129
- are present. Then the object is populated with the attribute values from xml. Then the
130
- #after_parse callback is called, with no arguments.
70
+ @order.to_xml # => "<order><id>1</id>...</order>"
71
+
72
+ You can also render a representation from a newly created object.
131
73
 
132
- In #after_parse you can ensure that your object initialization is complete, including initialization which
133
- requires more than one variable in concert.
74
+ Order.new(:id => 2, :items => [candy]).to_xml
134
75
 
135
- E.g.:
136
76
 
137
- class Measurement
138
- include ROXML
77
+ Representable makes working with representations extremely easy and testable.
139
78
 
140
- xml_reader :units, :from => :attr
141
- xml_reader :value, :from => :content
79
+ == More
142
80
 
143
- def initialize(value = 0, units = 'meters')
144
- to_metric
145
- end
81
+ Representable was written with REST representations in mind. However, it is a generic module for working with documents. If you do consider using it for a REST project, check out the {Roar framework}[http://github.com/apotonick/roar], which comes with representers, built-in hypermedia support and more. It internally uses Representable and streamlines the process for building hypermedia-driven REST applications.
146
82
 
147
- private
148
- def after_parse
149
- # xml attributes of self are already valid
150
- to_metric
151
- end
83
+ Representable comes with parser and renderer for XML and JSON and can easily be extended (Warning: internal API still changing).
152
84
 
153
- def to_metric
154
- # translate units & value into metric, for example
155
- end
156
- end
157
-
158
- One important use of this approach is to make ROXML object which may or may not include an xml backing,
159
- which may be used via _new_ construction as well as _from_xml_ construction.
160
-
161
- == Selecting a parser
162
-
163
- By default, ROXML will use Nokogiri if it is available, followed by LibXML. If you'd like to
164
- explicitly require one or the other, you may do the following:
165
-
166
- module ROXML
167
- XML_PARSER = 'nokogiri' # or 'libxml'
168
- end
169
- require 'roxml'
170
-
171
- For more information on available annotations, see ROXML::ClassMethods::Declarations
172
-
173
- == Note on Patches/Pull Requests
174
-
175
- * Fork the project.
176
- * Make your feature addition or bug fix.
177
- * Add specs for it. This is important so I don't break it in a
178
- future version unintentionally.
179
- * Commit, do not mess with rakefile, version, or history.
180
- (if you want to have your own version, that is fine but
181
- bump version in a commit by itself I can ignore when I pull)
182
- * Send me a pull request. Bonus points for topic branches.
183
85
 
184
86
  == Copyright
185
87
 
186
- Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom. See LICENSE for details.
88
+ Representable is a simplified fork of the ROXML gem. Big thanks to Ben Woosley for his work.
89
+
90
+ Copyright (c) 2011 Nick Sutterer <apotonick@gmail.com>
91
+ Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom.
@@ -1,7 +1,5 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/array/extract_options'
4
- require 'active_support/core_ext/string/starts_ends_with'
5
3
  require 'active_support/core_ext/string/inflections.rb'
6
4
  require 'active_support/core_ext/hash/reverse_merge.rb'
7
5
 
@@ -10,32 +8,19 @@ require 'hooks/inheritable_attribute'
10
8
 
11
9
  require 'representable/definition'
12
10
  require 'representable/nokogiri_extensions'
13
- require 'representable/references'
14
11
 
15
- require 'representable/xml' # TODO: do that dynamically.
12
+ #require 'representable/xml' # TODO: do that dynamically.
16
13
 
17
14
  module Representable
18
- VERSION = '3.1.5'
19
-
20
-
21
15
  def self.included(base)
22
16
  base.class_eval do
23
17
  extend ClassMethods::Accessors, ClassMethods::Declarations
24
-
25
-
26
-
27
- attr_accessor :roxml_references
28
18
 
29
19
  extend Hooks::InheritableAttribute
30
20
  inheritable_attr :representable_attrs
31
21
  self.representable_attrs = []
32
22
 
33
23
  inheritable_attr :explicit_representation_name # FIXME: move to Accessors.
34
-
35
-
36
- extend Xml::Declarations # DISCUSS: do that dynamically?
37
- extend Xml::ClassMethods # DISCUSS: do that dynamically?
38
- include Xml::InstanceMethods # DISCUSS: do that dynamically?
39
24
  end
40
25
  end
41
26
 
@@ -204,39 +189,30 @@ module Representable
204
189
  # [:cdata] true for values which should be input from or output as cdata elements
205
190
  # [:to_xml] this proc is applied to the attributes value outputting the instance via #to_xml
206
191
  #
207
- def representable_attr(*syms, &block)
208
- opts = syms.extract_options!
209
- syms.map do |sym|
210
- definition_class.new(sym, opts, &block).tap do |attr|
211
- representable_attrs << attr
212
- end
213
- end
192
+ def representable_property(*args) # TODO: make it accept 1-n props.
193
+ attr = representable_attr(*args)
194
+ add_reader(attr)
195
+ attr_writer(attr.accessor)
214
196
  end
215
-
216
- # Declares a read-only xml reference. See xml_attr for details.
217
- #
218
- # Note that while xml_reader does not create a setter for this attribute,
219
- # its value can be modified indirectly via methods. For more complete
220
- # protection, consider the :frozen option.
221
- def representable_reader(*syms, &block)
222
- representable_attr(*syms, &block).each do |attr|
223
- add_reader(attr)
197
+
198
+ def representable_collection(name, options={})
199
+ options[:as] = [options[:as]].compact
200
+ representable_property(name, options)
201
+ end
202
+
203
+ private
204
+ def representable_attr(name, options={})
205
+ definition_class.new(name, options).tap do |attr|
206
+ representable_attrs << attr
224
207
  end
225
208
  end
226
-
227
- # Declares a writable xml reference. See xml_attr for details.
228
- #
229
- # Note that while xml_accessor does create a setter for this attribute,
230
- # you can use the :frozen option to prevent its value from being
231
- # modified indirectly via methods.
232
- def representable_accessor(*syms, &block)
209
+
210
+ def representable_reader(*syms, &block)
233
211
  representable_attr(*syms, &block).each do |attr|
234
212
  add_reader(attr)
235
- attr_writer(attr.accessor)
236
213
  end
237
214
  end
238
-
239
- private
215
+
240
216
  def add_reader(attr)
241
217
  define_method(attr.accessor) do
242
218
  instance_variable_get(attr.instance_variable_name)
@@ -0,0 +1,69 @@
1
+ module Representable
2
+ module JSON
3
+ class Binding
4
+ attr_reader :definition
5
+ delegate :required?, :array?, :accessor, :wrapper, :name, :to => :definition
6
+
7
+ def initialize(definition)
8
+ @definition = definition
9
+ end
10
+
11
+ def value_in(hash)
12
+ value_from_hash(hash) or default
13
+ end
14
+
15
+ private
16
+ def default
17
+ ""
18
+ end
19
+
20
+ def collect_for(hash)
21
+ nodes = hash[name.to_s] or return
22
+ nodes = [nodes] unless nodes.is_a?(Array)
23
+
24
+ vals = nodes.collect { |node| yield node }
25
+
26
+ array? ? vals : vals.first
27
+ end
28
+ end
29
+
30
+ # Represents plain key-value.
31
+ class TextBinding < Binding
32
+ def update_json(hash, value)
33
+ hash[name] = value
34
+ end
35
+
36
+ private
37
+ def value_from_hash(hash)
38
+ collect_for(hash) do |value|
39
+ value
40
+ end
41
+ end
42
+ end
43
+
44
+ # Represents a tag with object binding.
45
+ class ObjectBinding < Binding
46
+ delegate :sought_type, :to => :definition
47
+
48
+ def update_json(hash, value)
49
+ if array?
50
+ hash.merge! ({accessor => value.collect {|v| v.to_json(:wrap => false)}}) # hier name=> wech.
51
+ else
52
+ hash.merge! value.to_json
53
+ end
54
+ end
55
+
56
+ private
57
+ def default
58
+ []
59
+ end
60
+
61
+ def value_from_hash(xml)
62
+ collect_for(xml) do |node|
63
+ sought_type.from_json(node, :wrap => false) # hier name=> wech.
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,152 @@
1
+ module Representable
2
+ module XML
3
+ class Binding
4
+ attr_reader :definition
5
+ delegate :required?, :array?, :accessor, :wrapper, :name, :to => :definition
6
+
7
+ def initialize(definition)
8
+ @definition = definition
9
+ end
10
+
11
+ def value_in(xml)
12
+ xml = Nokogiri::XML::Node.from(xml) or return default
13
+
14
+ value_from_node(xml) or default
15
+ end
16
+
17
+ private
18
+ def default
19
+ ""
20
+ end
21
+
22
+ def xpath
23
+ name
24
+ end
25
+
26
+ def wrap(xml, opts = {:always_create => false})
27
+ wrap_with = @auto_vals ? auto_wrapper : wrapper
28
+
29
+ return xml if !wrap_with || xml.name == wrap_with
30
+ if !opts[:always_create] && (child = xml.children.find {|c| c.name == wrap_with })
31
+ return child
32
+ end
33
+ xml.add_node(wrap_with.to_s)
34
+ end
35
+
36
+ def collect_for(xml)
37
+ nodes = xml.search("./#{xpath}")
38
+ vals = nodes.collect { |node| yield node }
39
+
40
+ array? ? vals : vals.first
41
+ end
42
+ end
43
+
44
+
45
+ # Represents a tag attribute.
46
+ class AttributeBinding < Binding
47
+ def update_xml(xml, values)
48
+ wrap(xml).tap do |xml|
49
+ xml[name] = values.to_s
50
+ end
51
+ end
52
+
53
+ private
54
+ def value_from_node(xml)
55
+ xml[name]
56
+ end
57
+ end
58
+
59
+
60
+ # Represents text content in a tag. # FIXME: is this tested???
61
+ class TextBinding < Binding
62
+ delegate :cdata?, :content?, :name?, :to => :definition
63
+
64
+ # Updates the text in the given _xml_ block to
65
+ # the _value_ provided.
66
+ def update_xml(xml, value)
67
+ wrap(xml).tap do |xml|
68
+ if content?
69
+ add(xml, value)
70
+ elsif name?
71
+ xml.name = value
72
+ elsif array?
73
+ value.each do |v|
74
+ add(xml.add_node(name), v)
75
+ end
76
+ else
77
+ add(xml.add_node(name), value)
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+ def value_from_node(xml)
84
+ collect_for(xml) do |node|
85
+ node.content
86
+ end
87
+ end
88
+
89
+ def add(dest, value)
90
+ if cdata?
91
+ dest.add_child(Nokogiri::XML::CDATA.new(dest.document, content))
92
+ else
93
+ dest.content = value.to_s
94
+ end
95
+ end
96
+ end
97
+
98
+
99
+ class NamespaceBinding < Binding
100
+ private
101
+ def value_from_node(xml)
102
+ xml.namespace.prefix
103
+ end
104
+ end
105
+
106
+ # Represents a tag with object binding.
107
+ class ObjectBinding < Binding
108
+ delegate :sought_type, :to => :definition
109
+
110
+ # Adds the ref's markup to +xml+.
111
+ def update_xml(xml, value)
112
+ wrap(xml).tap do |xml|
113
+ if array?
114
+ update_xml_for_collection(xml, value)
115
+ else
116
+ update_xml_for_entity(xml, value)
117
+ end
118
+ end
119
+ end
120
+
121
+ private
122
+ def default
123
+ []
124
+ end
125
+
126
+ def serialize(object)
127
+ object.to_xml
128
+ end
129
+
130
+ def deserialize(node_class, xml)
131
+ node_class.from_xml(xml)
132
+ end
133
+
134
+ # Deserializes the ref's element from +xml+.
135
+ def value_from_node(xml)
136
+ collect_for(xml) do |node|
137
+ deserialize(sought_type, node)
138
+ end
139
+ end
140
+
141
+ def update_xml_for_collection(xml, collection)
142
+ collection.each do |item|
143
+ update_xml_for_entity(xml, item)
144
+ end
145
+ end
146
+
147
+ def update_xml_for_entity(xml, entity)
148
+ xml.add_child(serialize(entity))
149
+ end
150
+ end
151
+ end
152
+ end