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 +1 -1
- data/lib/builder/hash_structure.rb +32 -53
- data/lib/builder/json_format.rb +1 -12
- data/lib/ext/stackable_array.rb +35 -0
- data/lib/ext/stackable_hash.rb +27 -0
- data/lib/jsonbuilder.rb +4 -2
- data/spec/builder/hash_structure_spec.rb +85 -16
- metadata +9 -5
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
|
|
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
|
|
15
|
+
if @target.current.is_a?(Hash) && !@target.current.empty?
|
|
16
16
|
key ||= :entry
|
|
17
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
@
|
|
49
|
+
@target.current << _target
|
|
50
|
+
elsif _target.is_a?(Hash)
|
|
51
|
+
@target.current.merge!(_target)
|
|
54
52
|
else
|
|
55
|
-
|
|
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
|
-
@
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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 =
|
|
80
|
-
|
|
81
|
-
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
|
110
|
-
self << arg
|
|
94
|
+
case arg
|
|
95
|
+
when Hash
|
|
96
|
+
self << StackableHash.new.replace(arg)
|
|
111
97
|
else
|
|
112
|
-
|
|
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
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
@
|
|
114
|
+
@target = @target.parent unless @array_mode
|
|
135
115
|
end
|
|
136
116
|
|
|
137
117
|
def _array_mode(&block)
|
|
138
118
|
@array_mode = true
|
|
139
|
-
@
|
|
119
|
+
@target.current = StackableArray.new
|
|
140
120
|
yield
|
|
141
|
-
@path.pop
|
|
142
121
|
@array_mode = false
|
|
143
122
|
end
|
|
144
123
|
|
data/lib/builder/json_format.rb
CHANGED
|
@@ -22,18 +22,7 @@ module Builder
|
|
|
22
22
|
_target.symbolize_keys! if _target.is_a?(Hash)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
|
|
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 =
|
|
5
|
-
REVISION =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
142
|
+
# XML :: <root><tag><![CDATA[value1]]><![CDATA[value2]]></tag></root>
|
|
86
143
|
builder.root do
|
|
87
|
-
builder.
|
|
144
|
+
builder.tag do
|
|
145
|
+
builder.cdata! "value1"
|
|
146
|
+
builder.cdata! "value2"
|
|
147
|
+
end
|
|
88
148
|
end
|
|
89
|
-
builder.target!.should == {:tag =>
|
|
149
|
+
builder.target!.should == {:tag => "value2"}
|
|
90
150
|
end
|
|
91
151
|
|
|
92
|
-
it "should
|
|
152
|
+
it "should add new value when called multiple times in array mode" do
|
|
93
153
|
builder = Builder::HashStructure.new
|
|
94
|
-
|
|
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.
|
|
100
|
-
builder
|
|
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 == {:
|
|
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
|
|
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-
|
|
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
|
|
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.
|
|
90
|
+
rubygems_version: 1.3.5
|
|
87
91
|
signing_key:
|
|
88
92
|
specification_version: 2
|
|
89
|
-
summary: Builder::XmlMarkup like JsonBuilder
|
|
93
|
+
summary: Builder::XmlMarkup like JsonBuilder
|
|
90
94
|
test_files:
|
|
91
95
|
- spec/jsonbuilder_spec.rb
|