xjson 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +3 -0
- data/doc/Xjson.html +1577 -0
- data/doc/Xjson/XjsonIncludeError.html +124 -0
- data/doc/Xjson/XjsonReferenceError.html +124 -0
- data/doc/_index.html +124 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +496 -0
- data/doc/file.CHANGELOG.html +76 -0
- data/doc/file.README.html +74 -0
- data/doc/file_list.html +61 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +74 -0
- data/doc/js/app.js +314 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +187 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/xjson.rb +268 -0
- data/test/golden/test.json +66 -0
- data/test/input/inc-arr.ext.json +4 -0
- data/test/input/inc-hash.ext.json +4 -0
- data/test/input/test.ext.json +34 -0
- data/test/test_xjson.rb +44 -0
- metadata +71 -0
data/lib/xjson.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'json'
|
2
|
+
# require 'byebug'
|
3
|
+
|
4
|
+
class Xjson
|
5
|
+
|
6
|
+
class XjsonIncludeError < RuntimeError; end
|
7
|
+
class XjsonReferenceError < RuntimeError; end
|
8
|
+
|
9
|
+
VERSION = "0.0.1"
|
10
|
+
def Xjson.version
|
11
|
+
Xjson::VERSION
|
12
|
+
end
|
13
|
+
|
14
|
+
def Xjson.load( filename )
|
15
|
+
Marshal.load( File.read( filename ) )
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :ext_data
|
19
|
+
attr_reader :data
|
20
|
+
attr_reader :dir
|
21
|
+
|
22
|
+
def initialize( xjson_file )
|
23
|
+
@cur_file = []
|
24
|
+
@cur_data = []
|
25
|
+
@ext_data = {}
|
26
|
+
@ext_data = read_json_file( xjson_file )
|
27
|
+
@data = expand( @ext_data )
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_json_file( xjson_file )
|
31
|
+
@cur_file.unshift xjson_file
|
32
|
+
if xjson_file[0] != "<"
|
33
|
+
JSON.parse( File.read( xjson_file ) )
|
34
|
+
else
|
35
|
+
JSON.parse( STDIN.read )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Flatten by one level within array.
|
40
|
+
def flatten( data )
|
41
|
+
case data
|
42
|
+
when Array;
|
43
|
+
res = []
|
44
|
+
data.each do |i|
|
45
|
+
if i.class == Array
|
46
|
+
res += i
|
47
|
+
else
|
48
|
+
res.push i
|
49
|
+
end
|
50
|
+
end
|
51
|
+
res
|
52
|
+
else
|
53
|
+
data
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_in_array_of_hash( scope, key, value )
|
58
|
+
index = 0
|
59
|
+
while index < scope.length
|
60
|
+
if Regexp.new( value).match( scope[ index ][ key ] )
|
61
|
+
return index
|
62
|
+
end
|
63
|
+
index += 1
|
64
|
+
end
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def reference_handle( data, ref_desc )
|
69
|
+
if ref_desc[0] != ":"
|
70
|
+
# [ data, ref_desc ]
|
71
|
+
reference_handle( data, ":#{ref_desc}" )
|
72
|
+
else
|
73
|
+
# Relative reference from root.
|
74
|
+
path = ref_desc.split( ":" )[1..-1]
|
75
|
+
scope = data
|
76
|
+
while path[0..-2].any?
|
77
|
+
if path[0] == "*"
|
78
|
+
# Wildcard for array.
|
79
|
+
unless path[1] && path[2]
|
80
|
+
raise XjsonReferenceError,
|
81
|
+
"Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\", missing match key and value ..."
|
82
|
+
end
|
83
|
+
index = find_in_array_of_hash( scope, path[1], path[2] )
|
84
|
+
unless index
|
85
|
+
raise XjsonReferenceError,
|
86
|
+
"Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\", key and value not matched ..."
|
87
|
+
end
|
88
|
+
scope = scope[ index ]
|
89
|
+
path.shift( 2 )
|
90
|
+
else
|
91
|
+
begin
|
92
|
+
index = Integer( path[0] )
|
93
|
+
scope = scope[ index ]
|
94
|
+
rescue
|
95
|
+
scope = scope[ path[0] ]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
path.shift
|
99
|
+
unless scope
|
100
|
+
raise XjsonReferenceError,
|
101
|
+
"Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\"..."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
[ scope, path[-1] ]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def reference( data, ref_desc )
|
109
|
+
path, label = reference_handle( data, ref_desc )
|
110
|
+
begin
|
111
|
+
index = Integer( label )
|
112
|
+
scope = path[ index ]
|
113
|
+
rescue
|
114
|
+
# scope = scope[ path[0] ]
|
115
|
+
scope = path[ label ]
|
116
|
+
end
|
117
|
+
# scope = path[ label ]
|
118
|
+
# if scope.class == String
|
119
|
+
scope
|
120
|
+
# else
|
121
|
+
# scope.to_s
|
122
|
+
# end
|
123
|
+
end
|
124
|
+
|
125
|
+
def override_desc( data, exp )
|
126
|
+
path, label = reference_handle( data, exp[0] )
|
127
|
+
{ path: path, label: label, value: exp[1] }
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def override_apply( desc, overwrite = false )
|
132
|
+
if desc[:label] == "*"
|
133
|
+
desc[:path].each do |place|
|
134
|
+
if not( place[ desc[:value][0] ] ) || overwrite
|
135
|
+
place[ desc[:value][0] ] = desc[:value][1]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
else
|
139
|
+
if not( desc[:path][desc[:label]] ) || overwrite
|
140
|
+
desc[:path][desc[:label]] = desc[:value]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def override( data, exp, overwrite = false )
|
147
|
+
desc = override_desc( data, exp )
|
148
|
+
override_apply( desc, overwrite )
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# Expand json recursively.
|
153
|
+
def expand( data )
|
154
|
+
|
155
|
+
case data
|
156
|
+
|
157
|
+
when TrueClass; data
|
158
|
+
|
159
|
+
when FalseClass; data
|
160
|
+
|
161
|
+
when Float; data
|
162
|
+
|
163
|
+
when Integer; data
|
164
|
+
|
165
|
+
when String; data
|
166
|
+
|
167
|
+
when Array;
|
168
|
+
ret = []
|
169
|
+
@cur_data.unshift ret
|
170
|
+
data.each do |v|
|
171
|
+
value = expand( v )
|
172
|
+
ret.push( value ) if value
|
173
|
+
end
|
174
|
+
@cur_data.shift
|
175
|
+
ret
|
176
|
+
|
177
|
+
when Hash
|
178
|
+
|
179
|
+
if data.size == 1
|
180
|
+
|
181
|
+
# Most possible extension.
|
182
|
+
|
183
|
+
k, v = data.first
|
184
|
+
|
185
|
+
case k
|
186
|
+
|
187
|
+
when "@eval"
|
188
|
+
%x"#{expand(v)}".split("\n")
|
189
|
+
|
190
|
+
when "@env"
|
191
|
+
ENV[expand(v)]
|
192
|
+
|
193
|
+
when "@join"
|
194
|
+
flatten( v[1..-1].map{|i| expand( i )} ).join( v[0] )
|
195
|
+
|
196
|
+
when "@flat"
|
197
|
+
flatten( v[1..-1].map{|i| expand( i )} )
|
198
|
+
|
199
|
+
when "@self"
|
200
|
+
reference( @ext_data, expand(v) )
|
201
|
+
|
202
|
+
when "@over";
|
203
|
+
override( @cur_data[0], expand(v), true )
|
204
|
+
nil
|
205
|
+
|
206
|
+
when "@base";
|
207
|
+
override( @cur_data[0], expand(v), false )
|
208
|
+
nil
|
209
|
+
|
210
|
+
when "@null"
|
211
|
+
nil
|
212
|
+
|
213
|
+
when "@include";
|
214
|
+
jsonfile = expand(v)
|
215
|
+
subdata = read_json_file( jsonfile )
|
216
|
+
expdata = expand( subdata )
|
217
|
+
if expdata.class == Hash
|
218
|
+
if @cur_data[0].class == expdata.class
|
219
|
+
expdata.each do |ke,ve|
|
220
|
+
@cur_data[0][ ke ] = ve
|
221
|
+
end
|
222
|
+
else
|
223
|
+
raise XjsonIncludeError,
|
224
|
+
"Included file (\"#{jsonfile}\") must contain a hash as top level"
|
225
|
+
end
|
226
|
+
elsif expdata.class == Array
|
227
|
+
expdata.each do |ve|
|
228
|
+
@cur_data[0].push ve
|
229
|
+
end
|
230
|
+
else
|
231
|
+
raise XjsonIncludeError,
|
232
|
+
"Included file (\"#{jsonfile}\") must contain a hash or a an array as top level"
|
233
|
+
end
|
234
|
+
@cur_file.shift
|
235
|
+
nil
|
236
|
+
|
237
|
+
else
|
238
|
+
# Non-extension.
|
239
|
+
{ k => expand( v ) }
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
else
|
244
|
+
ret = {}
|
245
|
+
@cur_data.unshift ret
|
246
|
+
data.each do |k,v|
|
247
|
+
case k
|
248
|
+
when "@null"; nil
|
249
|
+
else
|
250
|
+
value = expand( v )
|
251
|
+
ret[ k ] = value if value
|
252
|
+
end
|
253
|
+
end
|
254
|
+
@cur_data.shift
|
255
|
+
ret
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def to_s
|
261
|
+
JSON.pretty_generate( @data )
|
262
|
+
end
|
263
|
+
|
264
|
+
def dump( filename )
|
265
|
+
File.write( filename, Marshal.dump( @data ) )
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
{
|
2
|
+
"action": "test",
|
3
|
+
"regressions": {
|
4
|
+
"all": {
|
5
|
+
"test": [
|
6
|
+
[
|
7
|
+
"t_run_1_2",
|
8
|
+
[
|
9
|
+
1234
|
10
|
+
]
|
11
|
+
],
|
12
|
+
[
|
13
|
+
"t_run_1_4",
|
14
|
+
[
|
15
|
+
1234
|
16
|
+
]
|
17
|
+
],
|
18
|
+
[
|
19
|
+
"t_run_2_1",
|
20
|
+
[
|
21
|
+
1234
|
22
|
+
]
|
23
|
+
],
|
24
|
+
[
|
25
|
+
"t_run_2_2",
|
26
|
+
[
|
27
|
+
1234
|
28
|
+
]
|
29
|
+
],
|
30
|
+
[
|
31
|
+
"t_run_7_1",
|
32
|
+
[
|
33
|
+
1234
|
34
|
+
]
|
35
|
+
],
|
36
|
+
{
|
37
|
+
"foobar1": "test1"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"foobar2": "test2"
|
41
|
+
}
|
42
|
+
]
|
43
|
+
}
|
44
|
+
},
|
45
|
+
"foobar1": "test1",
|
46
|
+
"foobar2": "test2",
|
47
|
+
"release": "201104",
|
48
|
+
"minor": "3",
|
49
|
+
"runroot": "prog-",
|
50
|
+
"home": "FOOBAR",
|
51
|
+
"dut_files": [
|
52
|
+
"/release/201104/src/main.c",
|
53
|
+
[
|
54
|
+
"YES: 3"
|
55
|
+
],
|
56
|
+
{
|
57
|
+
"myarr": [
|
58
|
+
"bar",
|
59
|
+
1,
|
60
|
+
2,
|
61
|
+
3
|
62
|
+
]
|
63
|
+
}
|
64
|
+
],
|
65
|
+
"eof": true
|
66
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"action": "test",
|
3
|
+
|
4
|
+
"regressions": {
|
5
|
+
|
6
|
+
"all": {
|
7
|
+
"test": [
|
8
|
+
[ "t_run_1_2", [ 1234 ] ],
|
9
|
+
{ "@null": false },
|
10
|
+
[ "t_run_1_4", [ 1234 ] ],
|
11
|
+
[ "t_run_2_1", [ 1234 ] ],
|
12
|
+
[ "t_run_2_2", [ 1234 ] ],
|
13
|
+
[ "t_run_7_1", [ 1234 ] ],
|
14
|
+
{ "@include": "test/input/inc-arr.ext.json" }
|
15
|
+
]
|
16
|
+
}
|
17
|
+
},
|
18
|
+
|
19
|
+
"included-file": { "@include": "test/input/inc-hash.ext.json" },
|
20
|
+
|
21
|
+
"release" : "201104",
|
22
|
+
"minor" : "3",
|
23
|
+
"runroot" : { "@join": [ "-", "prog", {"@self":":regressions:all:test:1:0"} ] },
|
24
|
+
"home" : { "@env": "XJSON_FOOBAR" },
|
25
|
+
|
26
|
+
|
27
|
+
"dut_files": [
|
28
|
+
{ "@join": [ "/", "/release", {"@self":"release"}, "src/main.c" ] },
|
29
|
+
{ "@eval": { "@join": [ " ", "echo YES:", {"@self": "minor"} ] } },
|
30
|
+
{ "myarr": { "@flat" : [ "foo", "bar", [ 1, 2 ,3 ] ] } }
|
31
|
+
],
|
32
|
+
|
33
|
+
"eof": true
|
34
|
+
}
|
data/test/test_xjson.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require_relative '../lib/xjson.rb'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class XjsonTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_basic
|
8
|
+
|
9
|
+
FileUtils.mkdir_p( "test/result" )
|
10
|
+
|
11
|
+
ENV['XJSON_FOOBAR'] = "FOOBAR"
|
12
|
+
|
13
|
+
ifile = 'test/input/test.ext.json'
|
14
|
+
|
15
|
+
# Open file.
|
16
|
+
json = Xjson.new( ifile )
|
17
|
+
ofile = "test/result/test.json"
|
18
|
+
File.write( ofile, JSON.pretty_generate( json.data ) )
|
19
|
+
|
20
|
+
golden_data = File.read( "test/golden/test.json" )
|
21
|
+
design_data = File.read( ofile )
|
22
|
+
|
23
|
+
assert_equal( golden_data, design_data )
|
24
|
+
|
25
|
+
FileUtils.rm_f ofile
|
26
|
+
FileUtils.rm_f "test/result"
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
#require_relative '../lib/xjson.rb'
|
33
|
+
#require 'fileutils'
|
34
|
+
#FileUtils.mkdir_p( "test/result" )
|
35
|
+
#
|
36
|
+
#ifile = 'test/input/test.ext.json'
|
37
|
+
#
|
38
|
+
## Open file.
|
39
|
+
#json = Xjson.new( ifile )
|
40
|
+
#ofile = "test/result/test.json"
|
41
|
+
#File.write( ofile, JSON.pretty_generate( json.data ) )
|
42
|
+
#
|
43
|
+
#golden_data = File.read( "test/golden/test.json" )
|
44
|
+
#design_data = File.read( ofile )
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xjson
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tero Isannainen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-07-08 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Xjson is extension to JSON format.
|
14
|
+
email: tero.isannainen@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files:
|
18
|
+
- README.rdoc
|
19
|
+
- CHANGELOG.rdoc
|
20
|
+
files:
|
21
|
+
- CHANGELOG.rdoc
|
22
|
+
- LICENSE
|
23
|
+
- README.rdoc
|
24
|
+
- doc/Xjson.html
|
25
|
+
- doc/Xjson/XjsonIncludeError.html
|
26
|
+
- doc/Xjson/XjsonReferenceError.html
|
27
|
+
- doc/_index.html
|
28
|
+
- doc/class_list.html
|
29
|
+
- doc/css/common.css
|
30
|
+
- doc/css/full_list.css
|
31
|
+
- doc/css/style.css
|
32
|
+
- doc/file.CHANGELOG.html
|
33
|
+
- doc/file.README.html
|
34
|
+
- doc/file_list.html
|
35
|
+
- doc/frames.html
|
36
|
+
- doc/index.html
|
37
|
+
- doc/js/app.js
|
38
|
+
- doc/js/full_list.js
|
39
|
+
- doc/js/jquery.js
|
40
|
+
- doc/method_list.html
|
41
|
+
- doc/top-level-namespace.html
|
42
|
+
- lib/xjson.rb
|
43
|
+
- test/golden/test.json
|
44
|
+
- test/input/inc-arr.ext.json
|
45
|
+
- test/input/inc-hash.ext.json
|
46
|
+
- test/input/test.ext.json
|
47
|
+
- test/test_xjson.rb
|
48
|
+
homepage:
|
49
|
+
licenses:
|
50
|
+
- Ruby
|
51
|
+
metadata: {}
|
52
|
+
post_install_message: Check README...
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.9.3
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubygems_version: 3.2.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: Xjson is extension to JSON format.
|
71
|
+
test_files: []
|