gyoku 0.4.6 → 0.5.0

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