Class: Xjson

Inherits:
Object
  • Object
show all
Defined in:
lib/xjson.rb

Overview

require ‘byebug’

Defined Under Namespace

Classes: XjsonIncludeError, XjsonReferenceError

Constant Summary collapse

VERSION =
"0.0.1"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(xjson_file) ⇒ Xjson

Returns a new instance of Xjson.



22
23
24
25
26
27
28
# File 'lib/xjson.rb', line 22

def initialize( xjson_file )
    @cur_file = []
    @cur_data = []
    @ext_data = {}
    @ext_data = read_json_file( xjson_file )
    @data = expand( @ext_data )
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



19
20
21
# File 'lib/xjson.rb', line 19

def data
  @data
end

#dirObject (readonly)

Returns the value of attribute dir.



20
21
22
# File 'lib/xjson.rb', line 20

def dir
  @dir
end

#ext_dataObject (readonly)

Returns the value of attribute ext_data.



18
19
20
# File 'lib/xjson.rb', line 18

def ext_data
  @ext_data
end

Class Method Details

.load(filename) ⇒ Object



14
15
16
# File 'lib/xjson.rb', line 14

def Xjson.load( filename )
    Marshal.load( File.read( filename ) )
end

.versionObject



10
11
12
# File 'lib/xjson.rb', line 10

def Xjson.version
    Xjson::VERSION
end

Instance Method Details

#dump(filename) ⇒ Object



264
265
266
# File 'lib/xjson.rb', line 264

def dump( filename )
    File.write( filename, Marshal.dump( @data ) )
end

#expand(data) ⇒ Object

Expand json recursively.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/xjson.rb', line 153

def expand( data )

    case data

    when TrueClass; data

    when FalseClass; data

    when Float; data

    when Integer; data

    when String; data

    when Array;
        ret = []
        @cur_data.unshift ret
        data.each do |v|
            value = expand( v )
            ret.push( value ) if value
        end
        @cur_data.shift
        ret

    when Hash

        if data.size == 1

            # Most possible extension.

            k, v = data.first

            case k

            when "@eval"
                %x"#{expand(v)}".split("\n")

            when "@env"
                ENV[expand(v)]

            when "@join"
                flatten( v[1..-1].map{|i| expand( i )} ).join( v[0] )

            when "@flat"
                flatten( v[1..-1].map{|i| expand( i )} )

            when "@self"
                reference( @ext_data, expand(v) )

            when "@over";
                override( @cur_data[0], expand(v), true )
                nil

            when "@base";
                override( @cur_data[0], expand(v), false )
                nil

            when "@null"
                nil

            when "@include";
                jsonfile = expand(v)
                subdata = read_json_file( jsonfile )
                expdata = expand( subdata )
                if expdata.class == Hash
                    if @cur_data[0].class == expdata.class
                        expdata.each do |ke,ve|
                            @cur_data[0][ ke ] = ve
                        end
                    else
                        raise XjsonIncludeError,
                        "Included file (\"#{jsonfile}\") must contain a hash as top level"
                    end
                elsif expdata.class == Array
                    expdata.each do |ve|
                        @cur_data[0].push ve
                    end
                else
                    raise XjsonIncludeError,
                    "Included file (\"#{jsonfile}\") must contain a hash or a an array as top level"
                end
                @cur_file.shift
                nil

            else
                # Non-extension.
                { k => expand( v ) }

            end

        else
            ret = {}
            @cur_data.unshift ret
            data.each do |k,v|
                case k
                when "@null"; nil
                else
                    value = expand( v )
                    ret[ k ] = value if value
                end
            end
            @cur_data.shift
            ret
        end
    end
end

#find_in_array_of_hash(scope, key, value) ⇒ Object



57
58
59
60
61
62
63
64
65
66
# File 'lib/xjson.rb', line 57

def find_in_array_of_hash( scope, key, value )
    index = 0
    while index < scope.length
        if Regexp.new( value).match( scope[ index ][ key ] )
            return index
        end
        index += 1
    end
    nil
end

#flatten(data) ⇒ Object

Flatten by one level within array.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/xjson.rb', line 40

def flatten( data )
    case data
    when Array;
        res = []
        data.each do |i|
            if i.class == Array
                res += i
            else
                res.push i
            end
        end
        res
    else
        data
    end
end

#override(data, exp, overwrite = false) ⇒ Object



146
147
148
149
# File 'lib/xjson.rb', line 146

def override( data, exp, overwrite = false )
    desc = override_desc( data, exp )
    override_apply( desc, overwrite )
end

#override_apply(desc, overwrite = false) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/xjson.rb', line 131

def override_apply( desc, overwrite = false )
    if desc[:label] == "*"
        desc[:path].each do |place|
            if not( place[ desc[:value][0] ] ) || overwrite
                place[ desc[:value][0] ] = desc[:value][1]
            end
        end
    else
        if not( desc[:path][desc[:label]] ) || overwrite
            desc[:path][desc[:label]] = desc[:value]
        end
    end
end

#override_desc(data, exp) ⇒ Object



125
126
127
128
# File 'lib/xjson.rb', line 125

def override_desc( data, exp )
    path, label = reference_handle( data, exp[0] )
    { path: path, label: label, value: exp[1] }
end

#read_json_file(xjson_file) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/xjson.rb', line 30

def read_json_file( xjson_file )
    @cur_file.unshift xjson_file
    if xjson_file[0] != "<"
        JSON.parse( File.read( xjson_file ) )
    else
        JSON.parse( STDIN.read )
    end
end

#reference(data, ref_desc) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/xjson.rb', line 108

def reference( data, ref_desc )
    path, label = reference_handle( data, ref_desc )
    begin
        index = Integer( label )
        scope = path[ index ]
    rescue
        # scope = scope[ path[0] ]
        scope = path[ label ]
    end
    # scope = path[ label ]
    # if scope.class == String
        scope
    # else
    #     scope.to_s
    # end
end

#reference_handle(data, ref_desc) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/xjson.rb', line 68

def reference_handle( data, ref_desc )
    if ref_desc[0] != ":"
        # [ data, ref_desc ]
        reference_handle( data, ":#{ref_desc}" )
    else
        # Relative reference from root.
        path = ref_desc.split( ":" )[1..-1]
        scope = data
        while path[0..-2].any?
            if path[0] == "*"
                # Wildcard for array.
                unless path[1] && path[2]
                    raise XjsonReferenceError,
                    "Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\", missing match key and value ..."
                end
                index = find_in_array_of_hash( scope, path[1], path[2] )
                unless index
                    raise XjsonReferenceError,
                    "Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\", key and value not matched ..."
                end
                scope = scope[ index ]
                path.shift( 2 )
            else
                begin
                    index = Integer( path[0] )
                    scope = scope[ index ]
                rescue
                    scope = scope[ path[0] ]
                end
            end
            path.shift
            unless scope
                raise XjsonReferenceError,
                "Invalid reference: \"#{ref_desc}\" in \"#{@cur_file[0]}\"..."
            end
        end
        [ scope, path[-1] ]
    end
end

#to_sObject



260
261
262
# File 'lib/xjson.rb', line 260

def to_s
    JSON.pretty_generate( @data )
end