xjson 0.1

Sign up to get free protection for your applications and to get access to all the features.
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,4 @@
1
+ [
2
+ { "foobar1": "test1" },
3
+ { "foobar2": "test2" }
4
+ ]
@@ -0,0 +1,4 @@
1
+ {
2
+ "foobar1": "test1",
3
+ "foobar2": "test2"
4
+ }
@@ -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
+ }
@@ -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: []