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 CHANGED
@@ -4,6 +4,7 @@ doc
4
4
  coverage
5
5
  tmp
6
6
  *~
7
+ *.swp
7
8
  *.gem
8
9
  .bundle
9
- Gemfile.lock
10
+ Gemfile.lock
@@ -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.upcase }
43
+ Gyoku.convert_symbols_to { |key| key.sub(/^prefixed_/, '') }
44
44
 
45
- Gyoku.xml(:upcase => "key")
46
- # => "<UPCASE>key</UPCASE>"
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.
@@ -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
- yield xml, key, hash_without_attributes[key], (attributes[key] || {})
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
- missing, spurious = hash_without_order.keys - order, order - hash_without_order.keys
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
 
@@ -1,5 +1,5 @@
1
1
  module Gyoku
2
2
 
3
- VERSION = "0.4.6"
3
+ VERSION = "0.5.0"
4
4
 
5
5
  end
@@ -2,12 +2,14 @@ module Gyoku
2
2
  module XMLKey
3
3
  class << self
4
4
 
5
- CAMELCASE = lambda { |key| key.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } }
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
 
@@ -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" } }
@@ -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
- hash: 3
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
- date: 2012-06-28 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
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
- requirement: *id001
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
- hash: 25
43
- segments:
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
- requirement: *id002
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
- hash: 23
58
- segments:
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
- requirement: *id003
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
- hash: 3
110
- segments:
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
111
102
  - 0
112
- version: "0"
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
- hash: 3
119
- segments:
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
120
111
  - 0
121
- version: "0"
112
+ hash: -3740829974448807903
122
113
  requirements: []
123
-
124
114
  rubyforge_project: gyoku
125
- rubygems_version: 1.8.21
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