nov-jsonbuilder 0.1.3 → 0.2.1

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