fxf 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +190 -0
- data/lib/fxf.rb +467 -0
- metadata +45 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 70f8912e081de135c77935749f2b329a76f3db905f0c19fdac9aee2b3c1aef30
|
4
|
+
data.tar.gz: e92108b05650908867a92ee460e604bf4664ce3fc3f5e3e4132b70da6b112dce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0401c245c79b49771cabb9bf9d4e21b64fd375972aac13236dd9f0540bcecbe5a2a393588a6cd29336d3835a98afec46f6dc53da3f731a68952b532e00ddf0be
|
7
|
+
data.tar.gz: becc4252056063906a4e06815cb9c2c36f82b9f4fbfb23e623ad45e74d09ead403770e10344478aff39af007cb007d151eeb1df9fda32f7a7be8708ee878b9d7
|
data/README.md
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
# FXF
|
2
|
+
|
3
|
+
FXF is a JSON structure for serializing interconnected data. It also allows for
|
4
|
+
serialization of objects of arbitrary classes.
|
5
|
+
|
6
|
+
Native JSON only allows for hierarchical data. For example, the following
|
7
|
+
structure serializes to JSON quite nicely.
|
8
|
+
|
9
|
+
```text
|
10
|
+
hsh = {}
|
11
|
+
hsh['mary'] = {'name'=>'Mary'}
|
12
|
+
hsh['fred'] = {'name'=>'Fred'}
|
13
|
+
```
|
14
|
+
|
15
|
+
That produces JSON like this:
|
16
|
+
|
17
|
+
```text
|
18
|
+
{
|
19
|
+
"mary": {
|
20
|
+
"name": "Mary"
|
21
|
+
},
|
22
|
+
"fred": {
|
23
|
+
"name": "Fred"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
```
|
27
|
+
|
28
|
+
However, if you add interconnections to the data you start getting repeated data
|
29
|
+
in the JSON. For example, consider this structure in which the hash for Mary
|
30
|
+
includes a reference to the hash for Fred.
|
31
|
+
|
32
|
+
```text
|
33
|
+
hsh = {}
|
34
|
+
hsh['mary'] = {'name'=>'Mary'}
|
35
|
+
hsh['fred'] = {'name'=>'Fred'}
|
36
|
+
hsh['mary']['friend'] = hsh['fred']
|
37
|
+
```
|
38
|
+
|
39
|
+
In that case you get this structure with redundant information:
|
40
|
+
|
41
|
+
```text
|
42
|
+
{
|
43
|
+
"mary": {
|
44
|
+
"name": "Mary",
|
45
|
+
"friend": {
|
46
|
+
"name": "Fred"
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"fred": {
|
50
|
+
"name": "Fred"
|
51
|
+
}
|
52
|
+
}
|
53
|
+
```
|
54
|
+
|
55
|
+
The situation gets worse if data references itself. For example, if the JSON
|
56
|
+
module tries to implement this structure, an error results.
|
57
|
+
|
58
|
+
```text
|
59
|
+
hsh = {}
|
60
|
+
hsh['mary'] = {'name'=>'Mary'}
|
61
|
+
hsh['fred'] = {'name'=>'Fred'}
|
62
|
+
hsh['mary']['self'] = hsh['mary']
|
63
|
+
```
|
64
|
+
|
65
|
+
That gives us this nesting error:
|
66
|
+
|
67
|
+
```text
|
68
|
+
Traceback (most recent call last):
|
69
|
+
2: from ./json.rb:39:in `<main>'
|
70
|
+
1: from /usr/lib/ruby/2.5.0/json/common.rb:286:in `pretty_generate'
|
71
|
+
/usr/lib/ruby/2.5.0/json/common.rb:286:in `generate': nesting of 100 is too deep (JSON::NestingError)
|
72
|
+
```
|
73
|
+
|
74
|
+
FXF preserves the original structure of the object without any difficulties with
|
75
|
+
redundant or self-nested objects. To generate an FXF string, simply call
|
76
|
+
FXF.generate. In these examples we add `'pretty'=>true` for readability.
|
77
|
+
|
78
|
+
```text
|
79
|
+
fxf = FXF.generate(hsh, 'pretty'=>true)
|
80
|
+
```
|
81
|
+
|
82
|
+
So the structure from the previous example would be serialized with this
|
83
|
+
(admittedly not very human readable) JSON structure:
|
84
|
+
|
85
|
+
```text
|
86
|
+
{
|
87
|
+
"root": "47283390982220",
|
88
|
+
"objects": {
|
89
|
+
"47283390982220": {
|
90
|
+
"mary": "47283390982160",
|
91
|
+
"fred": "47283390982120"
|
92
|
+
},
|
93
|
+
"47283390982160": {
|
94
|
+
"name": "47283390982180",
|
95
|
+
"self": "47283390982160"
|
96
|
+
},
|
97
|
+
"47283390982180": "Mary",
|
98
|
+
"47283390982120": {
|
99
|
+
"name": "47283390982140"
|
100
|
+
},
|
101
|
+
"47283390982140": "Fred"
|
102
|
+
}
|
103
|
+
}
|
104
|
+
```
|
105
|
+
|
106
|
+
To parse that string back into a structure, use `FXF.parse`.
|
107
|
+
|
108
|
+
```text
|
109
|
+
parsed = FXF.parse(fxf)
|
110
|
+
```
|
111
|
+
|
112
|
+
The resulting parsed data has the same structure as the original.
|
113
|
+
|
114
|
+
```text
|
115
|
+
puts parsed['mary'] == parsed['mary']['self'] # true
|
116
|
+
```
|
117
|
+
|
118
|
+
## Custom classes
|
119
|
+
|
120
|
+
FXF can serialize data so that the class of the object is preserved. Classes
|
121
|
+
must be defined in such a way that their objects can be exported to FXF format,
|
122
|
+
then imported again from that format. Doing so requires implementing the
|
123
|
+
instance method `to_fxf` and the class method `from_fxf`. Consider this class.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
class MyClass
|
127
|
+
attr_reader :pk
|
128
|
+
|
129
|
+
def initialize(pk)
|
130
|
+
@pk = pk
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_fxf
|
134
|
+
return {'pk'=>@pk}
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.from_fxf(details)
|
138
|
+
return self.new(details['pk'])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
The `to_fxf` method returns a hash with information necessary to recreate the
|
144
|
+
object. In this case just the `pk` property is required.
|
145
|
+
|
146
|
+
When the object is deserialized, that information is passed to the class'
|
147
|
+
`from_fxf` method. Note that that is a method of the class itself, so it needs
|
148
|
+
to be defined with `self.from_fxf`. The method is given a hash of the same
|
149
|
+
information that was exported from `to_fxf`. In this case, `from_fxf` uses that
|
150
|
+
hash to create a new `MyClass` object using the primary key.
|
151
|
+
|
152
|
+
## Standard classes
|
153
|
+
|
154
|
+
FXF can export two standard classes without the need for any additional
|
155
|
+
modifications to them: DateTime and URI::HTTPS. More common classes will be
|
156
|
+
added as FXF is developed.
|
157
|
+
|
158
|
+
In this example, we create a `DateTime` object and a `URI::HTTPS` object.
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
hsh = {}
|
162
|
+
hsh['timestamp'] = DateTime.parse('Jan 5, 2017, 7:18 am')
|
163
|
+
hsh['uri'] = URI('https://www.example.com')
|
164
|
+
fxf = FXF.generate(hsh, 'pretty'=>true)
|
165
|
+
```
|
166
|
+
|
167
|
+
Identical objects are created when the FXF string is parsed.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
parsed = FXF.parse(fxf)
|
171
|
+
puts parsed['timestamp'].class # DateTime
|
172
|
+
puts parsed['uri'].class # URI::HTTPS
|
173
|
+
```
|
174
|
+
|
175
|
+
## Install
|
176
|
+
|
177
|
+
```
|
178
|
+
gem install fxf
|
179
|
+
```
|
180
|
+
|
181
|
+
## Author
|
182
|
+
|
183
|
+
Mike O'Sullivan
|
184
|
+
mike@idocs.com
|
185
|
+
|
186
|
+
## History
|
187
|
+
|
188
|
+
| version | date | notes |
|
189
|
+
|---------|--------------|-------------------------------|
|
190
|
+
| 1.0 | Jan 27, 2020 | Initial upload. |
|
data/lib/fxf.rb
ADDED
@@ -0,0 +1,467 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
|
4
|
+
#===============================================================================
|
5
|
+
# FXF
|
6
|
+
#
|
7
|
+
module FXF
|
8
|
+
# version 1.0
|
9
|
+
VERSION = '1.0'
|
10
|
+
|
11
|
+
#---------------------------------------------------------------------------
|
12
|
+
# generate
|
13
|
+
#
|
14
|
+
|
15
|
+
# Generates a FXF JSON string.
|
16
|
+
|
17
|
+
def self.generate(struct, opts={})
|
18
|
+
# $tm.hrm
|
19
|
+
rv = {}
|
20
|
+
self.generate_object(rv, struct)
|
21
|
+
rv = {'root'=>rv.keys[0], 'objects'=>rv}
|
22
|
+
|
23
|
+
# return JSON
|
24
|
+
if opts['pretty']
|
25
|
+
return JSON.pretty_generate(rv)
|
26
|
+
else
|
27
|
+
return JSON.generate(rv)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
#
|
31
|
+
# generate
|
32
|
+
#---------------------------------------------------------------------------
|
33
|
+
|
34
|
+
|
35
|
+
#---------------------------------------------------------------------------
|
36
|
+
# parse
|
37
|
+
#
|
38
|
+
|
39
|
+
# Parses an FXF string and returns the structure it defines.
|
40
|
+
|
41
|
+
def self.parse(fxf)
|
42
|
+
parser = FXF::Parser.new(fxf)
|
43
|
+
return parser.parse()
|
44
|
+
end
|
45
|
+
#
|
46
|
+
# parse
|
47
|
+
#---------------------------------------------------------------------------
|
48
|
+
|
49
|
+
|
50
|
+
# private
|
51
|
+
private
|
52
|
+
|
53
|
+
|
54
|
+
#---------------------------------------------------------------------------
|
55
|
+
# generate_object
|
56
|
+
#
|
57
|
+
|
58
|
+
# Scalar object types. These are all the data types in JSON except for
|
59
|
+
# hashes and arrays.
|
60
|
+
SCALARS = [String, Integer, Float, TrueClass, FalseClass, NilClass]
|
61
|
+
|
62
|
+
def self.generate_object(rv, obj)
|
63
|
+
# $tm.hrm
|
64
|
+
key = obj.object_id.to_s
|
65
|
+
|
66
|
+
# add to rv
|
67
|
+
if not rv.has_key?(key)
|
68
|
+
# scalar
|
69
|
+
if SCALARS.include?(obj.class)
|
70
|
+
rv[key] = obj
|
71
|
+
|
72
|
+
# hash
|
73
|
+
elsif obj.is_a?(Hash)
|
74
|
+
hsh = rv[key] = {}
|
75
|
+
|
76
|
+
obj.each do |k, v|
|
77
|
+
hsh[k] = self.generate_object(rv, v)
|
78
|
+
end
|
79
|
+
|
80
|
+
# array
|
81
|
+
elsif obj.is_a?(Array)
|
82
|
+
arr = rv[key] = []
|
83
|
+
|
84
|
+
obj.each do |v|
|
85
|
+
arr.push self.generate_object(rv, v)
|
86
|
+
end
|
87
|
+
|
88
|
+
# to_fxf
|
89
|
+
elsif obj.respond_to?('to_fxf')
|
90
|
+
dfn = {}
|
91
|
+
dfn['class'] = obj.class.to_s
|
92
|
+
dfn['details'] = obj.to_fxf()
|
93
|
+
object_dfn rv, key, 'custom', dfn
|
94
|
+
|
95
|
+
# standard class
|
96
|
+
elsif translator = FXF::Standard::TO_FXF[obj.class.to_s]
|
97
|
+
dfn = translator.call(obj)
|
98
|
+
object_dfn rv, key, 'standard', dfn
|
99
|
+
|
100
|
+
# else unknown class
|
101
|
+
else
|
102
|
+
# build details
|
103
|
+
details = {}
|
104
|
+
|
105
|
+
# string
|
106
|
+
if obj.respond_to?('to_s')
|
107
|
+
details['str'] = obj.to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
# buid definition
|
111
|
+
dfn = {}
|
112
|
+
dfn['scope'] = 'unrecognized'
|
113
|
+
dfn['class'] = obj.class.to_s
|
114
|
+
dfn['details'] = details
|
115
|
+
|
116
|
+
# store
|
117
|
+
rv[key] = [dfn]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# return
|
122
|
+
return key
|
123
|
+
end
|
124
|
+
#
|
125
|
+
# generate_object
|
126
|
+
#---------------------------------------------------------------------------
|
127
|
+
|
128
|
+
|
129
|
+
#---------------------------------------------------------------------------
|
130
|
+
# object_dfn
|
131
|
+
#
|
132
|
+
def self.object_dfn(rv, key, scope, dfn)
|
133
|
+
# $tm.hrm
|
134
|
+
export = {}
|
135
|
+
rv[key] = [export]
|
136
|
+
export['scope'] = scope
|
137
|
+
export['class'] = dfn['class']
|
138
|
+
export['details'] = {}
|
139
|
+
|
140
|
+
# add object references
|
141
|
+
if dfn['details']
|
142
|
+
if dfn['details'].is_a?(Hash)
|
143
|
+
dfn['details'].each do |k, v|
|
144
|
+
export['details'][k] = self.generate_object(rv, v)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
raise 'custom-object-details-must-be-hash'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
#
|
152
|
+
# object_dfn
|
153
|
+
#---------------------------------------------------------------------------
|
154
|
+
end
|
155
|
+
#
|
156
|
+
# FXF
|
157
|
+
#===============================================================================
|
158
|
+
|
159
|
+
|
160
|
+
#===============================================================================
|
161
|
+
# FXF::Standard
|
162
|
+
#
|
163
|
+
|
164
|
+
# This module defines procs for serializing and deserializing DateTime and
|
165
|
+
# URI::HTTPS objects.
|
166
|
+
|
167
|
+
module FXF::Standard
|
168
|
+
TO_FXF = {}
|
169
|
+
FROM_FXF = {}
|
170
|
+
|
171
|
+
#---------------------------------------------------------------------------
|
172
|
+
# DateTime
|
173
|
+
#
|
174
|
+
TO_FXF['DateTime'] = proc do |obj|
|
175
|
+
dfn = {}
|
176
|
+
dfn['class'] = 'datetime'
|
177
|
+
dfn['details'] = {'str'=>obj.to_s}
|
178
|
+
dfn
|
179
|
+
end
|
180
|
+
|
181
|
+
FROM_FXF['datetime'] = proc do |dfn|
|
182
|
+
# $tm.hrm
|
183
|
+
DateTime.parse(dfn.details['str'])
|
184
|
+
end
|
185
|
+
#
|
186
|
+
# DateTime
|
187
|
+
#---------------------------------------------------------------------------
|
188
|
+
|
189
|
+
|
190
|
+
#---------------------------------------------------------------------------
|
191
|
+
# URI
|
192
|
+
#
|
193
|
+
TO_FXF['URI::HTTPS'] = proc do |obj|
|
194
|
+
dfn = {}
|
195
|
+
dfn['class'] = 'uri'
|
196
|
+
dfn['details'] = {'str'=>obj.to_s}
|
197
|
+
dfn
|
198
|
+
end
|
199
|
+
|
200
|
+
FROM_FXF['uri'] = proc do |dfn|
|
201
|
+
URI(dfn.details['str'])
|
202
|
+
end
|
203
|
+
#
|
204
|
+
# URI
|
205
|
+
#---------------------------------------------------------------------------
|
206
|
+
end
|
207
|
+
#
|
208
|
+
# FXF::Standard
|
209
|
+
#===============================================================================
|
210
|
+
|
211
|
+
|
212
|
+
#===============================================================================
|
213
|
+
# FXF::Parser
|
214
|
+
#
|
215
|
+
|
216
|
+
# `FXF::Parser` isn't intended to be used directly. FXF.parse creates a
|
217
|
+
# `FXF::Parser` and calls its `parse` method.
|
218
|
+
|
219
|
+
class FXF::Parser
|
220
|
+
#---------------------------------------------------------------------------
|
221
|
+
# initialize
|
222
|
+
#
|
223
|
+
def initialize(raw)
|
224
|
+
@raw = raw
|
225
|
+
end
|
226
|
+
#
|
227
|
+
# initialize
|
228
|
+
#---------------------------------------------------------------------------
|
229
|
+
|
230
|
+
|
231
|
+
#---------------------------------------------------------------------------
|
232
|
+
# parse
|
233
|
+
#
|
234
|
+
def parse()
|
235
|
+
@full = JSON.parse(@raw)
|
236
|
+
@org = @full['objects']
|
237
|
+
@found = {}
|
238
|
+
@collections = []
|
239
|
+
rv = self.build_object(@full['root'])
|
240
|
+
|
241
|
+
# look for object place holders
|
242
|
+
placeholder_mod()
|
243
|
+
|
244
|
+
# return
|
245
|
+
return rv
|
246
|
+
end
|
247
|
+
#
|
248
|
+
# parse
|
249
|
+
#---------------------------------------------------------------------------
|
250
|
+
|
251
|
+
|
252
|
+
#---------------------------------------------------------------------------
|
253
|
+
# placeholder_mod
|
254
|
+
#
|
255
|
+
def placeholder_mod
|
256
|
+
# $tm.hrm
|
257
|
+
placeholders = []
|
258
|
+
phs_to_obj = {}
|
259
|
+
|
260
|
+
# build unique list of placeholders
|
261
|
+
@collections.each do |collection|
|
262
|
+
if collection.is_a?(Array)
|
263
|
+
collection.each do |el|
|
264
|
+
placeholder_add placeholders, el
|
265
|
+
end
|
266
|
+
elsif collection.is_a?(Hash)
|
267
|
+
collection.values.each do |el|
|
268
|
+
placeholder_add placeholders, el
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# build a hash of placeholders to objects
|
274
|
+
placeholders.each do |ph|
|
275
|
+
# standard
|
276
|
+
if ph.scope == 'standard'
|
277
|
+
if translator = FXF::Standard::FROM_FXF[ph.clss]
|
278
|
+
phs_to_obj[ph] = translator.call(ph)
|
279
|
+
else
|
280
|
+
raise 'do-not-have-standard-translator: ' + ph.clss
|
281
|
+
end
|
282
|
+
|
283
|
+
# custom
|
284
|
+
elsif ph.scope == 'custom'
|
285
|
+
if Module.const_defined?(ph.clss)
|
286
|
+
clss = Module.const_get(ph.clss)
|
287
|
+
|
288
|
+
if clss.respond_to?('from_fxf')
|
289
|
+
phs_to_obj[ph] = clss.from_fxf(ph.details)
|
290
|
+
else
|
291
|
+
raise 'class-does-not-have-from-fxf: ' + ph.clss
|
292
|
+
end
|
293
|
+
else
|
294
|
+
raise 'unknown-custom-class: ' + ph.clss
|
295
|
+
end
|
296
|
+
|
297
|
+
# else don't know how to build this object
|
298
|
+
else
|
299
|
+
phs_to_obj[ph] = ph
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# substitute placeholders to objects
|
304
|
+
@collections.each do |collection|
|
305
|
+
if collection.is_a?(Array)
|
306
|
+
collection.map! do |el|
|
307
|
+
rv = nil
|
308
|
+
|
309
|
+
if phs_to_obj.has_key?(el)
|
310
|
+
rv = phs_to_obj[el]
|
311
|
+
else
|
312
|
+
rv = el
|
313
|
+
end
|
314
|
+
|
315
|
+
rv
|
316
|
+
end
|
317
|
+
|
318
|
+
elsif collection.is_a?(Hash)
|
319
|
+
collection.each do |k, v|
|
320
|
+
if phs_to_obj.has_key?(v)
|
321
|
+
collection[k] = phs_to_obj[v]
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
#
|
328
|
+
# placeholder_mod
|
329
|
+
#---------------------------------------------------------------------------
|
330
|
+
|
331
|
+
|
332
|
+
#---------------------------------------------------------------------------
|
333
|
+
# placeholder_add
|
334
|
+
#
|
335
|
+
def placeholder_add(placeholders, el)
|
336
|
+
# $tm.hrm
|
337
|
+
|
338
|
+
# if placeholder, and not in placeholders array, add to array
|
339
|
+
if el.is_a?(FXF::Parser::ObjectHolder) and (not placeholders.include?(el))
|
340
|
+
placeholders.push el
|
341
|
+
end
|
342
|
+
end
|
343
|
+
#
|
344
|
+
# placeholder_add
|
345
|
+
#---------------------------------------------------------------------------
|
346
|
+
|
347
|
+
|
348
|
+
#---------------------------------------------------------------------------
|
349
|
+
# build_object
|
350
|
+
#
|
351
|
+
def build_object(key)
|
352
|
+
# $tm.hrm
|
353
|
+
rv = nil
|
354
|
+
|
355
|
+
# if already found
|
356
|
+
if @found.has_key?(key)
|
357
|
+
return @found[key]
|
358
|
+
end
|
359
|
+
|
360
|
+
# get object definition
|
361
|
+
dfn = @org.delete(key)
|
362
|
+
|
363
|
+
# scalar
|
364
|
+
if FXF::SCALARS.include?(dfn.class)
|
365
|
+
@found[key] = dfn
|
366
|
+
return dfn
|
367
|
+
|
368
|
+
# array
|
369
|
+
elsif dfn.is_a?(Array)
|
370
|
+
# if object description
|
371
|
+
if dfn[0].is_a?(Hash)
|
372
|
+
details = {}
|
373
|
+
build_hash(dfn[0]['details'], details)
|
374
|
+
dfn = FXF::Parser::ObjectHolder.new dfn[0]['scope'], dfn[0]['class'], details
|
375
|
+
@found[key] = dfn
|
376
|
+
return dfn
|
377
|
+
else
|
378
|
+
@found[key] = []
|
379
|
+
@collections.push @found[key]
|
380
|
+
return build_array(dfn, @found[key])
|
381
|
+
end
|
382
|
+
|
383
|
+
# hash
|
384
|
+
elsif dfn.is_a?(Hash)
|
385
|
+
@found[key] = {}
|
386
|
+
@collections.push @found[key]
|
387
|
+
return build_hash(dfn, @found[key])
|
388
|
+
|
389
|
+
# else unknown
|
390
|
+
else
|
391
|
+
puts 'unknown: ' + dfn.class.to_s
|
392
|
+
exit
|
393
|
+
end
|
394
|
+
|
395
|
+
# return
|
396
|
+
return rv
|
397
|
+
end
|
398
|
+
#
|
399
|
+
# build_object
|
400
|
+
#---------------------------------------------------------------------------
|
401
|
+
|
402
|
+
|
403
|
+
#---------------------------------------------------------------------------
|
404
|
+
# build_hash
|
405
|
+
#
|
406
|
+
def build_hash(dfn, hsh)
|
407
|
+
# loop through elements
|
408
|
+
dfn.each do |key, ref|
|
409
|
+
hsh[key] = build_object(ref)
|
410
|
+
end
|
411
|
+
|
412
|
+
# return
|
413
|
+
return hsh
|
414
|
+
end
|
415
|
+
#
|
416
|
+
# build_hash
|
417
|
+
#---------------------------------------------------------------------------
|
418
|
+
|
419
|
+
|
420
|
+
#---------------------------------------------------------------------------
|
421
|
+
# build_array
|
422
|
+
#
|
423
|
+
def build_array(dfn, arr)
|
424
|
+
# loop through elements
|
425
|
+
dfn.each do |ref|
|
426
|
+
arr.push build_object(ref)
|
427
|
+
end
|
428
|
+
|
429
|
+
# return
|
430
|
+
return arr
|
431
|
+
end
|
432
|
+
#
|
433
|
+
# build_array
|
434
|
+
#---------------------------------------------------------------------------
|
435
|
+
end
|
436
|
+
#
|
437
|
+
# FXF::Parser
|
438
|
+
#===============================================================================
|
439
|
+
|
440
|
+
|
441
|
+
#===============================================================================
|
442
|
+
# FXF::Parser::ObjectHolder
|
443
|
+
#
|
444
|
+
|
445
|
+
# Objects of this class are placeholders for objects that have been serialized.
|
446
|
+
# This class is used by FXF::Parser and is not meant to be used directly.
|
447
|
+
|
448
|
+
class FXF::Parser::ObjectHolder
|
449
|
+
attr_reader :scope
|
450
|
+
attr_reader :clss
|
451
|
+
attr_reader :details
|
452
|
+
|
453
|
+
#---------------------------------------------------------------------------
|
454
|
+
# initialize
|
455
|
+
#
|
456
|
+
def initialize(scope, clss, details)
|
457
|
+
@scope = scope
|
458
|
+
@clss = clss
|
459
|
+
@details = details
|
460
|
+
end
|
461
|
+
#
|
462
|
+
# initialize
|
463
|
+
#---------------------------------------------------------------------------
|
464
|
+
end
|
465
|
+
#
|
466
|
+
# FXF::Parser::ObjectHolder
|
467
|
+
#===============================================================================
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fxf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike O'Sullivan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A JSON implementation for non-hierarchical data and for arbitrary objects
|
14
|
+
email: mike@idocs.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- lib/fxf.rb
|
21
|
+
homepage: https://rubygems.org/gems/fxf
|
22
|
+
licenses:
|
23
|
+
- MIT
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubyforge_project:
|
41
|
+
rubygems_version: 2.7.6
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: Serializer for tangled data and objects
|
45
|
+
test_files: []
|