representable 0.9.2 → 0.9.3

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.
@@ -1,3 +1,7 @@
1
+ h2. 0.9.3
2
+
3
+ * Removed the @:as => [..]@ syntax in favor of @:array => true@.
4
+
1
5
  h2. 0.9.2
2
6
 
3
7
  * Arguments and block now successfully forwarded in @#from_*@.
@@ -51,172 +51,28 @@ private
51
51
  representable_attrs.map {|attr| binding_for_definition(attr) }
52
52
  end
53
53
 
54
- # Declares a reference to a certain xml element, whether an attribute, a node,
55
- # or a typed collection of nodes. This method does not add a corresponding accessor
56
- # to the object. For that behavior see the similar methods: .xml_reader and .xml_accessor.
54
+ # Declares a represented document node, which is usually a XML tag or a JSON key.
57
55
  #
58
- # == Sym Option
59
- # [sym] Symbol representing the name of the accessor.
56
+ # Examples:
60
57
  #
61
- # === Default naming
62
- # This name will be the default node or attribute name searched for,
63
- # if no other is declared. For example,
64
- #
65
- # xml_reader :bob
66
- # xml_accessor :pony, :from => :attr
67
- #
68
- # are equivalent to:
69
- #
70
- # xml_reader :bob, :from => 'bob'
71
- # xml_accessor :pony, :from => '@pony'
72
- #
73
- # == Options
74
- # === :as
75
- # ==== Basic Types
76
- # Allows you to specify one of several basic types to return the value as. For example
77
- #
78
- # xml_reader :count, :as => Integer
79
- #
80
- # is equivalent to:
81
- #
82
- # xml_reader(:count) {|val| Integer(val) unless val.empty? }
83
- #
84
- # Such block shorthands for Integer, Float, Fixnum, BigDecimal, Date, Time, and DateTime
85
- # are currently available, but only for non-Hash declarations.
86
- #
87
- # To reference many elements, put the desired type in a literal array. e.g.:
88
- #
89
- # xml_reader :counts, :as => [Integer]
90
- #
91
- # Even an array of text nodes can be specified with :as => []
92
- #
93
- # xml_reader :quotes, :as => []
94
- #
95
- # === Other ROXML Class
96
- # Declares an accessor that represents another ROXML class as child XML element
97
- # (one-to-one or composition) or array of child elements (one-to-many or
98
- # aggregation) of this type. Default is one-to-one. For one-to-many, simply pass the class
99
- # as the only element in an array.
100
- #
101
- # Composition example:
102
- # <book>
103
- # <publisher>
104
- # <name>Pragmatic Bookshelf</name>
105
- # </publisher>
106
- # </book>
107
- #
108
- # Can be mapped using the following code:
109
- # class Book
110
- # xml_reader :publisher, :as => Publisher
111
- # end
112
- #
113
- # Aggregation example:
114
- # <library>
115
- # <books>
116
- # <book/>
117
- # <book/>
118
- # </books>
119
- # </library>
120
- #
121
- # Can be mapped using the following code:
122
- # class Library
123
- # xml_reader :books, :as => [Book], :in => "books"
124
- # end
125
- #
126
- # If you don't have the <books> tag to wrap around the list of <book> tags:
127
- # <library>
128
- # <name>Ruby books</name>
129
- # <book/>
130
- # <book/>
131
- # </library>
132
- #
133
- # You can skip the wrapper argument:
134
- # xml_reader :books, :as => [Book]
135
- #
136
- # === :from
137
- # The name by which the xml value will be found, either an attribute or tag name in XML.
138
- # Default is sym, or the singular form of sym, in the case of arrays and hashes.
139
- #
140
- # This value may also include XPath notation.
141
- #
142
- # ==== :from => :content
143
- # When :from is set to :content, this refers to the content of the current node,
144
- # rather than a sub-node. It is equivalent to :from => '.'
145
- #
146
- # Example:
147
- # class Contributor
148
- # xml_reader :name, :from => :content
149
- # xml_reader :role, :from => :attr
150
- # end
151
- #
152
- # To map:
153
- # <contributor role="editor">James Wick</contributor>
154
- #
155
- # ==== :from => :attr
156
- # When :from is set to :attr, this refers to the content of an attribute,
157
- # rather than a sub-node. It is equivalent to :from => '@attribute_name'
158
- #
159
- # Example:
160
- # class Book
161
- # xml_reader :isbn, :from => "@ISBN"
162
- # xml_accessor :title, :from => :attr # :from defaults to '@title'
163
- # end
164
- #
165
- # To map:
166
- # <book ISBN="0974514055" title="Programming Ruby: the pragmatic programmers' guide" />
167
- #
168
- # ==== :from => :text
169
- # The default source, if none is specified, this means the accessor
170
- # represents a text node from XML. This is documented for completeness
171
- # only. You should just leave this option off when you want the default behavior,
172
- # as in the examples below.
173
- #
174
- # :text is equivalent to :from => accessor_name, and you should specify the
175
- # actual node name (and, optionally, a namespace) if it differs, as in the case of :author below.
176
- #
177
- # Example:
178
- # class Book
179
- # xml_reader :author, :from => 'Author'
180
- # xml_accessor :description, :cdata => true
181
- # xml_reader :title
182
- # end
183
- #
184
- # To map:
185
- # <book>
186
- # <title>Programming Ruby: the pragmatic programmers' guide</title>
187
- # <description><![CDATA[Probably the best Ruby book out there]]></description>
188
- # <Author>David Thomas</Author>
189
- # </book>
190
- #
191
- # Likewise, a number of :text node values can be collected in an array like so:
192
- #
193
- # Example:
194
- # class Library
195
- # xml_reader :books, :as => []
196
- # end
197
- #
198
- # To map:
199
- # <library>
200
- # <book>To kill a mockingbird</book>
201
- # <book>House of Leaves</book>
202
- # <book>Gödel, Escher, Bach</book>
203
- # </library>
204
- #
205
- # === Other Options
206
- # [:in] An optional name of a wrapping tag for this XML accessor.
207
- # This can include other xpath values, which will be joined with :from with a '/'
208
- # [:required] If true, throws RequiredElementMissing when the element isn't present
209
- # [:cdata] true for values which should be input from or output as cdata elements
210
- # [:to_xml] this proc is applied to the attributes value outputting the instance via #to_xml
211
- #
212
- def representable_property(*args) # TODO: make it accept 1-n props.
58
+ # representable_property :name
59
+ # representable_property :name, :from => :title
60
+ # representable_property :name, :as => Name
61
+ def representable_property(*args)
213
62
  attr = add_representable_property(*args)
214
63
  attr_reader(attr.getter)
215
64
  attr_writer(attr.getter)
216
65
  end
217
66
 
67
+ # Declares a represented document node collection.
68
+ #
69
+ # Examples:
70
+ #
71
+ # representable_collection :products
72
+ # representable_collection :products, :from => :item
73
+ # representable_collection :products, :as => Product
218
74
  def representable_collection(name, options={})
219
- options[:as] = [options[:as]].compact
75
+ options[:collection] = true
220
76
  representable_property(name, options)
221
77
  end
222
78
 
@@ -44,7 +44,7 @@ module Representable
44
44
  class ObjectBinding < Binding
45
45
  def write(hash, value)
46
46
  if definition.array?
47
- hash.merge! ({definition.from => value.collect {|v| v.to_hash(:wrap => false)}}) # hier name=> wech.
47
+ hash.merge!({definition.from => value.collect {|v| v.to_hash(:wrap => false)}})
48
48
  else
49
49
  hash.merge! value.to_hash
50
50
  end
@@ -3,24 +3,16 @@ module Representable
3
3
  attr_reader :name, :sought_type, :wrapper, :from
4
4
  alias_method :getter, :name
5
5
 
6
- def initialize(sym, opts={})
7
- @name = sym.to_s
8
-
9
- @array = true if opts[:as].is_a?(Array) # DISCUSS: move to ArrayDefinition.
10
- @from = (opts[:from] || name).to_s
11
- @sought_type = extract_type(opts[:as])
6
+ def initialize(sym, options={})
7
+ @name = sym.to_s
8
+ @array = options[:collection]
9
+ @from = (options[:from] || name).to_s
10
+ @sought_type = options[:as] || :text
12
11
 
13
12
  # FIXME: move me to xml.
14
- if opts[:from] == :content
15
- opts[:from] = '.'
16
- elsif opts[:from] == :name
17
- opts[:from] = '*'
18
- elsif opts[:from] == :attr
19
- @sought_type = :attr
20
- opts[:from] = nil
21
- elsif opts[:from].to_s =~ /^@/
13
+ if options[:from].to_s =~ /^@/
22
14
  @sought_type = :attr
23
- opts[:from].sub!('@', '')
15
+ options[:from].sub!('@', '')
24
16
  end
25
17
  end
26
18
 
@@ -67,12 +59,5 @@ module Representable
67
59
 
68
60
  value
69
61
  end
70
-
71
- private
72
- def extract_type(as)
73
- as = as.first if as.is_a?(Array) # TODO: move to ArrayDefinition.
74
-
75
- as || :text
76
- end
77
62
  end
78
63
  end
@@ -2,6 +2,10 @@ require 'json'
2
2
  require 'representable/bindings/json_bindings'
3
3
 
4
4
  module Representable
5
+ # Brings #to_xml, #to_hash, #from_xml and #from_hash to your object.
6
+ #
7
+ # Note: The authorative methods are #to_hash and #from_hash, if you override #to_json instead,
8
+ # things might work as expected.
5
9
  module JSON
6
10
  BINDING_FOR_TYPE = { # TODO: refactor #representable_accessor for better extendability.
7
11
  :text => TextBinding,
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "0.9.2"
2
+ VERSION = "0.9.3"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'representable'
2
+ require 'representable/nokogiri_extensions'
2
3
  require 'representable/bindings/xml_bindings'
3
4
 
4
5
  module Representable
@@ -9,7 +9,6 @@ class DefinitionTest < MiniTest::Spec
9
9
  it "responds to #typed?" do
10
10
  assert ! @def.typed?
11
11
  assert Representable::Definition.new(:songs, :as => Hash).typed?
12
- assert Representable::Definition.new(:songs, :as => [Hash]).typed?
13
12
  end
14
13
 
15
14
  it "responds to #getter and returns string" do
@@ -41,19 +40,19 @@ class DefinitionTest < MiniTest::Spec
41
40
  end
42
41
 
43
42
  it "works with collection" do
44
- @d = Representable::Definition.new(:song, :as => [])
43
+ @d = Representable::Definition.new(:song, :collection => true)
45
44
  assert_equal [2,3,4], @d.apply([1,2,3]) { |v| v+1 }
46
45
  end
47
46
 
48
47
  it "skips with collection and nil" do
49
- @d = Representable::Definition.new(:song, :as => [])
48
+ @d = Representable::Definition.new(:song, :collection => true)
50
49
  assert_equal nil, @d.apply(nil) { |v| v+1 }
51
50
  end
52
51
  end
53
52
 
54
- describe ":as => []" do
53
+ describe ":collection => true" do
55
54
  before do
56
- @def = Representable::Definition.new(:songs, :as => [], :tag => :song)
55
+ @def = Representable::Definition.new(:songs, :collection => true, :tag => :song)
57
56
  end
58
57
 
59
58
  it "responds to #array?" do
@@ -64,18 +63,6 @@ class DefinitionTest < MiniTest::Spec
64
63
  assert_equal :text, @def.sought_type
65
64
  end
66
65
  end
67
-
68
-
69
- describe ":as => [Item]" do
70
- before do
71
- @def = Representable::Definition.new(:songs, :as => [Hash])
72
- end
73
-
74
- it "responds to #sought_type" do
75
- assert_equal Hash, @def.sought_type
76
- end
77
- end
78
-
79
66
 
80
67
  describe ":as => Item" do
81
68
  before do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 2
9
- version: 0.9.2
8
+ - 3
9
+ version: 0.9.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Nick Sutterer
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-11-25 00:00:00 +01:00
17
+ date: 2011-11-27 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency