gyoku 0.4.6 → 0.5.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/.gitignore +2 -1
- data/CHANGELOG.md +6 -0
- data/README.md +67 -4
- data/lib/gyoku/hash.rb +27 -3
- data/lib/gyoku/version.rb +1 -1
- data/lib/gyoku/xml_key.rb +3 -1
- data/spec/gyoku/hash_spec.rb +67 -0
- data/spec/gyoku/xml_key_spec.rb +5 -0
- metadata +59 -69
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.5.0 (2012-12-15)
|
2
|
+
|
3
|
+
Feature: [#19](https://github.com/savonrb/gyoku/pull/19) adds support for explicit XML attributes.
|
4
|
+
|
5
|
+
Feature: [#17](https://github.com/savonrb/gyoku/pull/17) adds an `:upcase` formula.
|
6
|
+
|
1
7
|
## 0.4.6 (2012-06-28)
|
2
8
|
|
3
9
|
* Fix: [#16](https://github.com/rubiii/gyoku/issues/16) Date objects were mapped like DateTime objects.
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ Gyoku.xml(:lower_camel_case => "key")
|
|
31
31
|
You can change the default conversion formula.
|
32
32
|
|
33
33
|
``` ruby
|
34
|
-
Gyoku.convert_symbols_to :camelcase # or one of [:none, :lower_camelcase]
|
34
|
+
Gyoku.convert_symbols_to :camelcase # or one of [:none, :lower_camelcase, :upcase]
|
35
35
|
|
36
36
|
Gyoku.xml(:camel_case => "key")
|
37
37
|
# => "<CamelCase>key</CamelCase>"
|
@@ -40,10 +40,10 @@ Gyoku.xml(:camel_case => "key")
|
|
40
40
|
And you can also define your own formula.
|
41
41
|
|
42
42
|
``` ruby
|
43
|
-
Gyoku.convert_symbols_to { |key| key.
|
43
|
+
Gyoku.convert_symbols_to { |key| key.sub(/^prefixed_/, '') }
|
44
44
|
|
45
|
-
Gyoku.xml(:
|
46
|
-
# => "<
|
45
|
+
Gyoku.xml(:prefixed_attribute => "key")
|
46
|
+
# => "<attribute>key</attribute>"
|
47
47
|
```
|
48
48
|
|
49
49
|
Hash key Strings are not converted and may contain namespaces.
|
@@ -107,3 +107,66 @@ Adding XML attributes is rather ugly, but it can be done by specifying an additi
|
|
107
107
|
Gyoku.xml(:person => "Eve", :attributes! => { :person => { :id => 1 } })
|
108
108
|
# => "<person id=\"1\">Eve</person>"
|
109
109
|
```
|
110
|
+
|
111
|
+
Explicit XML Attributes
|
112
|
+
-----------------------
|
113
|
+
In addition to using :attributes!, you may also specify attributes with key names beginning with "@".
|
114
|
+
|
115
|
+
Since you'll need to set the attribute within the hash containing the node's contents, a :content! key can be used to explicity set the content of the node. The ":content!" value may be a String, Hash, or Array.
|
116
|
+
|
117
|
+
This is particularly useful for self-closing tags.
|
118
|
+
|
119
|
+
**Using :attributes!**
|
120
|
+
|
121
|
+
``` ruby
|
122
|
+
Gyoku.xml(
|
123
|
+
"foo/" => "",
|
124
|
+
:attributes! => {
|
125
|
+
"foo/" => {
|
126
|
+
"bar" => "1",
|
127
|
+
"biz" => "2",
|
128
|
+
"baz" => "3"
|
129
|
+
}
|
130
|
+
}
|
131
|
+
)
|
132
|
+
# => "<foo baz=\"3\" bar=\"1\" biz=\"2\"/>"
|
133
|
+
```
|
134
|
+
|
135
|
+
**Using "@" keys and ":content!"**
|
136
|
+
|
137
|
+
``` ruby
|
138
|
+
Gyoku.xml(
|
139
|
+
"foo/" => {
|
140
|
+
:@bar => "1",
|
141
|
+
:@biz => "2",
|
142
|
+
:@baz => "3",
|
143
|
+
:content! => ""
|
144
|
+
})
|
145
|
+
# => "<foo baz=\"3\" bar=\"1\" biz=\"2\"/>"
|
146
|
+
```
|
147
|
+
This seems a bit more explicit with the attributes rather than having to maintain a hash of attributes.
|
148
|
+
|
149
|
+
For backward compatibility, :attributes! will still work. However, "@" keys will override :attributes! keys if there is a conflict.
|
150
|
+
|
151
|
+
``` ruby
|
152
|
+
Gyoku.xml(:person => {:content! => "Adam", :@id! => 0})
|
153
|
+
# => "<person id=\"0\">Adam</person>"
|
154
|
+
```
|
155
|
+
|
156
|
+
Example with ":content!", :attributes! and "@" keys
|
157
|
+
--------------------------------------------------
|
158
|
+
``` ruby
|
159
|
+
Gyoku.xml({
|
160
|
+
:subtitle => {
|
161
|
+
:@lang => "en",
|
162
|
+
:content! => "It's Godzilla!"
|
163
|
+
},
|
164
|
+
:attributes! => { :subtitle => { "lang" => "jp" } }
|
165
|
+
}
|
166
|
+
# => "<subtitle lang=\"en\">It's Godzilla!</subtitle>"
|
167
|
+
```
|
168
|
+
|
169
|
+
The example above shows an example of how you can use all three at the same time.
|
170
|
+
|
171
|
+
Notice that we have the attribute "lang" defined twice.
|
172
|
+
The "@lang" value takes precedence over the :attribute![:subtitle]["lang"] value.
|
data/lib/gyoku/hash.rb
CHANGED
@@ -28,13 +28,33 @@ module Gyoku
|
|
28
28
|
|
29
29
|
# Iterates over a given +hash+ and yields a builder +xml+ instance, the current
|
30
30
|
# Hash +key+ and any XML +attributes+.
|
31
|
+
#
|
32
|
+
# Keys beginning with "@" are treated as explicit attributes for their container.
|
33
|
+
# You can use both :attributes! and "@" keys to specify attributes.
|
34
|
+
# In the event of a conflict, the "@" key takes precedence.
|
31
35
|
def self.iterate_with_xml(hash)
|
32
36
|
xml = Builder::XmlMarkup.new
|
33
37
|
attributes = hash[:attributes!] || {}
|
34
38
|
hash_without_attributes = hash.reject { |key, value| key == :attributes! }
|
35
39
|
|
36
|
-
order(hash_without_attributes).each do |key|
|
37
|
-
|
40
|
+
order(hash_without_attributes).each do |key|
|
41
|
+
node_attr = attributes[key] || {}
|
42
|
+
# node_attr must be kind of ActiveSupport::HashWithIndifferentAccess
|
43
|
+
node_attr = ::Hash[node_attr.map { |k,v| [k.to_s, v] }]
|
44
|
+
node_value = hash[key]
|
45
|
+
|
46
|
+
if node_value.respond_to?(:keys)
|
47
|
+
explicit_keys = node_value.keys.select{|k| k.to_s =~ /^@/ }
|
48
|
+
explicit_attr = {}
|
49
|
+
explicit_keys.each{|k| explicit_attr[k.to_s[1..-1]] = node_value[k]}
|
50
|
+
node_attr.merge!(explicit_attr)
|
51
|
+
explicit_keys.each{|k| node_value.delete(k) }
|
52
|
+
|
53
|
+
node_value = node_value.delete(:content!) || node_value
|
54
|
+
node_value = "" if node_value.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
yield xml, key, node_value, node_attr
|
38
58
|
end
|
39
59
|
|
40
60
|
xml.target!
|
@@ -48,7 +68,11 @@ module Gyoku
|
|
48
68
|
hash_without_order = hash.reject { |key, value| key == :order! }
|
49
69
|
order = hash_without_order.keys unless order.kind_of? ::Array
|
50
70
|
|
51
|
-
|
71
|
+
# Ignore Explicit Attributes
|
72
|
+
orderable = order.delete_if{|k| k =~ /^@/ }
|
73
|
+
hashable = hash_without_order.keys.select{|k| !(k =~ /^@/) }
|
74
|
+
|
75
|
+
missing, spurious = hashable - orderable, orderable - hashable
|
52
76
|
raise ArgumentError, "Missing elements in :order! #{missing.inspect}" unless missing.empty?
|
53
77
|
raise ArgumentError, "Spurious elements in :order! #{spurious.inspect}" unless spurious.empty?
|
54
78
|
|
data/lib/gyoku/version.rb
CHANGED
data/lib/gyoku/xml_key.rb
CHANGED
@@ -2,12 +2,14 @@ module Gyoku
|
|
2
2
|
module XMLKey
|
3
3
|
class << self
|
4
4
|
|
5
|
-
CAMELCASE
|
5
|
+
CAMELCASE = lambda { |key| key.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } }
|
6
6
|
LOWER_CAMELCASE = lambda { |key| key[0].chr.downcase + CAMELCASE.call(key)[1..-1] }
|
7
|
+
UPCASE = lambda { |key| key.upcase }
|
7
8
|
|
8
9
|
FORMULAS = {
|
9
10
|
:lower_camelcase => lambda { |key| LOWER_CAMELCASE.call(key) },
|
10
11
|
:camelcase => lambda { |key| CAMELCASE.call(key) },
|
12
|
+
:upcase => lambda { |key| UPCASE.call(key) },
|
11
13
|
:none => lambda { |key| key }
|
12
14
|
}
|
13
15
|
|
data/spec/gyoku/hash_spec.rb
CHANGED
@@ -140,6 +140,73 @@ describe Gyoku::Hash do
|
|
140
140
|
to_xml(hash).should == '<category id="1"/>'
|
141
141
|
end
|
142
142
|
|
143
|
+
it "recognizes @attribute => value along :attributes!" do
|
144
|
+
hash = {
|
145
|
+
"category" => {
|
146
|
+
:content! => "users",
|
147
|
+
:@id => 1
|
148
|
+
}
|
149
|
+
}
|
150
|
+
to_xml(hash).should == '<category id="1">users</category>'
|
151
|
+
end
|
152
|
+
|
153
|
+
it "recognizes @attribute => value along :attributes! in selfclosed tags" do
|
154
|
+
hash = {
|
155
|
+
"category/" => {
|
156
|
+
:@id => 1
|
157
|
+
}
|
158
|
+
}
|
159
|
+
to_xml(hash).should == '<category id="1"/>'
|
160
|
+
end
|
161
|
+
|
162
|
+
it ":@attribute => value takes over :attributes!" do
|
163
|
+
hash = {
|
164
|
+
"category/" => {
|
165
|
+
:@id => 1
|
166
|
+
},
|
167
|
+
:attributes! => {
|
168
|
+
"category/" => {
|
169
|
+
'id' => 2, # will be ignored
|
170
|
+
'type' => 'admins'
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
# attribute order is undefined
|
175
|
+
['<category id="1" type="admins"/>','<category type="admins" id="1"/>'].should include to_xml(hash)
|
176
|
+
|
177
|
+
# with symbols
|
178
|
+
hash = {
|
179
|
+
"category/" => {
|
180
|
+
:@id => 1
|
181
|
+
},
|
182
|
+
:attributes! => {
|
183
|
+
"category/" => {
|
184
|
+
:id => 2, # will be ignored
|
185
|
+
:type => 'admins'
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
['<category id="1" type="admins"/>','<category type="admins" id="1"/>'].should include to_xml(hash)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "recognizes :content! => value as tag content" do
|
193
|
+
hash = {
|
194
|
+
"category" => {
|
195
|
+
:content! => "users"
|
196
|
+
}
|
197
|
+
}
|
198
|
+
to_xml(hash).should == "<category>users</category>"
|
199
|
+
end
|
200
|
+
|
201
|
+
it "ignores :content! if self-closing mark present" do
|
202
|
+
hash = {
|
203
|
+
"category/" => {
|
204
|
+
:content! => "users"
|
205
|
+
}
|
206
|
+
}
|
207
|
+
to_xml(hash).should == "<category/>"
|
208
|
+
end
|
209
|
+
|
143
210
|
context "with :element_form_default set to :qualified and a :namespace" do
|
144
211
|
it "adds the given :namespace to every element" do
|
145
212
|
hash = { :first => { "first_name" => "Lucy" }, ":second" => { :":first_name" => "Anna" }, "v2:third" => { "v2:firstName" => "Danie" } }
|
data/spec/gyoku/xml_key_spec.rb
CHANGED
@@ -59,6 +59,11 @@ describe Gyoku::XMLKey do
|
|
59
59
|
Gyoku::XMLKey.create(:snake_case).should == "SnakeCase"
|
60
60
|
end
|
61
61
|
|
62
|
+
it "accepts :upcase" do
|
63
|
+
Gyoku::XMLKey.symbol_converter = :upcase
|
64
|
+
Gyoku::XMLKey.create(:snake_case).should == "SNAKE_CASE"
|
65
|
+
end
|
66
|
+
|
62
67
|
it "accepts :none" do
|
63
68
|
Gyoku::XMLKey.symbol_converter = :none
|
64
69
|
Gyoku::XMLKey.create(:snake_Case).should == "snake_Case"
|
metadata
CHANGED
@@ -1,77 +1,70 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: gyoku
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 4
|
9
|
-
- 6
|
10
|
-
version: 0.4.6
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Daniel Harrington
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
date: 2012-12-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: builder
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
22
17
|
none: false
|
23
|
-
requirements:
|
24
|
-
- -
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
hash: 15
|
27
|
-
segments:
|
28
|
-
- 2
|
29
|
-
- 1
|
30
|
-
- 2
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
31
21
|
version: 2.1.2
|
32
|
-
name: builder
|
33
22
|
type: :runtime
|
34
23
|
prerelease: false
|
35
|
-
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
25
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
|
44
|
-
- 0
|
45
|
-
- 9
|
46
|
-
version: "0.9"
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.1.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
47
31
|
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0.9'
|
48
38
|
type: :development
|
49
39
|
prerelease: false
|
50
|
-
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
41
|
none: false
|
54
|
-
requirements:
|
42
|
+
requirements:
|
55
43
|
- - ~>
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
|
58
|
-
|
59
|
-
- 2
|
60
|
-
- 10
|
61
|
-
version: "2.10"
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.9'
|
46
|
+
- !ruby/object:Gem::Dependency
|
62
47
|
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.10'
|
63
54
|
type: :development
|
64
55
|
prerelease: false
|
65
|
-
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.10'
|
66
62
|
description: Gyoku converts Ruby Hashes to XML
|
67
63
|
email: me@rubiii.com
|
68
64
|
executables: []
|
69
|
-
|
70
65
|
extensions: []
|
71
|
-
|
72
66
|
extra_rdoc_files: []
|
73
|
-
|
74
|
-
files:
|
67
|
+
files:
|
75
68
|
- .gitignore
|
76
69
|
- .rspec
|
77
70
|
- .travis.yml
|
@@ -95,38 +88,35 @@ files:
|
|
95
88
|
- spec/spec_helper.rb
|
96
89
|
homepage: http://github.com/rubiii/gyoku
|
97
90
|
licenses: []
|
98
|
-
|
99
91
|
post_install_message:
|
100
92
|
rdoc_options: []
|
101
|
-
|
102
|
-
require_paths:
|
93
|
+
require_paths:
|
103
94
|
- lib
|
104
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
96
|
none: false
|
106
|
-
requirements:
|
107
|
-
- -
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
|
110
|
-
segments:
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
segments:
|
111
102
|
- 0
|
112
|
-
|
113
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
hash: -3740829974448807903
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
105
|
none: false
|
115
|
-
requirements:
|
116
|
-
- -
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
|
119
|
-
segments:
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
segments:
|
120
111
|
- 0
|
121
|
-
|
112
|
+
hash: -3740829974448807903
|
122
113
|
requirements: []
|
123
|
-
|
124
114
|
rubyforge_project: gyoku
|
125
|
-
rubygems_version: 1.8.
|
115
|
+
rubygems_version: 1.8.24
|
126
116
|
signing_key:
|
127
117
|
specification_version: 3
|
128
118
|
summary: Converts Ruby Hashes to XML
|
129
|
-
test_files:
|
119
|
+
test_files:
|
130
120
|
- spec/gyoku/array_spec.rb
|
131
121
|
- spec/gyoku/hash_spec.rb
|
132
122
|
- spec/gyoku/xml_key_spec.rb
|