jsonbuilder 0.1.3 → 0.2.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/Rakefile +1 -1
- data/lib/builder/hash_structure.rb +31 -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 +67 -16
- metadata +7 -4
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,30 @@ 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
|
-
_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
|
+
if args.size > 1 && !args[0].is_a?(Hash)
|
86
|
+
args[0] = StackableHash.new.replace(@default_content_key => args[0])
|
103
87
|
end
|
88
|
+
[key, args]
|
104
89
|
end
|
105
90
|
|
106
91
|
def _set_args(args, &block)
|
107
92
|
args.each do |arg|
|
108
|
-
case arg
|
109
|
-
when
|
110
|
-
self << arg
|
93
|
+
case arg
|
94
|
+
when Hash
|
95
|
+
self << StackableHash.new.replace(arg)
|
111
96
|
else
|
112
|
-
|
97
|
+
@target.current = arg
|
113
98
|
end
|
114
99
|
end
|
115
100
|
if @array_mode && block_given?
|
@@ -121,24 +106,17 @@ module Builder
|
|
121
106
|
end
|
122
107
|
end
|
123
108
|
|
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
|
109
|
+
def _setup_key(key, &block)
|
110
|
+
@root = key unless @root
|
111
|
+
@target = @target.child(key) unless @array_mode
|
133
112
|
yield
|
134
|
-
@
|
113
|
+
@target = @target.parent unless @array_mode
|
135
114
|
end
|
136
115
|
|
137
116
|
def _array_mode(&block)
|
138
117
|
@array_mode = true
|
139
|
-
@
|
118
|
+
@target.current = StackableArray.new
|
140
119
|
yield
|
141
|
-
@path.pop
|
142
120
|
@array_mode = false
|
143
121
|
end
|
144
122
|
|
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 = 0
|
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,16 @@ 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
|
+
|
16
26
|
it "should remove the root tag" do
|
17
27
|
builder = Builder::HashStructure.new
|
18
28
|
# XML :: <root><tag>value</tag></root>
|
@@ -58,7 +68,25 @@ describe Builder::HashStructure do
|
|
58
68
|
builder.target!.should == {:tag => {:id => 1, :text => "value"}}
|
59
69
|
end
|
60
70
|
|
61
|
-
it "should
|
71
|
+
it "should accept strings for insertion" do
|
72
|
+
builder = Builder::HashStructure.new
|
73
|
+
sub_builder = Builder::HashStructure.new
|
74
|
+
sub_builder.tag('value')
|
75
|
+
|
76
|
+
# XML :: <root><tag id="1">value</tag></root>
|
77
|
+
builder.root do
|
78
|
+
builder.tags do |tag|
|
79
|
+
builder << sub_builder.target!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
builder.target!.should == {:tags => "value"}
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
describe Builder::HashStructure, "#cdata!" do
|
88
|
+
|
89
|
+
it "should use the default_content_key when called with attributes" do
|
62
90
|
builder = Builder::HashStructure.new
|
63
91
|
# XML :: <root><tag id="1"><![CDATA[value]]></tag></root>
|
64
92
|
builder.root do
|
@@ -69,7 +97,18 @@ describe Builder::HashStructure do
|
|
69
97
|
builder.target!.should == {:tag => {:id => 1, :content => "value"}}
|
70
98
|
end
|
71
99
|
|
72
|
-
it "should
|
100
|
+
it "should not use the default_content_key when called without attributes" do
|
101
|
+
builder = Builder::HashStructure.new
|
102
|
+
# XML :: <root><tag><![CDATA[value]]></tag></root>
|
103
|
+
builder.root do
|
104
|
+
builder.tag do
|
105
|
+
builder.cdata! "value"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
builder.target!.should == {:tag => "value"}
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should allow the default_content_key to be specified as a second argument" do
|
73
112
|
builder = Builder::HashStructure.new
|
74
113
|
# XML :: <quotes><quote id=\"1\"><![CDATA[All generalizations are false, including this one.]]></quote></quotes>
|
75
114
|
builder.quotes do
|
@@ -80,31 +119,45 @@ describe Builder::HashStructure do
|
|
80
119
|
builder.target!.should == {:quote => {:id => 1, :text => "All generalizations are false, including this one."}}
|
81
120
|
end
|
82
121
|
|
83
|
-
it "should
|
122
|
+
it "should overwrite previous value when called multiple times out of array mode" do
|
84
123
|
builder = Builder::HashStructure.new
|
85
|
-
# XML :: <root><tag
|
124
|
+
# XML :: <root><tag><![CDATA[value1]]><![CDATA[value2]]></tag></root>
|
86
125
|
builder.root do
|
87
|
-
builder.
|
126
|
+
builder.tag do
|
127
|
+
builder.cdata! "value1"
|
128
|
+
builder.cdata! "value2"
|
129
|
+
end
|
88
130
|
end
|
89
|
-
builder.target!.should == {:tag =>
|
131
|
+
builder.target!.should == {:tag => "value2"}
|
90
132
|
end
|
91
133
|
|
92
|
-
it "should
|
134
|
+
it "should add new value when called multiple times in array mode" do
|
93
135
|
builder = Builder::HashStructure.new
|
94
|
-
|
95
|
-
sub_builder.tag('value')
|
96
|
-
|
97
|
-
# XML :: <root><tag id="1">value</tag></root>
|
136
|
+
# XML :: <root><tag id="1"><![CDATA[value]]></tag></root>
|
98
137
|
builder.root do
|
99
|
-
builder.
|
100
|
-
builder
|
138
|
+
builder.tag do
|
139
|
+
builder.array_mode do
|
140
|
+
builder.cdata! "value1"
|
141
|
+
builder.cdata! "value2"
|
142
|
+
end
|
101
143
|
end
|
102
144
|
end
|
103
|
-
builder.target!.should == {:
|
145
|
+
builder.target!.should == {:tag => ["value1", "value2"]}
|
104
146
|
end
|
105
147
|
|
106
148
|
end
|
107
149
|
|
150
|
+
describe Builder::HashStructure, "#content!" do
|
151
|
+
it "should use the specified default_content_key when it and content and attributes are specified via the content!" do
|
152
|
+
builder = Builder::HashStructure.new
|
153
|
+
# XML :: <root><tag id="1">value</tag></root>
|
154
|
+
builder.root do
|
155
|
+
builder.content!(:tag, :text, "value", :id => 1)
|
156
|
+
end
|
157
|
+
builder.target!.should == {:tag => {:id => 1, :text => "value"}}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
108
161
|
describe Builder::HashStructure, '#serialization_method!' do
|
109
162
|
it 'should report the to_hash method' do
|
110
163
|
Builder::HashStructure.new.serialization_method!.should == :to_hash
|
@@ -126,7 +179,6 @@ describe Builder::HashStructure, "#target!" do
|
|
126
179
|
builder.target!.should == {:root => "value"}
|
127
180
|
end
|
128
181
|
|
129
|
-
|
130
182
|
it "should return a HashStructure when root has deeper structure" do
|
131
183
|
builder = Builder::HashStructure.new
|
132
184
|
builder.root do
|
@@ -138,7 +190,6 @@ describe Builder::HashStructure, "#target!" do
|
|
138
190
|
end
|
139
191
|
|
140
192
|
describe Builder::HashStructure, "#root!" do
|
141
|
-
|
142
193
|
it "should force the root tag" do
|
143
194
|
builder = Builder::HashStructure.new
|
144
195
|
builder.root!(:root) do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
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 +09: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,6 +47,9 @@ 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
|
@@ -86,6 +89,6 @@ rubyforge_project: jsonbuilder
|
|
86
89
|
rubygems_version: 1.3.1
|
87
90
|
signing_key:
|
88
91
|
specification_version: 2
|
89
|
-
summary: Builder::XmlMarkup like JsonBuilder
|
92
|
+
summary: Builder::XmlMarkup like JsonBuilder
|
90
93
|
test_files:
|
91
94
|
- spec/jsonbuilder_spec.rb
|