fxf 1.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.
- 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: []
|