representative 0.1.3 → 0.2.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/README.markdown CHANGED
@@ -37,15 +37,18 @@ Given a Ruby data-structure:
37
37
  Representative::Xml can be used to generate XML, in a declarative style:
38
38
 
39
39
  xml = Builder::XmlMarkup.new(:indent => 2)
40
- representative = Representative::Xml.new(xml)
41
-
42
- representative.list_of!(:books, books) do |_book|
43
- _book.title
44
- _book.list_of!(:authors)
45
- _book.published do |_published|
46
- _published.by
47
- _published.year
40
+
41
+ Representative::Xml.new(xml) do |r|
42
+
43
+ r.list_of :books, books do
44
+ r.element :title
45
+ r.list_of :authors
46
+ r.element :published do
47
+ r.element :by
48
+ r.element :year
49
+ end
48
50
  end
51
+
49
52
  end
50
53
 
51
54
  puts xml.target!
@@ -85,18 +88,18 @@ The resulting XML looks like this:
85
88
 
86
89
  Notice that:
87
90
 
88
- - Representative generates elements for each object-attribute you name (and not the ones you don't).
89
91
  - The structure of the XML mirrors the structure described by the nested Ruby blocks.
90
- - Using `list_of!` for a collection attribute generates an "array" element, which plays nicely
92
+ - Representative walks the object-graph for you.
93
+ - Using `list_of` for a collection attribute generates an "array" element, which plays nicely
91
94
  with most Ruby XML-to-hash converters.
92
95
  - Where a named object-attribute is nil, you get an empty element.
93
96
 
94
97
  Installation
95
98
  ------------
96
99
 
97
- Representative is packaged as a Gem, hosted on [gemcutter](http://gemcutter.org/gems/representative). Install with:
100
+ Representative is packaged as a Gem. Install with:
98
101
 
99
- sudo gem install representative
102
+ gem install representative
100
103
 
101
104
  Copyright
102
105
  ---------
data/examples/xml_demo.rb CHANGED
@@ -29,15 +29,15 @@ books = [
29
29
  ]
30
30
 
31
31
  xml = Builder::XmlMarkup.new(:indent => 2)
32
- representative = Representative::Xml.new(xml)
33
-
34
- representative.list_of!(:books, books) do |_book|
35
- _book.title
36
- _book.list_of!(:authors)
37
- _book.published do |_published|
38
- _published.by
39
- _published.year
32
+ Representative::Xml.new(xml) do |r|
33
+ r.list_of :books, books do
34
+ r.element :title
35
+ r.list_of :authors
36
+ r.element :published do
37
+ r.element :by
38
+ r.element :year
39
+ end
40
40
  end
41
41
  end
42
42
 
43
- puts xml.target!
43
+ puts xml.target!
@@ -1,3 +1,3 @@
1
1
  module Representative
2
- VERSION = "0.1.3".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -15,61 +15,40 @@ module Representative
15
15
  yield self if block_given?
16
16
  end
17
17
 
18
- def method_missing(name, *args, &block)
19
- if name.to_s =~ /!$/
20
- super
21
- else
22
- attribute!(name, *args, &block)
18
+ def represent(subject)
19
+ @subjects.push(subject)
20
+ begin
21
+ yield subject
22
+ ensure
23
+ @subjects.pop
23
24
  end
24
25
  end
25
-
26
- def subject!
26
+
27
+ def subject
27
28
  @subjects.last
28
29
  end
29
30
 
30
- def attribute!(subject_attribute_name, *args, &block)
31
+ def element(name, *args, &block)
31
32
 
32
33
  element_attributes = args.extract_options!
33
34
  value_generator = if args.empty?
34
35
  lambda do |subject|
35
- @inspector.get_value(subject, subject_attribute_name)
36
+ @inspector.get_value(subject, name)
36
37
  end
37
38
  else
38
39
  args.shift
39
40
  end
40
41
  raise ArgumentError, "too many arguments" unless args.empty?
41
42
 
42
- element_name = subject_attribute_name.to_s.dasherize
43
-
44
43
  value = resolve_value(value_generator)
45
44
  resolved_element_attributes = resolve_element_attributes(element_attributes, value)
46
- resolved_element_attributes.merge!(@inspector.get_metadata(subject!, subject_attribute_name))
45
+ resolved_element_attributes.merge!(@inspector.get_metadata(subject, name))
47
46
 
48
- element!(element_name, value, resolved_element_attributes, &block)
47
+ emit_element(name, value, resolved_element_attributes, &block)
49
48
 
50
49
  end
51
50
 
52
- def element!(element_name, subject, options, &block)
53
- content = content_generator = nil
54
- if block && subject
55
- unless block == Representative::EMPTY
56
- content_generator = Proc.new do
57
- @subjects.push(subject)
58
- begin
59
- block.call(self)
60
- ensure
61
- @subjects.pop
62
- end
63
- end
64
- end
65
- else
66
- content = subject
67
- end
68
- tag_args = [content, options].compact
69
- @xml.tag!(element_name, *tag_args, &content_generator)
70
- end
71
-
72
- def list_of!(attribute_name, *args, &block)
51
+ def list_of(attribute_name, *args, &block)
73
52
 
74
53
  options = args.extract_options!
75
54
  value_generator = args.empty? ? attribute_name : args.shift
@@ -90,19 +69,34 @@ module Representative
90
69
  @xml.tag!(list_name, resolved_list_element_attributes.merge(:type => "array")) do
91
70
  items.each do |item|
92
71
  resolved_item_element_attributes = resolve_element_attributes(item_element_attributes, item)
93
- element!(item_name, item, resolved_item_element_attributes, &block)
72
+ emit_element(item_name, item, resolved_item_element_attributes, &block)
94
73
  end
95
74
  end
96
75
 
97
76
  end
98
77
 
99
- def empty!(attribute_name, *args)
100
- attribute!(attribute_name, *args, &Representative::EMPTY)
78
+ def empty
79
+ Representative::EMPTY
101
80
  end
102
-
81
+
103
82
  private
104
83
 
105
- def resolve_value(value_generator, subject = subject!)
84
+ def emit_element(name, subject, options, &content_block)
85
+ content = content_generator = nil
86
+ if subject && content_block
87
+ unless content_block == Representative::EMPTY
88
+ content_generator = Proc.new do
89
+ represent(subject, &content_block)
90
+ end
91
+ end
92
+ else
93
+ content = subject
94
+ end
95
+ tag_args = [content, options].compact
96
+ @xml.tag!(name.to_s.dasherize, *tag_args, &content_generator)
97
+ end
98
+
99
+ def resolve_value(value_generator, subject = subject)
106
100
  if value_generator == :self
107
101
  subject
108
102
  elsif value_generator.respond_to?(:to_proc)
@@ -10,8 +10,8 @@ describe Representative::Xml do
10
10
  @xml = Builder::XmlMarkup.new
11
11
  end
12
12
 
13
- def represent
14
- @xml_representative
13
+ def r
14
+ @representative ||= Representative::Xml.new(@xml, @subject)
15
15
  end
16
16
 
17
17
  def resulting_xml
@@ -22,38 +22,37 @@ describe Representative::Xml do
22
22
 
23
23
  before do
24
24
  @subject = OpenStruct.new(:name => "Fred", :width => 200, :vehicle => OpenStruct.new(:year => "1959", :make => "Chevrolet"))
25
- @xml_representative = Representative::Xml.new(@xml, @subject)
26
25
  end
27
26
 
28
- describe "calling a method" do
27
+ describe "#element" do
29
28
 
30
29
  it "generates an element with content extracted from the subject" do
31
- represent.name
30
+ r.element :name
32
31
  resulting_xml.should == %(<name>Fred</name>)
33
32
  end
34
33
 
35
- it "dasherizes the method name" do
34
+ it "dasherizes the property name" do
36
35
  @subject.full_name = "Fredrick"
37
- represent.full_name
36
+ r.element :full_name
38
37
  resulting_xml.should == %(<full-name>Fredrick</full-name>)
39
38
  end
40
39
 
41
- describe "with an attribute" do
40
+ describe "with attributes" do
42
41
 
43
42
  it "generates attributes on the element" do
44
- represent.name(:lang => "fr")
43
+ r.element :name, :lang => "fr"
45
44
  resulting_xml.should == %(<name lang="fr">Fred</name>)
46
45
  end
47
46
 
48
47
  it "dasherizes the attribute name" do
49
- represent.name(:sourced_from => "phonebook")
48
+ r.element :name, :sourced_from => "phonebook"
50
49
  resulting_xml.should == %(<name sourced-from="phonebook">Fred</name>)
51
50
  end
52
51
 
53
52
  describe "whose value supports #to_proc" do
54
53
 
55
54
  it "calls the Proc on the subject to generate a value" do
56
- represent.name(:rev => :reverse)
55
+ r.element :name, :rev => :reverse
57
56
  resulting_xml.should == %(<name rev="derF">Fred</name>)
58
57
  end
59
58
 
@@ -62,7 +61,7 @@ describe Representative::Xml do
62
61
  describe "with value nil" do
63
62
 
64
63
  it "omits the attribute" do
65
- represent.name(:lang => nil)
64
+ r.element :name, :lang => nil
66
65
  resulting_xml.should == %(<name>Fred</name>)
67
66
  end
68
67
 
@@ -70,17 +69,17 @@ describe Representative::Xml do
70
69
 
71
70
  end
72
71
 
73
- describe "with a non-Hash argument" do
72
+ describe "with an explicit value" do
74
73
 
75
74
  it "generates an element with explicitly provided content" do
76
- represent.name("Bloggs")
75
+ r.element :name, "Bloggs"
77
76
  resulting_xml.should == %(<name>Bloggs</name>)
78
77
  end
79
78
 
80
- describe "AND a Hash argument" do
79
+ describe "AND attributes" do
81
80
 
82
81
  it "generates attributes on the element" do
83
- represent.name("Bloggs", :lang => "fr")
82
+ r.element :name, "Bloggs", :lang => "fr"
84
83
  resulting_xml.should == %(<name lang="fr">Bloggs</name>)
85
84
  end
86
85
 
@@ -88,37 +87,37 @@ describe Representative::Xml do
88
87
 
89
88
  end
90
89
 
91
- describe "with an argument that supports #to_proc" do
90
+ describe "with a value argument that supports #to_proc" do
92
91
 
93
92
  it "calls the Proc on the subject to generate a value" do
94
- represent.name(:width)
93
+ r.element :name, :width
95
94
  resulting_xml.should == %(<name>200</name>)
96
95
  end
97
96
 
98
97
  end
99
98
 
100
- describe "with argument :self" do
99
+ describe "with value argument :self" do
101
100
 
102
101
  it "doesn't alter the subject" do
103
- represent.info(:self) do |info|
104
- info.name
102
+ r.element :info, :self do
103
+ r.element :name
105
104
  end
106
105
  resulting_xml.should == %(<info><name>Fred</name></info>)
107
106
  end
108
107
 
109
108
  end
110
109
 
111
- describe "with a nil argument" do
110
+ describe "with value argument nil" do
112
111
 
113
112
  it "builds an empty element" do
114
- represent.name(nil)
113
+ r.element :name, nil
115
114
  resulting_xml.should == %(<name/>)
116
115
  end
117
116
 
118
- describe "and a Hash entry value that supports #to_proc" do
117
+ describe "and attributes" do
119
118
 
120
- it "omits the attribute" do
121
- represent.name(nil, :size => :size)
119
+ it "omits the attributes" do
120
+ r.element :name, nil, :size => :size
122
121
  resulting_xml.should == %(<name/>)
123
122
  end
124
123
 
@@ -127,8 +126,8 @@ describe Representative::Xml do
127
126
  describe "and a block" do
128
127
 
129
128
  it "doesn't call the block" do
130
- represent.name(nil) do |name|
131
- name.foo
129
+ r.element :name, nil do
130
+ raise "hell"
132
131
  end
133
132
  resulting_xml.should == %(<name/>)
134
133
  end
@@ -140,41 +139,47 @@ describe Representative::Xml do
140
139
  describe "with a block" do
141
140
 
142
141
  it "generates nested elements" do
143
- represent.vehicle do |vehicle|
144
- vehicle.year
145
- vehicle.make
142
+ r.element :vehicle do
143
+ r.element :year
144
+ r.element :make
146
145
  end
147
146
  resulting_xml.should == %(<vehicle><year>1959</year><make>Chevrolet</make></vehicle>)
148
147
  end
149
148
 
149
+ it "yields each new subject" do
150
+ r.element :vehicle do |vehicle|
151
+ vehicle.should == @subject.vehicle
152
+ end
153
+ end
154
+
150
155
  end
151
-
152
- end
153
156
 
154
- describe "#empty!" do
155
-
156
- it "generates an empty element" do
157
- represent.empty!(:vehicle, :year => :year)
158
- resulting_xml.should == %(<vehicle year="1959"/>)
157
+ describe "with an EMPTY block" do
158
+
159
+ it "generates an empty element" do
160
+ r.element :vehicle, :year => :year, &r.empty
161
+ resulting_xml.should == %(<vehicle year="1959"/>)
162
+ end
163
+
159
164
  end
160
165
 
161
166
  end
162
167
 
163
- describe "#list_of!" do
168
+ describe "#list_of" do
164
169
 
165
170
  before do
166
171
  @subject.nick_names = ["Freddie", "Knucklenose"]
167
172
  end
168
173
 
169
174
  it "generates an array element" do
170
- represent.list_of!(:nick_names)
175
+ r.list_of(:nick_names)
171
176
  resulting_xml.should == %(<nick-names type="array"><nick-name>Freddie</nick-name><nick-name>Knucklenose</nick-name></nick-names>)
172
177
  end
173
178
 
174
179
  describe "with :list_attributes" do
175
180
 
176
181
  it "attaches attributes to the array element" do
177
- represent.list_of!(:nick_names, :list_attributes => {:color => "blue", :size => :size})
182
+ r.list_of(:nick_names, :list_attributes => {:color => "blue", :size => :size})
178
183
  array_element_attributes = REXML::Document.new(resulting_xml).root.attributes
179
184
  array_element_attributes["type"].should == "array"
180
185
  array_element_attributes["color"].should == "blue"
@@ -187,7 +192,7 @@ describe Representative::Xml do
187
192
  describe "with :item_attributes" do
188
193
 
189
194
  it "attaches attributes to each item element" do
190
- represent.list_of!(:nick_names, :item_attributes => {:length => :size})
195
+ r.list_of(:nick_names, :item_attributes => {:length => :size})
191
196
  resulting_xml.should == %(<nick-names type="array"><nick-name length="7">Freddie</nick-name><nick-name length="11">Knucklenose</nick-name></nick-names>)
192
197
  end
193
198
 
@@ -195,7 +200,7 @@ describe Representative::Xml do
195
200
 
196
201
  describe "with an explicit :item_name" do
197
202
  it "uses the name provided" do
198
- represent.list_of!(:nick_names, :item_name => :nick)
203
+ r.list_of(:nick_names, :item_name => :nick)
199
204
  resulting_xml.should == %(<nick-names type="array"><nick>Freddie</nick><nick>Knucklenose</nick></nick-names>)
200
205
  end
201
206
  end
@@ -203,7 +208,7 @@ describe Representative::Xml do
203
208
  describe "with an argument that resolves to nil" do
204
209
 
205
210
  it "omits the attribute" do
206
- represent.list_of!(:flags)
211
+ r.list_of(:flags)
207
212
  resulting_xml.should == %(<flags/>)
208
213
  end
209
214
 
@@ -212,19 +217,28 @@ describe Representative::Xml do
212
217
  describe "with a block" do
213
218
 
214
219
  it "generates a nested element for each list element" do
215
- represent.list_of!(:nick_names) do |nick_name|
216
- nick_name.length
220
+ r.list_of(:nick_names) do
221
+ r.element :length
217
222
  end
218
223
  resulting_xml.should == %(<nick-names type="array"><nick-name><length>7</length></nick-name><nick-name><length>11</length></nick-name></nick-names>)
219
224
  end
220
225
 
221
226
  end
222
227
 
228
+ describe "with an EMPTY block" do
229
+
230
+ it "generates empty elements for each list element" do
231
+ r.list_of(:nick_names, :item_attributes => {:value => :to_s}, &r.empty)
232
+ resulting_xml.should == %(<nick-names type="array"><nick-name value="Freddie"/><nick-name value="Knucklenose"/></nick-names>)
233
+ end
234
+
235
+ end
236
+
223
237
  describe "with :item_attributes AND block" do
224
238
 
225
239
  it "generates attributes and nested elements" do
226
- represent.list_of!(:nick_names, :item_attributes => {:length => :size}) do |nick_name|
227
- nick_name.reverse
240
+ r.list_of(:nick_names, :item_attributes => {:length => :size}) do
241
+ r.element :reverse
228
242
  end
229
243
  resulting_xml.should == %(<nick-names type="array"><nick-name length="7"><reverse>eidderF</reverse></nick-name><nick-name length="11"><reverse>esonelkcunK</reverse></nick-name></nick-names>)
230
244
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mike Williams
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-24 00:00:00 +10:00
17
+ date: 2010-07-02 00:00:00 +10:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency