representative 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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