representative 0.2.0 → 0.2.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.
- data/lib/representative/version.rb +1 -1
- data/lib/representative/xml.rb +101 -45
- data/spec/representative/xml_spec.rb +2 -1
- metadata +3 -3
data/lib/representative/xml.rb
CHANGED
@@ -6,8 +6,14 @@ require "representative/object_inspector"
|
|
6
6
|
|
7
7
|
module Representative
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
# Easily generate XML while traversing an object-graph.
|
10
|
+
#
|
11
|
+
class Xml
|
12
|
+
|
13
|
+
# Create an XML-generating Representative. The first argument should be an instance of
|
14
|
+
# Builder::XmlMarkup (or something that implements it's interface). The second argument
|
15
|
+
# if any, is the initial #subject of representation.
|
16
|
+
#
|
11
17
|
def initialize(xml_builder, subject = nil, options = {})
|
12
18
|
@xml = xml_builder
|
13
19
|
@subjects = [subject]
|
@@ -15,7 +21,18 @@ module Representative
|
|
15
21
|
yield self if block_given?
|
16
22
|
end
|
17
23
|
|
18
|
-
|
24
|
+
# Return the current "subject" of representation.
|
25
|
+
#
|
26
|
+
# This object will provide element values where they haven't been
|
27
|
+
# explicitly provided.
|
28
|
+
#
|
29
|
+
def subject
|
30
|
+
@subjects.last
|
31
|
+
end
|
32
|
+
|
33
|
+
# Evaluate a block with a specified object as #subject.
|
34
|
+
#
|
35
|
+
def representing(subject)
|
19
36
|
@subjects.push(subject)
|
20
37
|
begin
|
21
38
|
yield subject
|
@@ -23,14 +40,42 @@ module Representative
|
|
23
40
|
@subjects.pop
|
24
41
|
end
|
25
42
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
43
|
+
|
44
|
+
# Generate an element.
|
45
|
+
#
|
46
|
+
# With two arguments, it generates an element with the specified text content.
|
47
|
+
#
|
48
|
+
# r.element :size, 42
|
49
|
+
# # => <size>42</size>
|
50
|
+
#
|
51
|
+
# More commonly, though, the second argument is omitted, in which case the
|
52
|
+
# element content is assumed to be the named property of the current #subject.
|
53
|
+
#
|
54
|
+
# r.representing my_shoe do
|
55
|
+
# r.element :size
|
56
|
+
# end
|
57
|
+
# # => <size>9</size>
|
58
|
+
#
|
59
|
+
# If a block is attached, nested elements can be generated. The element "value"
|
60
|
+
# (whether explicitly provided, or derived from the current subject) becomes the
|
61
|
+
# subject during evaluation of the block.
|
62
|
+
#
|
63
|
+
# r.element :book, book do
|
64
|
+
# r.title
|
65
|
+
# r.author
|
66
|
+
# end
|
67
|
+
# # => <book><title>Whatever</title><author>Whoever</author></book>
|
68
|
+
#
|
69
|
+
# Providing a final Hash argument specifies element attributes.
|
70
|
+
#
|
71
|
+
# r.element :size, :type => "integer"
|
72
|
+
# # => <size type="integer">9</size>
|
73
|
+
#
|
31
74
|
def element(name, *args, &block)
|
32
75
|
|
33
|
-
|
76
|
+
attributes = args.extract_options!
|
77
|
+
attributes = attributes.merge(@inspector.get_metadata(subject, name))
|
78
|
+
|
34
79
|
value_generator = if args.empty?
|
35
80
|
lambda do |subject|
|
36
81
|
@inspector.get_value(subject, name)
|
@@ -38,64 +83,75 @@ module Representative
|
|
38
83
|
else
|
39
84
|
args.shift
|
40
85
|
end
|
86
|
+
|
41
87
|
raise ArgumentError, "too many arguments" unless args.empty?
|
42
88
|
|
43
89
|
value = resolve_value(value_generator)
|
44
|
-
|
45
|
-
|
90
|
+
return @xml.tag!(name) if value.nil?
|
91
|
+
|
92
|
+
representing(value) do
|
93
|
+
|
94
|
+
content_string = subject.to_s unless block
|
95
|
+
content_block = unless block.nil? || block == Representative::EMPTY
|
96
|
+
Proc.new do
|
97
|
+
block.call(subject)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
resolved_attributes = resolve_attributes(attributes)
|
102
|
+
tag_args = [content_string, resolved_attributes].compact
|
46
103
|
|
47
|
-
|
104
|
+
@xml.tag!(name.to_s.dasherize, *tag_args, &content_block)
|
105
|
+
|
106
|
+
end
|
48
107
|
|
49
108
|
end
|
50
109
|
|
51
|
-
|
110
|
+
# Generate a list of elements from Enumerable data.
|
111
|
+
#
|
112
|
+
# r.list_of :books, my_books do
|
113
|
+
# r.element :title
|
114
|
+
# end
|
115
|
+
# # => <books type="array">
|
116
|
+
# # <book><title>Sailing for old dogs</title></book>
|
117
|
+
# # <book><title>On the horizon</title></book>
|
118
|
+
# # <book><title>The Little Blue Book of VHS Programming</title></book>
|
119
|
+
# # </books>
|
120
|
+
#
|
121
|
+
# Like #element, the value can be explicit, but is more commonly extracted
|
122
|
+
# by name from the current #subject.
|
123
|
+
#
|
124
|
+
def list_of(name, *args, &block)
|
52
125
|
|
53
126
|
options = args.extract_options!
|
54
|
-
value_generator = args.empty? ?
|
127
|
+
value_generator = args.empty? ? name : args.shift
|
55
128
|
raise ArgumentError, "too many arguments" unless args.empty?
|
56
129
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
item_element_attributes = options[:item_attributes] || {}
|
130
|
+
list_attributes = options[:list_attributes] || {}
|
131
|
+
item_name = options[:item_name] || name.to_s.singularize
|
132
|
+
item_attributes = options[:item_attributes] || {}
|
61
133
|
|
62
134
|
items = resolve_value(value_generator)
|
63
|
-
|
64
|
-
return @xml.tag!(list_name)
|
65
|
-
end
|
66
|
-
|
67
|
-
resolved_list_element_attributes = resolve_element_attributes(list_element_attributes, items)
|
68
|
-
|
69
|
-
@xml.tag!(list_name, resolved_list_element_attributes.merge(:type => "array")) do
|
135
|
+
element(name, items, list_attributes.merge(:type => "array")) do
|
70
136
|
items.each do |item|
|
71
|
-
|
72
|
-
emit_element(item_name, item, resolved_item_element_attributes, &block)
|
137
|
+
element(item_name, item, item_attributes, &block)
|
73
138
|
end
|
74
139
|
end
|
75
140
|
|
76
141
|
end
|
77
142
|
|
143
|
+
# Return a magic value that, when passed to #element as a block, forces
|
144
|
+
# generation of an empty element.
|
145
|
+
#
|
146
|
+
# r.element(:link, :rel => "me", :href => "http://dogbiscuit.org", &r.empty)
|
147
|
+
# # => <link rel="parent" href="http://dogbiscuit.org"/>
|
148
|
+
#
|
78
149
|
def empty
|
79
150
|
Representative::EMPTY
|
80
151
|
end
|
81
152
|
|
82
153
|
private
|
83
154
|
|
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
155
|
def resolve_value(value_generator, subject = subject)
|
100
156
|
if value_generator == :self
|
101
157
|
subject
|
@@ -106,9 +162,9 @@ module Representative
|
|
106
162
|
end
|
107
163
|
end
|
108
164
|
|
109
|
-
def
|
110
|
-
if
|
111
|
-
|
165
|
+
def resolve_attributes(attributes)
|
166
|
+
if attributes
|
167
|
+
attributes.inject({}) do |resolved, (name, value_generator)|
|
112
168
|
resolved_value = resolve_value(value_generator, subject)
|
113
169
|
resolved[name.to_s.dasherize] = resolved_value unless resolved_value.nil?
|
114
170
|
resolved
|
@@ -148,8 +148,9 @@ describe Representative::Xml do
|
|
148
148
|
|
149
149
|
it "yields each new subject" do
|
150
150
|
r.element :vehicle do |vehicle|
|
151
|
-
|
151
|
+
r.element :year, vehicle.year
|
152
152
|
end
|
153
|
+
resulting_xml.should == %(<vehicle><year>1959</year></vehicle>)
|
153
154
|
end
|
154
155
|
|
155
156
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
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-07-
|
17
|
+
date: 2010-07-04 00:00:00 +10:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|