nov-jsonbuilder 0.1.3 → 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/Rakefile CHANGED
@@ -13,7 +13,7 @@ include FileUtils
13
13
  NAME = "jsonbuilder"
14
14
  AUTHOR = "nov"
15
15
  EMAIL = "nov@matake.jp"
16
- DESCRIPTION = "Builder::XmlMarkup like JsonBuilder (Builder::JsonMarkup)"
16
+ DESCRIPTION = "Builder::XmlMarkup like JsonBuilder"
17
17
  RUBYFORGE_PROJECT = NAME
18
18
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
19
19
  BIN_FILES = %w( )
@@ -6,26 +6,24 @@ module Builder
6
6
  # in this case, we need some key for value.
7
7
  @default_content_key = (options[:default_content_key] || :content).to_sym
8
8
  @include_root = options[:include_root]
9
- @target = {}
9
+ @target = StackableHash.new
10
10
  @array_mode = false
11
11
  end
12
12
 
13
13
  # NOTICE: you have to call this method to use array in json
14
14
  def array_mode(key = nil, &block)
15
- if eval("#{_current}").is_a?(::Hash)
15
+ if @target.current.is_a?(Hash) && !@target.current.empty?
16
16
  key ||= :entry
17
- eval("#{_current}.merge!(key => [])")
18
- _move_current(key.to_sym) do
17
+ _setup_key(key.to_sym) do
19
18
  _array_mode(&block)
20
19
  end
21
20
  else
22
- eval("#{_current} = []")
23
21
  _array_mode(&block)
24
22
  end
25
23
  end
26
24
 
27
25
  def target!
28
- if @include_root
26
+ if @include_root || @target.is_a?(Array)
29
27
  @target
30
28
  else
31
29
  @target[@root]
@@ -48,25 +46,22 @@ module Builder
48
46
 
49
47
  def <<(_target)
50
48
  if @array_mode
51
- key = @path.pop
52
- eval("#{_current} << _target")
53
- @path.push(key)
49
+ @target.current << _target
50
+ elsif _target.is_a?(Hash)
51
+ @target.current.merge!(_target)
54
52
  else
55
- if _target.is_a?(String)
56
- eval("#{_current} = _target")
57
- else
58
- eval("#{_current} ||= {}")
59
- eval("#{_current}.merge!(_target)")
60
- end
53
+ @target.current = _target
61
54
  end
62
55
  end
63
56
 
64
57
  def text!(text, default_content_key = nil)
65
- @default_content_key = default_content_key.to_sym unless default_content_key.nil?
66
- if eval("#{_current}").is_a?(::Hash)
67
- eval("#{_current}.merge!({@default_content_key => text})")
58
+ if @target.current.is_a?(Array)
59
+ @target.current << text
60
+ elsif @target.current.is_a?(Hash) && !@target.current.empty?
61
+ @default_content_key = default_content_key.to_sym unless default_content_key.nil?
62
+ @target.current.merge!(StackableHash.new.replace(@default_content_key => text))
68
63
  else
69
- eval("#{_current} = text")
64
+ @target.current = text
70
65
  end
71
66
  end
72
67
  alias_method :cdata!, :text!
@@ -76,40 +71,31 @@ module Builder
76
71
  end
77
72
 
78
73
  def method_missing(key, *args, &block)
79
- key = args.first.is_a?(Symbol) ? "#{key}:#{args.shift}".to_sym : key.to_sym
80
- args[0] = {@default_content_key => args[0]} if args.size > 1 && !args[0].is_a?(::Hash)
81
- if @root
82
- _child(key, args, &block)
83
- else
84
- _root(key, args, &block)
74
+ key, args = _explore_key_and_args(key, *args)
75
+ _setup_key(key) do
76
+ _set_args(args, &block)
85
77
  end
86
78
  target!
87
79
  end
88
80
 
89
81
  private
90
82
 
91
- def _root(root, args, &block)
92
- @root = root
93
- @target[root] = {}
94
- @path = [root]
95
- _set_args(args, &block)
96
- yield(self) if block_given?
97
- end
98
-
99
- def _child(key, args, &block)
100
- eval("#{_current} ||= {}") unless @array_mode
101
- _move_current(key) do
102
- _set_args(args, &block)
83
+ def _explore_key_and_args(key, *args)
84
+ key = (args.first.is_a?(Symbol) ? "#{key}:#{args.shift}" : key.to_s).gsub(/[-:]/, "_").to_sym
85
+ args.reject! { |arg| arg.nil? }
86
+ if args.size > 1 && !args[0].is_a?(Hash)
87
+ args[0] = StackableHash.new.replace(@default_content_key => args[0])
103
88
  end
89
+ [key, args]
104
90
  end
105
91
 
106
92
  def _set_args(args, &block)
107
93
  args.each do |arg|
108
- case arg
109
- when ::Hash
110
- self << arg
94
+ case arg
95
+ when Hash
96
+ self << StackableHash.new.replace(arg)
111
97
  else
112
- eval("#{_current} = arg")
98
+ @target.current = arg
113
99
  end
114
100
  end
115
101
  if @array_mode && block_given?
@@ -121,24 +107,17 @@ module Builder
121
107
  end
122
108
  end
123
109
 
124
- def _current
125
- current_path = @path.inject('') do |current_path, key|
126
- current_path += key.is_a?(Integer) ? "[#{key}]" : "[:\"#{key}\"]"
127
- end
128
- "@target#{current_path}"
129
- end
130
-
131
- def _move_current(key, &block)
132
- @path.push(key) unless @array_mode
110
+ def _setup_key(key, &block)
111
+ @root = key unless @root
112
+ @target = @target.child(key) unless @array_mode
133
113
  yield
134
- @array_mode ? @path[@path.size - 1] += 1 : @path.pop
114
+ @target = @target.parent unless @array_mode
135
115
  end
136
116
 
137
117
  def _array_mode(&block)
138
118
  @array_mode = true
139
- @path.push(0)
119
+ @target.current = StackableArray.new
140
120
  yield
141
- @path.pop
142
121
  @array_mode = false
143
122
  end
144
123
 
@@ -22,18 +22,7 @@ module Builder
22
22
  _target.symbolize_keys! if _target.is_a?(Hash)
23
23
  end
24
24
 
25
- if @array_mode
26
- key = @path.pop
27
- eval("#{_current} << _target")
28
- @path.push(key)
29
- else
30
- if _target.is_a?(String)
31
- eval("#{_current} = _target")
32
- else
33
- eval("#{_current} ||= {}")
34
- eval("#{_current}.merge!(_target)")
35
- end
36
- end
25
+ super(_target)
37
26
  end
38
27
 
39
28
  def target!
@@ -0,0 +1,35 @@
1
+ class StackableArray < Array
2
+ attr_accessor :parent, :current_key
3
+
4
+ def child(key)
5
+ hash = StackableHash.new
6
+ hash[key] = StackableHash.new
7
+
8
+ new_target = self.current
9
+ new_target.merge!(hash)
10
+ new_target.current_key = key
11
+ new_target.parent = self
12
+ new_target
13
+ end
14
+
15
+ def merge!(hash)
16
+ if self.last.is_a?(Hash) && !self.last.key?(hash.keys.first)
17
+ self.last.merge!(hash)
18
+ else
19
+ self << hash
20
+ end
21
+ end
22
+
23
+ def current=(value)
24
+ if self.current.is_a?(Hash)
25
+ self.last[current_key] = value
26
+ else
27
+ self << value
28
+ end
29
+ end
30
+
31
+ def current
32
+ self.current_key ? self.last[current_key] : self.last
33
+ end
34
+
35
+ end
@@ -0,0 +1,27 @@
1
+ class StackableHash < Hash
2
+ attr_accessor :parent, :current_key
3
+
4
+ def child(key)
5
+ hash = StackableHash.new
6
+ hash[key] = StackableHash.new
7
+
8
+ new_target = self.current || self
9
+ new_target.merge!(hash)
10
+ new_target.current_key = key
11
+ new_target.parent = self
12
+ new_target
13
+ end
14
+
15
+ def <<(value)
16
+ self[current_key] << value
17
+ end
18
+
19
+ def current=(value)
20
+ self[current_key] = value
21
+ end
22
+
23
+ def current
24
+ self[current_key]
25
+ end
26
+
27
+ end
data/lib/jsonbuilder.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module JsonBuilder
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 1
5
- REVISION = 3
4
+ MINOR = 2
5
+ REVISION = 1
6
6
  class << self
7
7
  def to_version
8
8
  "#{MAJOR}.#{MINOR}.#{REVISION}"
@@ -19,3 +19,5 @@ require 'builder/abstract'
19
19
  require 'builder/xml_markup'
20
20
  require 'builder/hash_structure'
21
21
  require 'builder/json_format'
22
+ require 'ext/stackable_hash'
23
+ require 'ext/stackable_array'
@@ -13,6 +13,34 @@ end
13
13
 
14
14
  describe Builder::HashStructure do
15
15
 
16
+ it "should replace ':' and '-' with '_' if those characters are used as a key" do
17
+ builder = Builder::HashStructure.new
18
+ builder.root do
19
+ builder.atom :name, "atom:name" # atom:name
20
+ builder.thr :"in-reply-to", "thr:in-reply-to" # thr:in-reply-to
21
+ builder.tag! :"dc:creator", "dc:creator" # thr:in-reply-to
22
+ end
23
+ builder.target!.should == {:atom_name => "atom:name", :thr_in_reply_to => "thr:in-reply-to", :dc_creator => "dc:creator"}
24
+ end
25
+
26
+ it "should support root attributes" do
27
+ builder = Builder::HashStructure.new
28
+ # XML :: <root><tag>value</tag></root>
29
+ builder.root(:id => 1) do
30
+ builder.tag "value"
31
+ end
32
+ builder.target!.should == {:id => 1, :tag => "value"}
33
+ end
34
+
35
+ it "should ignore nil attributes" do
36
+ builder = Builder::HashStructure.new
37
+ # XML :: <root><tag>value</tag></root>
38
+ builder.root(nil) do
39
+ builder.tag "value"
40
+ end
41
+ builder.target!.should == {:tag => "value"}
42
+ end
43
+
16
44
  it "should remove the root tag" do
17
45
  builder = Builder::HashStructure.new
18
46
  # XML :: <root><tag>value</tag></root>
@@ -58,7 +86,25 @@ describe Builder::HashStructure do
58
86
  builder.target!.should == {:tag => {:id => 1, :text => "value"}}
59
87
  end
60
88
 
61
- it "should use the default_content_key when both cdata! and attributes exist" do
89
+ it "should accept strings for insertion" do
90
+ builder = Builder::HashStructure.new
91
+ sub_builder = Builder::HashStructure.new
92
+ sub_builder.tag('value')
93
+
94
+ # XML :: <root><tag id="1">value</tag></root>
95
+ builder.root do
96
+ builder.tags do |tag|
97
+ builder << sub_builder.target!
98
+ end
99
+ end
100
+ builder.target!.should == {:tags => "value"}
101
+ end
102
+
103
+ end
104
+
105
+ describe Builder::HashStructure, "#cdata!" do
106
+
107
+ it "should use the default_content_key when called with attributes" do
62
108
  builder = Builder::HashStructure.new
63
109
  # XML :: <root><tag id="1"><![CDATA[value]]></tag></root>
64
110
  builder.root do
@@ -69,7 +115,18 @@ describe Builder::HashStructure do
69
115
  builder.target!.should == {:tag => {:id => 1, :content => "value"}}
70
116
  end
71
117
 
72
- it "should allow the default_content_key to be specified as a second argument to cdata!" do
118
+ it "should not use the default_content_key when called without attributes" do
119
+ builder = Builder::HashStructure.new
120
+ # XML :: <root><tag><![CDATA[value]]></tag></root>
121
+ builder.root do
122
+ builder.tag do
123
+ builder.cdata! "value"
124
+ end
125
+ end
126
+ builder.target!.should == {:tag => "value"}
127
+ end
128
+
129
+ it "should allow the default_content_key to be specified as a second argument" do
73
130
  builder = Builder::HashStructure.new
74
131
  # XML :: <quotes><quote id=\"1\"><![CDATA[All generalizations are false, including this one.]]></quote></quotes>
75
132
  builder.quotes do
@@ -80,31 +137,45 @@ describe Builder::HashStructure do
80
137
  builder.target!.should == {:quote => {:id => 1, :text => "All generalizations are false, including this one."}}
81
138
  end
82
139
 
83
- it "should use the specified default_content_key when it and content and attributes are specified via the content!" do
140
+ it "should overwrite previous value when called multiple times out of array mode" do
84
141
  builder = Builder::HashStructure.new
85
- # XML :: <root><tag id="1">value</tag></root>
142
+ # XML :: <root><tag><![CDATA[value1]]><![CDATA[value2]]></tag></root>
86
143
  builder.root do
87
- builder.content!(:tag, :text, "value", :id => 1)
144
+ builder.tag do
145
+ builder.cdata! "value1"
146
+ builder.cdata! "value2"
147
+ end
88
148
  end
89
- builder.target!.should == {:tag => {:id => 1, :text => "value"}}
149
+ builder.target!.should == {:tag => "value2"}
90
150
  end
91
151
 
92
- it "should accept strings for insertion" do
152
+ it "should add new value when called multiple times in array mode" do
93
153
  builder = Builder::HashStructure.new
94
- sub_builder = Builder::HashStructure.new
95
- sub_builder.tag('value')
96
-
97
- # XML :: <root><tag id="1">value</tag></root>
154
+ # XML :: <root><tag id="1"><![CDATA[value]]></tag></root>
98
155
  builder.root do
99
- builder.tags do |tag|
100
- builder << sub_builder.target!
156
+ builder.tag do
157
+ builder.array_mode do
158
+ builder.cdata! "value1"
159
+ builder.cdata! "value2"
160
+ end
101
161
  end
102
162
  end
103
- builder.target!.should == {:tags => "value"}
163
+ builder.target!.should == {:tag => ["value1", "value2"]}
104
164
  end
105
165
 
106
166
  end
107
167
 
168
+ describe Builder::HashStructure, "#content!" do
169
+ it "should use the specified default_content_key when it and content and attributes are specified via the content!" do
170
+ builder = Builder::HashStructure.new
171
+ # XML :: <root><tag id="1">value</tag></root>
172
+ builder.root do
173
+ builder.content!(:tag, :text, "value", :id => 1)
174
+ end
175
+ builder.target!.should == {:tag => {:id => 1, :text => "value"}}
176
+ end
177
+ end
178
+
108
179
  describe Builder::HashStructure, '#serialization_method!' do
109
180
  it 'should report the to_hash method' do
110
181
  Builder::HashStructure.new.serialization_method!.should == :to_hash
@@ -126,7 +197,6 @@ describe Builder::HashStructure, "#target!" do
126
197
  builder.target!.should == {:root => "value"}
127
198
  end
128
199
 
129
-
130
200
  it "should return a HashStructure when root has deeper structure" do
131
201
  builder = Builder::HashStructure.new
132
202
  builder.root do
@@ -138,7 +208,6 @@ describe Builder::HashStructure, "#target!" do
138
208
  end
139
209
 
140
210
  describe Builder::HashStructure, "#root!" do
141
-
142
211
  it "should force the root tag" do
143
212
  builder = Builder::HashStructure.new
144
213
  builder.root!(:root) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nov-jsonbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - nov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-02 00:00:00 -07:00
12
+ date: 2009-07-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,7 +22,7 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: "0"
24
24
  version:
25
- description: Builder::XmlMarkup like JsonBuilder (Builder::JsonMarkup)
25
+ description: Builder::XmlMarkup like JsonBuilder
26
26
  email: nov@matake.jp
27
27
  executables: []
28
28
 
@@ -47,11 +47,15 @@ files:
47
47
  - lib/builder/hash_structure.rb
48
48
  - lib/builder/json_format.rb
49
49
  - lib/builder/xml_markup.rb
50
+ - lib/ext
51
+ - lib/ext/stackable_array.rb
52
+ - lib/ext/stackable_hash.rb
50
53
  - lib/jsonbuilder.rb
51
54
  - lib/patch
52
55
  - lib/patch/active_support_json_decode.rb
53
56
  has_rdoc: true
54
57
  homepage: http://jsonbuilder.rubyforge.org
58
+ licenses:
55
59
  post_install_message:
56
60
  rdoc_options:
57
61
  - --title
@@ -83,9 +87,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
87
  requirements: []
84
88
 
85
89
  rubyforge_project: jsonbuilder
86
- rubygems_version: 1.2.0
90
+ rubygems_version: 1.3.5
87
91
  signing_key:
88
92
  specification_version: 2
89
- summary: Builder::XmlMarkup like JsonBuilder (Builder::JsonMarkup)
93
+ summary: Builder::XmlMarkup like JsonBuilder
90
94
  test_files:
91
95
  - spec/jsonbuilder_spec.rb