dynarex 1.8.26 → 1.9.2
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/dynarex.rb +355 -328
- data.tar.gz.sig +0 -0
- metadata +43 -42
- metadata.gz.sig +0 -0
data/lib/dynarex.rb
CHANGED
@@ -30,7 +30,7 @@ hkey_gems
|
|
30
30
|
require dynarex
|
31
31
|
class Dynarex
|
32
32
|
media_type dynarex
|
33
|
-
'
|
33
|
+
'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -39,35 +39,35 @@ class DynarexException < Exception
|
|
39
39
|
end
|
40
40
|
|
41
41
|
class DynarexRecordset < Array
|
42
|
-
|
42
|
+
|
43
43
|
def initialize(a, caller=nil)
|
44
44
|
super(a)
|
45
45
|
@caller = caller
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def reject!()
|
49
|
-
|
49
|
+
|
50
50
|
a = self.to_a.clone
|
51
51
|
a2 = super
|
52
52
|
return nil unless a2
|
53
53
|
a3 = a - a2
|
54
|
-
|
54
|
+
|
55
55
|
@caller.delete a3.map(&:id)
|
56
56
|
self
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def sum(field)
|
60
60
|
self.inject(0) {|r, x| r + x[field.to_sym][/\d+(\.\d+)?$/].to_f }
|
61
61
|
end
|
62
|
-
|
63
|
-
def index(val)
|
62
|
+
|
63
|
+
def index(val)
|
64
64
|
self.map(&:to_h).index val.to_h
|
65
65
|
end
|
66
|
-
|
67
|
-
def index_by_id(id)
|
66
|
+
|
67
|
+
def index_by_id(id)
|
68
68
|
self.map(&:id).index id
|
69
|
-
end
|
70
|
-
|
69
|
+
end
|
70
|
+
|
71
71
|
end
|
72
72
|
|
73
73
|
|
@@ -77,8 +77,8 @@ class Dynarex
|
|
77
77
|
|
78
78
|
attr_accessor :format_mask, :delimiter, :xslt_schema, :schema, :linked,
|
79
79
|
:order, :type, :limit, :xslt, :json_out, :unique
|
80
|
-
|
81
|
-
|
80
|
+
|
81
|
+
|
82
82
|
#Create a new dynarex document from 1 of the following options:
|
83
83
|
#* a local file path
|
84
84
|
#* a URL
|
@@ -87,18 +87,18 @@ class Dynarex
|
|
87
87
|
#* an XML string
|
88
88
|
# Dynarex.new '<contacts><summary><schema>contacts/contact(name,age,dob)</schema></summary><records/></contacts>'
|
89
89
|
|
90
|
-
def initialize(rawx=nil, username: nil, password: nil, schema: nil,
|
91
|
-
default_key: nil, json_out: true, debug: false,
|
92
|
-
delimiter: ' # ', autosave: false, order: 'ascending',
|
90
|
+
def initialize(rawx=nil, username: nil, password: nil, schema: nil,
|
91
|
+
default_key: nil, json_out: true, debug: false,
|
92
|
+
delimiter: ' # ', autosave: false, order: 'ascending',
|
93
93
|
unique: false, filepath: nil)
|
94
94
|
|
95
95
|
|
96
96
|
puts 'inside Dynarex::initialize' if debug
|
97
|
-
@username, @password, @schema,
|
98
|
-
|
97
|
+
@username, @password, @schema, = username, password, schema
|
98
|
+
@default_key, @json_out, @debug = default_key, json_out, debug
|
99
99
|
@autosave, @unique = autosave, unique
|
100
100
|
@local_filepath = filepath
|
101
|
-
|
101
|
+
|
102
102
|
puts ('@debug: ' + @debug.inspect).debug if debug
|
103
103
|
@delimiter = delimiter
|
104
104
|
@spaces_delimited = false
|
@@ -108,12 +108,12 @@ class Dynarex
|
|
108
108
|
rawx ||= schema if schema
|
109
109
|
|
110
110
|
if rawx then
|
111
|
-
|
111
|
+
|
112
112
|
return import(rawx) if rawx =~ /\.txt$/
|
113
|
-
openx(rawx.clone)
|
114
|
-
|
113
|
+
openx(rawx.clone)
|
114
|
+
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
self.order = @order unless @order.to_sym == :ascending
|
118
118
|
|
119
119
|
end
|
@@ -125,17 +125,17 @@ class Dynarex
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def all()
|
128
|
-
|
128
|
+
|
129
129
|
refresh! if @dirty_flag
|
130
130
|
a = @doc.root.xpath("records/*").map {|x| recordx_to_record x}
|
131
131
|
DynarexRecordset.new(a, self)
|
132
|
-
|
132
|
+
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
def clone()
|
136
136
|
Dynarex.new(self.to_xml)
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
def default_key()
|
140
140
|
self.summary[:default_key]
|
141
141
|
end
|
@@ -146,10 +146,10 @@ class Dynarex
|
|
146
146
|
@spaces_delimited = true
|
147
147
|
separator = ' # '
|
148
148
|
end
|
149
|
-
|
149
|
+
|
150
150
|
@delimiter = separator
|
151
151
|
|
152
|
-
if separator.length > 0 then
|
152
|
+
if separator.length > 0 then
|
153
153
|
@summary[:delimiter] = separator
|
154
154
|
else
|
155
155
|
@summary.delete :delimiter
|
@@ -158,14 +158,14 @@ class Dynarex
|
|
158
158
|
@format_mask = @format_mask.to_s.gsub(/\s/, separator)
|
159
159
|
@summary[:format_mask] = @format_mask
|
160
160
|
end
|
161
|
-
|
161
|
+
|
162
162
|
def doc
|
163
163
|
(load_records; rebuild_doc) if @dirty_flag == true
|
164
164
|
@doc
|
165
|
-
end
|
165
|
+
end
|
166
166
|
|
167
167
|
# XML import
|
168
|
-
#
|
168
|
+
#
|
169
169
|
def foreign_import(options={})
|
170
170
|
o = {xml: '', schema: ''}.merge(options)
|
171
171
|
h = {xml: o[:xml], schema: @schema, foreign_schema: o[:schema]}
|
@@ -174,21 +174,21 @@ class Dynarex
|
|
174
174
|
openx(buffer)
|
175
175
|
self
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
def fields
|
179
179
|
@fields
|
180
180
|
end
|
181
|
-
|
181
|
+
|
182
182
|
def first
|
183
183
|
r = @doc.root.element("records/*")
|
184
|
-
r ? recordx_to_record(r) : nil
|
184
|
+
r ? recordx_to_record(r) : nil
|
185
185
|
end
|
186
186
|
|
187
187
|
def format_mask=(s)
|
188
188
|
@format_mask = s
|
189
189
|
@summary[:format_mask] = @format_mask
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
def insert(raw_params)
|
193
193
|
record = make_record(raw_params)
|
194
194
|
@doc.root.element('records/*').insert_before record
|
@@ -198,32 +198,32 @@ class Dynarex
|
|
198
198
|
def inspect()
|
199
199
|
"<object #%s>" % [self.object_id]
|
200
200
|
end
|
201
|
-
|
201
|
+
|
202
202
|
def linked=(bool)
|
203
203
|
@linked = bool == 'true'
|
204
204
|
end
|
205
|
-
|
205
|
+
|
206
206
|
def order=(value)
|
207
|
-
|
208
|
-
self.summary.merge!({order: value.to_s})
|
207
|
+
|
208
|
+
self.summary.merge!({order: value.to_s})
|
209
209
|
|
210
210
|
@order = value.to_s
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
def recordx_type()
|
214
214
|
@summary[:recordx_type]
|
215
215
|
end
|
216
|
-
|
216
|
+
|
217
217
|
def schema=(s)
|
218
218
|
openx s
|
219
219
|
end
|
220
|
-
|
220
|
+
|
221
221
|
def type=(v)
|
222
222
|
@order = 'descending' if v == 'feed'
|
223
223
|
@type = v
|
224
224
|
@summary[:type] = v
|
225
225
|
end
|
226
|
-
|
226
|
+
|
227
227
|
# Returns the hash representation of the document summary.
|
228
228
|
#
|
229
229
|
def summary
|
@@ -233,29 +233,29 @@ class Dynarex
|
|
233
233
|
# Return a Hash (which can be edited) containing all records.
|
234
234
|
#
|
235
235
|
def records
|
236
|
-
|
236
|
+
|
237
237
|
load_records if @dirty_flag == true
|
238
|
-
|
238
|
+
|
239
239
|
if block_given? then
|
240
240
|
yield(@records)
|
241
241
|
rebuild_doc
|
242
|
-
@dirty_flag = true
|
242
|
+
@dirty_flag = true
|
243
243
|
else
|
244
244
|
@records
|
245
245
|
end
|
246
|
-
|
246
|
+
|
247
247
|
end
|
248
|
-
|
249
|
-
# Returns a ready-only snapshot of records as a simple Hash.
|
248
|
+
|
249
|
+
# Returns a ready-only snapshot of records as a simple Hash.
|
250
250
|
#
|
251
251
|
def flat_records(select: nil)
|
252
|
-
|
252
|
+
|
253
253
|
fields = select
|
254
|
-
|
254
|
+
|
255
255
|
load_records if @dirty_flag == true
|
256
256
|
|
257
257
|
if fields then
|
258
|
-
|
258
|
+
|
259
259
|
case fields.class.to_s.downcase.to_sym
|
260
260
|
when :string
|
261
261
|
field = fields.to_sym
|
@@ -267,58 +267,58 @@ class Dynarex
|
|
267
267
|
@flat_records.map {|row| fields.inject({})\
|
268
268
|
{|r,x| r.merge(x.to_sym => row[x.to_sym])}}
|
269
269
|
end
|
270
|
-
|
270
|
+
|
271
271
|
else
|
272
272
|
@flat_records
|
273
273
|
end
|
274
|
-
|
274
|
+
|
275
275
|
end
|
276
|
-
|
276
|
+
|
277
277
|
alias to_a flat_records
|
278
|
-
|
278
|
+
|
279
279
|
# Returns an array snapshot of OpenStruct records
|
280
280
|
#
|
281
281
|
def ro_records
|
282
282
|
flat_records.map {|record| OpenStruct.new record }
|
283
283
|
end
|
284
|
-
|
284
|
+
|
285
285
|
def rm(force: false)
|
286
|
-
|
286
|
+
|
287
287
|
if force or all.empty? then
|
288
288
|
FileX.rm @local_filepath if @local_filepath
|
289
289
|
'file ' + @local_filepath + ' deleted'
|
290
290
|
else
|
291
291
|
'unable to rm file: document not empty'
|
292
292
|
end
|
293
|
-
|
293
|
+
|
294
294
|
end
|
295
|
-
|
296
295
|
|
297
|
-
|
296
|
+
|
297
|
+
def to_doc
|
298
298
|
self.clone().doc
|
299
299
|
end
|
300
|
-
|
300
|
+
|
301
301
|
# Typically uses the 1st field as a key and the remaining fields as the value
|
302
302
|
#
|
303
303
|
def to_h()
|
304
|
-
|
304
|
+
|
305
305
|
key = self.default_key.to_sym
|
306
306
|
fields = self.fields() - [key]
|
307
307
|
puts 'fields: ' + fields.inspect if @debug
|
308
|
-
|
309
|
-
flat_records.inject({}) do |r, h|
|
310
|
-
|
308
|
+
|
309
|
+
flat_records.inject({}) do |r, h|
|
310
|
+
|
311
311
|
puts 'h: ' + h.inspect if @debug
|
312
|
-
|
312
|
+
|
313
313
|
value = if h.length == 2 then
|
314
314
|
h[fields[0]].to_s
|
315
315
|
else
|
316
|
-
fields.map {|x| h[x]}
|
316
|
+
fields.map {|x| h[x]}
|
317
317
|
end
|
318
|
-
|
318
|
+
|
319
319
|
r.merge(h[key] => value)
|
320
320
|
end
|
321
|
-
|
321
|
+
|
322
322
|
end
|
323
323
|
|
324
324
|
def to_html(domain: '')
|
@@ -327,32 +327,32 @@ class Dynarex
|
|
327
327
|
xsl_buffer = RXFHelper.read(domain + @xslt, h).first
|
328
328
|
Rexslt.new(xsl_buffer, self.to_doc).to_s
|
329
329
|
|
330
|
-
end
|
331
|
-
|
332
|
-
|
333
|
-
# to_json: pretty is set to true because although the file size is larger,
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
# to_json: pretty is set to true because although the file size is larger,
|
334
334
|
# the file can be load slightly quicker
|
335
|
-
|
335
|
+
|
336
336
|
def to_json(pretty: true)
|
337
|
-
|
337
|
+
|
338
338
|
records = self.to_a
|
339
339
|
summary = self.summary.to_h
|
340
|
-
|
340
|
+
|
341
341
|
root_name = schema()[/^\w+/]
|
342
342
|
record_name = schema()[/(?<=\/)[^\(]+/]
|
343
|
-
|
343
|
+
|
344
344
|
h = {
|
345
345
|
root_name.to_sym =>
|
346
346
|
{
|
347
347
|
summary: @summary,
|
348
|
-
records: @records.map {|_, h| {record_name.to_sym => h} }
|
348
|
+
records: @records.map {|_, h| {record_name.to_sym => h} }
|
349
349
|
}
|
350
350
|
}
|
351
|
-
|
351
|
+
|
352
352
|
pretty ? JSON.pretty_generate(h) : h.to_json
|
353
|
-
|
353
|
+
|
354
354
|
end
|
355
|
-
|
355
|
+
|
356
356
|
def to_s(header: true, delimiter: @delimiter)
|
357
357
|
|
358
358
|
xsl_buffer =<<EOF
|
@@ -373,22 +373,22 @@ EOF
|
|
373
373
|
|
374
374
|
raw_summary_fields = self.summary[:schema][/^\w+\[([^\]]+)\]/,1]
|
375
375
|
sumry = ''
|
376
|
-
|
376
|
+
|
377
377
|
if raw_summary_fields then
|
378
|
-
summary_fields = raw_summary_fields.split(',') # .map(&:to_sym)
|
378
|
+
summary_fields = raw_summary_fields.split(',') # .map(&:to_sym)
|
379
379
|
sumry = summary_fields.map {|x| x.strip!; x + ': ' + \
|
380
380
|
self.summary[x.to_sym].to_s}.join("\n") + "\n\n"
|
381
381
|
end
|
382
|
-
|
382
|
+
|
383
383
|
if @raw_header then
|
384
384
|
declaration = @raw_header
|
385
385
|
else
|
386
386
|
|
387
|
-
smry_fields = %i(schema)
|
387
|
+
smry_fields = %i(schema)
|
388
388
|
smry_fields << :order if self.summary[:order] == 'descending'
|
389
|
-
|
389
|
+
|
390
390
|
if delimiter.length > 0 then
|
391
|
-
smry_fields << :delimiter
|
391
|
+
smry_fields << :delimiter
|
392
392
|
else
|
393
393
|
smry_fields << :format_mask unless self.summary[:rawdoc_type] == 'rowx'
|
394
394
|
end
|
@@ -406,44 +406,44 @@ EOF
|
|
406
406
|
<xsl:text>\n</xsl:text>%s:<xsl:text> </xsl:text><xsl:value-of select='%s'/>
|
407
407
|
</xsl:if>" % ([field]*3)
|
408
408
|
end
|
409
|
-
|
409
|
+
|
410
410
|
puts ('a: ' + a.inspect).debug if @debug
|
411
411
|
|
412
|
-
xslt_format = a.join
|
412
|
+
xslt_format = a.join
|
413
413
|
|
414
414
|
xsl_buffer.sub!(/\[!regex_values\]/, xslt_format)
|
415
|
-
|
415
|
+
|
416
416
|
if @debug then
|
417
417
|
File.write '/tmp/foo.xsl', xsl_buffer
|
418
418
|
File.write '/tmp/foo.xml', @doc.xml
|
419
419
|
puts 'xsl_buffer: ' + xsl_buffer.inspect
|
420
420
|
end
|
421
|
-
|
421
|
+
|
422
422
|
out = Rexslt.new(xsl_buffer, @doc).to_s
|
423
|
-
|
423
|
+
|
424
424
|
docheader + "\n--+\n" + out
|
425
|
-
elsif self.summary[:rawdoc_type] == 'sectionx' then
|
426
|
-
|
425
|
+
elsif self.summary[:rawdoc_type] == 'sectionx' then
|
426
|
+
|
427
427
|
a = (self.fields - [:uid, 'uid']).map do |field|
|
428
428
|
"<xsl:if test=\"%s != ''\">
|
429
429
|
<xsl:text>\n</xsl:text><xsl:value-of select='%s'/>
|
430
430
|
</xsl:if>" % ([field]*2)
|
431
431
|
end
|
432
432
|
|
433
|
-
xslt_format = a.join
|
433
|
+
xslt_format = a.join
|
434
434
|
|
435
435
|
xsl_buffer.sub!(/\[!regex_values\]/, xslt_format)
|
436
436
|
puts 'xsl_buffer: ' + xsl_buffer.inspect if @debug
|
437
437
|
|
438
438
|
out = Rexslt.new(xsl_buffer, @doc).to_s
|
439
|
-
|
439
|
+
|
440
440
|
header ? docheader + "--#\n" + out : out
|
441
|
-
|
441
|
+
|
442
442
|
elsif self.delimiter.length > 0 then
|
443
|
-
|
443
|
+
|
444
444
|
tfo = TableFormatter.new border: false, wrap: false, \
|
445
445
|
divider: self.delimiter
|
446
|
-
tfo.source = self.to_a.map{|x| x.values}
|
446
|
+
tfo.source = self.to_a.map{|x| x.values}
|
447
447
|
docheader + tfo.display.strip
|
448
448
|
|
449
449
|
else
|
@@ -454,7 +454,7 @@ EOF
|
|
454
454
|
s1, s2 = '<xsl:text>', '</xsl:text>'
|
455
455
|
xslt_format = s1 + format_mask\
|
456
456
|
.gsub(/(?:\[!(\w+)\])/, s2 + '<xsl:value-of select="\1"/>' + s1) + s2
|
457
|
-
|
457
|
+
|
458
458
|
xsl_buffer.sub!(/\[!regex_values\]/, xslt_format)
|
459
459
|
|
460
460
|
puts 'xsl_buffer: ' + xsl_buffer if @debug
|
@@ -466,7 +466,7 @@ EOF
|
|
466
466
|
end
|
467
467
|
|
468
468
|
def to_table(fields: nil, markdown: false, innermarkdown: false, heading: true)
|
469
|
-
|
469
|
+
|
470
470
|
tfo = TableFormatter.new markdown: markdown, innermarkdown: innermarkdown
|
471
471
|
tfo.source = self.to_a.map {|h| fields ? fields.map {|x| h[x]} : h.values }
|
472
472
|
|
@@ -475,59 +475,59 @@ EOF
|
|
475
475
|
fields = raw_headings.split(self.delimiter) if raw_headings and fields.nil?
|
476
476
|
tfo.labels = (fields ? fields : self.fields.map{|x| x.to_s.capitalize })
|
477
477
|
end
|
478
|
-
|
478
|
+
|
479
479
|
tfo
|
480
|
-
|
480
|
+
|
481
481
|
end
|
482
|
-
|
483
|
-
def to_xml(opt={})
|
482
|
+
|
483
|
+
def to_xml(opt={})
|
484
484
|
opt = {pretty: true} if opt == :pretty
|
485
485
|
display_xml(opt)
|
486
486
|
end
|
487
|
-
|
488
|
-
# Save the document to a file.
|
489
|
-
|
487
|
+
|
488
|
+
# Save the document to a file.
|
489
|
+
|
490
490
|
def save(filepath=@local_filepath, options={})
|
491
|
-
|
491
|
+
|
492
492
|
if @debug then
|
493
|
-
puts 'inside Dynarex::save'
|
493
|
+
puts 'inside Dynarex::save'
|
494
494
|
puts 'filepath: ' + filepath.inspect
|
495
495
|
|
496
496
|
end
|
497
|
-
|
497
|
+
|
498
498
|
return unless filepath
|
499
|
-
|
499
|
+
|
500
500
|
opt = {pretty: true}.merge options
|
501
501
|
|
502
502
|
@local_filepath = filepath || 'dx.xml'
|
503
503
|
xml = display_xml(opt)
|
504
504
|
buffer = block_given? ? yield(xml) : xml
|
505
|
-
|
505
|
+
|
506
506
|
if @debug then
|
507
507
|
puts 'before write; filepath: ' + filepath.inspect
|
508
508
|
puts 'buffer: ' + buffer.inspect
|
509
509
|
end
|
510
|
-
|
510
|
+
|
511
511
|
FileX.write filepath, buffer
|
512
512
|
FileX.write(filepath.sub(/\.xml$/,'.json'), self.to_json) if @json_out
|
513
513
|
end
|
514
|
-
|
514
|
+
|
515
515
|
#Parses 1 or more lines of text to create or update existing records.
|
516
516
|
|
517
517
|
def parse(x=nil)
|
518
518
|
|
519
519
|
@dirty_flag = true
|
520
|
-
|
520
|
+
|
521
521
|
if x.is_a? Array then
|
522
|
-
|
522
|
+
|
523
523
|
unless @schema then
|
524
|
-
cols = x.first.keys.map {|c| c == 'id' ? 'uid' : c}
|
524
|
+
cols = x.first.keys.map {|c| c == 'id' ? 'uid' : c}
|
525
525
|
self.schema = "items/item(%s)" % cols.join(', ')
|
526
526
|
end
|
527
|
-
|
527
|
+
|
528
528
|
x.each {|record| self.create record }
|
529
|
-
return self
|
530
|
-
|
529
|
+
return self
|
530
|
+
|
531
531
|
end
|
532
532
|
raw_buffer, type = RXFHelper.read(x, auto: false)
|
533
533
|
|
@@ -535,15 +535,15 @@ EOF
|
|
535
535
|
|
536
536
|
buffer = block_given? ? yield(raw_buffer) : raw_buffer.clone
|
537
537
|
string_parse buffer
|
538
|
-
|
538
|
+
|
539
539
|
else
|
540
540
|
foreign_import x
|
541
541
|
end
|
542
|
-
|
543
|
-
end
|
542
|
+
|
543
|
+
end
|
544
544
|
|
545
545
|
|
546
|
-
alias import parse
|
546
|
+
alias import parse
|
547
547
|
|
548
548
|
#Create a record from a hash containing the field name, and the field value.
|
549
549
|
# dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
|
@@ -553,8 +553,8 @@ EOF
|
|
553
553
|
|
554
554
|
puts 'inside create' if @debug
|
555
555
|
raise 'Dynarex#create(): input error: no arg provided' unless obj
|
556
|
-
|
557
|
-
case obj.class.to_s.downcase.to_sym
|
556
|
+
|
557
|
+
case obj.class.to_s.downcase.to_sym
|
558
558
|
when :hash
|
559
559
|
hash_create obj, id, attr: custom_attributes
|
560
560
|
when :string
|
@@ -566,7 +566,7 @@ EOF
|
|
566
566
|
end
|
567
567
|
|
568
568
|
@dirty_flag = true
|
569
|
-
|
569
|
+
|
570
570
|
puts 'before save ' + @autosave.inspect if @debug
|
571
571
|
save() if @autosave
|
572
572
|
|
@@ -575,13 +575,13 @@ EOF
|
|
575
575
|
|
576
576
|
#Create a record from a string, given the dynarex document contains a format mask.
|
577
577
|
# dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
|
578
|
-
# dynarex.create_from_line 'Tracy 37 15-Jun-1972'
|
579
|
-
|
578
|
+
# dynarex.create_from_line 'Tracy 37 15-Jun-1972'
|
579
|
+
|
580
580
|
def create_from_line(line, id=nil, attr: '')
|
581
581
|
t = @format_mask.to_s.gsub(/\[!(\w+)\]/, '(.*)').sub(/\[/,'\[')\
|
582
582
|
.sub(/\]/,'\]')
|
583
583
|
line.match(/#{t}/).captures
|
584
|
-
|
584
|
+
|
585
585
|
a = line.match(/#{t}/).captures
|
586
586
|
h = Hash[@fields.zip(a)]
|
587
587
|
create h
|
@@ -596,8 +596,8 @@ EOF
|
|
596
596
|
|
597
597
|
|
598
598
|
#Updates a record from an id and a hash containing field name and field value.
|
599
|
-
# dynarex.update 4, name: Jeff, age: 38
|
600
|
-
|
599
|
+
# dynarex.update 4, name: Jeff, age: 38
|
600
|
+
|
601
601
|
def update(id, obj)
|
602
602
|
|
603
603
|
params = if obj.is_a? Hash then
|
@@ -605,32 +605,32 @@ EOF
|
|
605
605
|
elsif obj.is_a? RecordX
|
606
606
|
obj.to_h
|
607
607
|
end
|
608
|
-
|
608
|
+
|
609
609
|
fields = capture_fields(params)
|
610
610
|
|
611
611
|
# for each field update each record field
|
612
|
-
record = @doc.root.element("records/#{@record_name}[@id='#{id.to_s}']")
|
612
|
+
record = @doc.root.element("records/#{@record_name}[@id='#{id.to_s}']")
|
613
613
|
|
614
614
|
fields.each do |k,v|
|
615
615
|
puts "updating ... %s = '%s'" % [k,v] if @debug
|
616
616
|
record.element(k.to_s).text = v if v
|
617
617
|
end
|
618
|
-
|
618
|
+
|
619
619
|
record.add_attribute(last_modified: Time.now.to_s)
|
620
620
|
|
621
621
|
@dirty_flag = true
|
622
622
|
|
623
623
|
save() if @autosave
|
624
|
-
|
624
|
+
|
625
625
|
self
|
626
626
|
|
627
627
|
end
|
628
628
|
|
629
|
-
|
629
|
+
|
630
630
|
#Delete a record.
|
631
631
|
# dyarex.delete 3 # deletes record with id 3
|
632
|
-
|
633
|
-
def delete(x)
|
632
|
+
|
633
|
+
def delete(x)
|
634
634
|
|
635
635
|
return x.each {|id| self.delete id} if x.is_a? Array
|
636
636
|
|
@@ -639,86 +639,86 @@ EOF
|
|
639
639
|
else
|
640
640
|
@doc.delete x
|
641
641
|
end
|
642
|
-
|
642
|
+
|
643
643
|
@dirty_flag = true
|
644
644
|
save() if @autosave
|
645
|
-
|
645
|
+
|
646
646
|
self
|
647
647
|
end
|
648
648
|
|
649
649
|
def element(x)
|
650
650
|
@doc.root.element x
|
651
|
-
end
|
652
|
-
|
651
|
+
end
|
652
|
+
|
653
653
|
def sort_by!(field=nil, &element_blk)
|
654
654
|
|
655
655
|
blk = field ? ->(x){ x.text(field.to_s).to_s} : element_blk
|
656
656
|
r = sort_records_by! &blk
|
657
|
-
@dirty_flag = true
|
657
|
+
@dirty_flag = true
|
658
658
|
r
|
659
659
|
|
660
|
-
end
|
660
|
+
end
|
661
|
+
|
661
662
|
|
662
|
-
|
663
663
|
def record(id)
|
664
|
-
e = @doc.root.element("records/*[@id='#{id}']")
|
664
|
+
e = @doc.root.element("records/*[@id='#{id}']")
|
665
665
|
recordx_to_record e if e
|
666
666
|
end
|
667
|
-
|
667
|
+
|
668
668
|
alias find record
|
669
669
|
alias find_by_id record
|
670
670
|
|
671
671
|
def record_exists?(id)
|
672
672
|
!@doc.root.element("records/*[@id='#{id}']").nil?
|
673
673
|
end
|
674
|
-
|
674
|
+
|
675
675
|
def refresh()
|
676
676
|
@dirty_flag = true
|
677
677
|
end
|
678
|
-
|
678
|
+
|
679
679
|
def refresh!()
|
680
|
-
(load_records; rebuild_doc) if @dirty_flag == true
|
680
|
+
(load_records; rebuild_doc) if @dirty_flag == true
|
681
681
|
end
|
682
|
-
|
682
|
+
|
683
683
|
# used internally by to_rss()
|
684
684
|
#
|
685
685
|
def rss_xslt(opt={})
|
686
|
-
|
686
|
+
|
687
687
|
h = {limit: 11}.merge(opt)
|
688
688
|
doc = Rexle.new(self.to_xslt)
|
689
689
|
e = doc.element('//xsl:apply-templates[2]')
|
690
|
-
|
690
|
+
|
691
691
|
e2 = doc.root.element('xsl:template[3]')
|
692
692
|
item = e2.element('item')
|
693
693
|
new_item = item.deep_clone
|
694
694
|
item.delete
|
695
|
-
|
695
|
+
|
696
696
|
pubdate = @xslt_schema[/pubDate:/]
|
697
697
|
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
698
698
|
|
699
699
|
if pubdate.nil? then
|
700
700
|
pubdate = Rexle.new("<pubDate><xsl:value-of select='pubDate'>" + \
|
701
701
|
"</xsl:value-of></pubDate>").root
|
702
|
-
new_item.add pubdate
|
702
|
+
new_item.add pubdate
|
703
703
|
end
|
704
704
|
|
705
|
-
xslif.add new_item
|
705
|
+
xslif.add new_item
|
706
706
|
e2.add xslif.root
|
707
|
-
xslt = doc.xml
|
707
|
+
xslt = doc.xml
|
708
|
+
|
709
|
+
xslt
|
708
710
|
|
709
|
-
xslt
|
710
|
-
|
711
711
|
end
|
712
|
-
|
712
|
+
|
713
713
|
def filter(&blk)
|
714
|
-
|
714
|
+
|
715
715
|
dx = Dynarex.new @schema
|
716
716
|
self.all.select(&blk).each {|x| dx.create x}
|
717
717
|
dx
|
718
|
-
|
718
|
+
|
719
719
|
end
|
720
720
|
|
721
|
-
def to_xslt(opt={})
|
721
|
+
def to_xslt(opt={})
|
722
722
|
|
723
723
|
h = {limit: -1}.merge(opt)
|
724
724
|
@xslt_schema = @xslt_schema || self.summary[:xslt_schema]
|
@@ -728,55 +728,55 @@ EOF
|
|
728
728
|
|
729
729
|
return xslt
|
730
730
|
end
|
731
|
-
|
731
|
+
|
732
732
|
def to_rss(opt={}, xslt=nil)
|
733
|
-
|
733
|
+
|
734
734
|
puts 'inside to_rss'.info if @debug
|
735
|
-
|
735
|
+
|
736
736
|
unless xslt then
|
737
|
-
|
737
|
+
|
738
738
|
h = {limit: 11}.merge(opt)
|
739
739
|
doc = Rexle.new(self.to_xslt)
|
740
740
|
e = doc.element('//xsl:apply-templates[2]')
|
741
|
-
|
741
|
+
|
742
742
|
e2 = doc.root.element('xsl:template[3]')
|
743
743
|
item = e2.element('item')
|
744
744
|
new_item = item.deep_clone
|
745
745
|
item.delete
|
746
|
-
|
746
|
+
|
747
747
|
pubdate = @xslt_schema[/pubDate:/]
|
748
|
-
xslif = Rexle.new("<xsl:if test='position()
|
749
|
-
|
750
|
-
|
748
|
+
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
749
|
+
|
750
|
+
|
751
751
|
if pubdate.nil? then
|
752
752
|
pubdate2 = Rexle.new("<pubDate><xsl:value-of select='pubDate'></xsl:value-of></pubDate>").root
|
753
|
-
new_item.add pubdate2
|
753
|
+
new_item.add pubdate2
|
754
754
|
end
|
755
755
|
|
756
|
-
xslif.add new_item
|
756
|
+
xslif.add new_item
|
757
757
|
e2.add xslif
|
758
|
-
xslt = doc.xml
|
758
|
+
xslt = doc.xml
|
759
759
|
|
760
760
|
xslt
|
761
761
|
end
|
762
|
-
|
762
|
+
|
763
763
|
doc = Rexle.new(self.to_xml)
|
764
|
-
|
764
|
+
|
765
765
|
puts ('pubdate: ' + pubdate.inspect).debug if @debug
|
766
|
-
|
766
|
+
|
767
767
|
if pubdate.nil? then
|
768
768
|
doc.root.xpath('records/*').each do |x|
|
769
769
|
raw_dt = DateTime.parse x.attributes[:created]
|
770
770
|
dt = raw_dt.strftime("%a, %d %b %Y %H:%M:%S %z")
|
771
|
-
x.add Rexle::Element.new('pubDate').add_text dt.to_s
|
771
|
+
x.add Rexle::Element.new('pubDate').add_text dt.to_s
|
772
772
|
end
|
773
773
|
end
|
774
774
|
|
775
775
|
puts ('doc: ' + doc.root.xml) if @debug
|
776
|
-
|
776
|
+
File.write '/tmp/blog.xml', doc.root.xml
|
777
777
|
puts ('xslt:' + xslt.inspect) if @debug
|
778
|
-
|
779
|
-
|
778
|
+
File.write '/tmp/blog.xslt', xslt
|
779
|
+
|
780
780
|
out = Rexslt.new(xslt, doc).to_s(declaration: false)
|
781
781
|
|
782
782
|
#Rexle.new("<rss version='2.0'>%s</rss>" % xml).xml(pretty: true)
|
@@ -786,23 +786,23 @@ EOF
|
|
786
786
|
xml = doc.xml(pretty: true)
|
787
787
|
xml
|
788
788
|
end
|
789
|
-
|
789
|
+
|
790
790
|
def unique=(bool)
|
791
791
|
self.summary.merge!({unique: bool})
|
792
792
|
@dirty_flag = true
|
793
793
|
@unique = bool
|
794
794
|
end
|
795
|
-
|
795
|
+
|
796
796
|
def xpath(x)
|
797
797
|
@doc.root.xpath x
|
798
798
|
end
|
799
799
|
|
800
800
|
def xslt=(value)
|
801
|
-
|
801
|
+
|
802
802
|
self.summary.merge!({xslt: value})
|
803
803
|
@dirty_flag = true
|
804
804
|
@xslt = value
|
805
|
-
end
|
805
|
+
end
|
806
806
|
|
807
807
|
private
|
808
808
|
|
@@ -810,7 +810,7 @@ EOF
|
|
810
810
|
@default_key = :uid
|
811
811
|
@summary[:default_key] = 'uid'
|
812
812
|
@fields << :uid
|
813
|
-
a.each.with_index{|x,i| x << (i+1).to_s}
|
813
|
+
a.each.with_index{|x,i| x << (i+1).to_s}
|
814
814
|
end
|
815
815
|
|
816
816
|
def create_find(fields)
|
@@ -823,21 +823,42 @@ EOF
|
|
823
823
|
end
|
824
824
|
|
825
825
|
def findx_by(field, value)
|
826
|
+
|
826
827
|
#@logger.debug "field: #{field.inspect}, value: #{value.inspect}"
|
827
828
|
(load_records; rebuild_doc) if @dirty_flag == true
|
828
|
-
|
829
|
-
|
829
|
+
|
830
|
+
if value.is_a? String then
|
831
|
+
|
832
|
+
r = @doc.root.element("records/*[#{field}=\"#{value}\"]")
|
833
|
+
r ? recordx_to_record(r) : nil
|
834
|
+
|
835
|
+
elsif value.is_a? Regexp
|
836
|
+
|
837
|
+
found = all.select {|x| x.method(field).call =~ /#{value}/i}
|
838
|
+
found.first if found.any?
|
839
|
+
|
840
|
+
end
|
841
|
+
|
830
842
|
end
|
831
843
|
|
832
844
|
def findx_all_by(field, value)
|
833
|
-
|
845
|
+
|
846
|
+
if value.is_a? String then
|
847
|
+
|
848
|
+
@doc.root.xpath("records/*[#{field}=\"#{value}\"]")\
|
834
849
|
.map {|x| recordx_to_record x}
|
850
|
+
|
851
|
+
elsif value.is_a? Regexp
|
852
|
+
|
853
|
+
all.select {|x| x.method(field).call =~ /#{value}/i}
|
854
|
+
|
855
|
+
end
|
835
856
|
end
|
836
857
|
|
837
858
|
def recordx_to_record(recordx)
|
838
|
-
|
859
|
+
|
839
860
|
h = recordx.attributes
|
840
|
-
|
861
|
+
|
841
862
|
records = recordx.xpath("*").map {|x| x.text ? x.text.unescape.to_s : '' }
|
842
863
|
hash = @fields.zip(records).to_h
|
843
864
|
RecordX.new(hash, self, h[:id], h[:created], h[:last_modified])
|
@@ -859,21 +880,21 @@ EOF
|
|
859
880
|
fields.keys.each {|key| fields[key] = params[key.to_sym] if params.has_key? key.to_sym}
|
860
881
|
fields
|
861
882
|
end
|
862
|
-
|
883
|
+
|
863
884
|
def display_xml(options={})
|
864
885
|
#@logger.debug 'inside display_xml'
|
865
886
|
opt = {unescape_html: false}.merge options
|
866
|
-
|
887
|
+
|
867
888
|
state = :external
|
868
889
|
#@logger.debug 'before diry'
|
869
890
|
if @dirty_flag == true then
|
870
|
-
load_records
|
891
|
+
load_records
|
871
892
|
state = :internal
|
872
893
|
end
|
873
894
|
#@logger.debug 'before rebuilt'
|
874
895
|
doc = rebuild_doc(state)
|
875
896
|
#@logger.debug 'after rebuild_doc'
|
876
|
-
|
897
|
+
|
877
898
|
if opt[:unescape_html] == true then
|
878
899
|
doc.content(opt)
|
879
900
|
else
|
@@ -887,15 +908,15 @@ EOF
|
|
887
908
|
raw_params.merge!(uid: id) if @default_key.to_sym == :uid
|
888
909
|
params = Hash[raw_params.keys.map(&:to_sym).zip(raw_params.values)]
|
889
910
|
|
890
|
-
fields = capture_fields(params)
|
911
|
+
fields = capture_fields(params)
|
891
912
|
record = Rexle::Element.new @record_name
|
892
913
|
|
893
914
|
fields.each do |k,v|
|
894
|
-
element = Rexle::Element.new(k.to_s)
|
915
|
+
element = Rexle::Element.new(k.to_s)
|
895
916
|
element.root.text = v.to_s.gsub('<','<').gsub('>','>') if v
|
896
917
|
record.add element if record
|
897
918
|
end
|
898
|
-
|
919
|
+
|
899
920
|
attributes = {id: id.to_s, created: Time.now.to_s, last_modified: nil}\
|
900
921
|
.merge attr
|
901
922
|
attributes.each {|k,v| record.add_attribute(k, v)}
|
@@ -912,7 +933,7 @@ EOF
|
|
912
933
|
buffer = RXFHelper.read(line.chomp, auto: false).first
|
913
934
|
|
914
935
|
doc = Rexle.new buffer
|
915
|
-
|
936
|
+
|
916
937
|
if doc.root.name == 'kvx' then
|
917
938
|
|
918
939
|
kvx = Kvx.new doc
|
@@ -924,17 +945,17 @@ EOF
|
|
924
945
|
end
|
925
946
|
|
926
947
|
end
|
927
|
-
|
948
|
+
|
928
949
|
def rebuild_doc(state=:internal)
|
929
|
-
|
950
|
+
|
930
951
|
puts 'inside rebuild_doc'.info if @debug
|
931
952
|
|
932
|
-
reserved_keywords = (
|
953
|
+
reserved_keywords = (
|
933
954
|
Object.public_methods | \
|
934
955
|
Kernel.public_methods | \
|
935
956
|
public_methods + [:method_missing]
|
936
957
|
)
|
937
|
-
|
958
|
+
|
938
959
|
xml = RexleBuilder.new
|
939
960
|
|
940
961
|
a = xml.send @root_name do
|
@@ -960,30 +981,33 @@ EOF
|
|
960
981
|
#jr160315records.reverse! if @order == 'descending' and state == :external
|
961
982
|
|
962
983
|
xml.records do
|
963
|
-
|
984
|
+
|
964
985
|
records.each do |k, item|
|
965
|
-
|
986
|
+
|
966
987
|
attributes = {}
|
967
|
-
|
988
|
+
|
968
989
|
item.keys.each do |key|
|
969
990
|
attributes[key] = item[key] || '' unless key == :body
|
970
991
|
end
|
971
|
-
|
992
|
+
|
972
993
|
if @record_name.nil? then
|
973
994
|
raise DynarexException, 'record_name can\'t be nil. Check the schema'
|
974
995
|
end
|
975
|
-
|
996
|
+
|
997
|
+
puts 'attributes: ' + attributes.inspect if @debug
|
998
|
+
puts '@record_name: ' + @record_name.inspect
|
999
|
+
|
976
1000
|
xml.send(@record_name, attributes) do
|
977
|
-
item[:body].each do |name,value|
|
1001
|
+
item[:body].each do |name,value|
|
978
1002
|
|
979
1003
|
if reserved_keywords.include? name then
|
980
|
-
name = ('._' + name.to_s).to_sym
|
1004
|
+
name = ('._' + name.to_s).to_sym
|
981
1005
|
end
|
982
|
-
|
1006
|
+
|
983
1007
|
val = value.send(value.is_a?(String) ? :to_s : :to_yaml)
|
984
1008
|
xml.send(name, val.gsub('>','>')\
|
985
1009
|
.gsub('<','<')\
|
986
|
-
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
1010
|
+
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
987
1011
|
x[-1] == ';' ? x : x.sub('&','&')
|
988
1012
|
end
|
989
1013
|
)
|
@@ -998,22 +1022,22 @@ EOF
|
|
998
1022
|
end
|
999
1023
|
|
1000
1024
|
doc = Rexle.new(a)
|
1001
|
-
|
1025
|
+
|
1002
1026
|
puts ('@xslt: ' + @xslt.inspect).debug if @debug
|
1003
|
-
|
1027
|
+
|
1004
1028
|
if @xslt then
|
1005
|
-
doc.instructions = [['xml-stylesheet',
|
1029
|
+
doc.instructions = [['xml-stylesheet',
|
1006
1030
|
"title='XSL_formatting' type='text/xsl' href='#{@xslt}'"]]
|
1007
1031
|
end
|
1008
1032
|
|
1009
1033
|
return doc if state != :internal
|
1010
1034
|
@doc = doc
|
1011
|
-
end
|
1012
|
-
|
1035
|
+
end
|
1036
|
+
|
1013
1037
|
def string_parse(buffer)
|
1014
|
-
|
1038
|
+
|
1015
1039
|
if @spaces_delimited then
|
1016
|
-
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1040
|
+
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1017
1041
|
end
|
1018
1042
|
|
1019
1043
|
buffer.gsub!("\r",'')
|
@@ -1024,25 +1048,25 @@ EOF
|
|
1024
1048
|
buffer.gsub!(/<./) {|x| x[1] != '?' ? x.sub(/</,'<') : x }
|
1025
1049
|
|
1026
1050
|
@raw_header = buffer[/<\?dynarex[^>]+>/]
|
1027
|
-
|
1051
|
+
|
1028
1052
|
if buffer[/<\?/] then
|
1029
1053
|
|
1030
1054
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1031
1055
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1032
1056
|
@raw_header = buffer.slice!(/<\?dynarex[^>]+>/) + "\n"
|
1033
|
-
|
1057
|
+
|
1034
1058
|
header = @raw_header[/<?dynarex (.*)?>/,1]
|
1035
1059
|
|
1036
1060
|
r1 = /([\w\-]+\s*\=\s*'[^']*)'/
|
1037
1061
|
r2 = /([\w\-]+\s*\=\s*"[^"]*)"/
|
1038
1062
|
|
1039
|
-
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1063
|
+
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1040
1064
|
|
1041
1065
|
r.each do |x|
|
1042
1066
|
|
1043
1067
|
attr, val = x.split(/\s*=\s*["']/,2)
|
1044
1068
|
name = (attr + '=').to_sym
|
1045
|
-
|
1069
|
+
|
1046
1070
|
if self.public_methods.include? name then
|
1047
1071
|
self.method(name).call(unescape val)
|
1048
1072
|
else
|
@@ -1062,7 +1086,7 @@ EOF
|
|
1062
1086
|
if raw_summary then
|
1063
1087
|
|
1064
1088
|
a_summary = raw_summary.split(',').map(&:strip)
|
1065
|
-
|
1089
|
+
|
1066
1090
|
@summary ||= {}
|
1067
1091
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1068
1092
|
|
@@ -1082,7 +1106,7 @@ EOF
|
|
1082
1106
|
@summary[:schema] = @schema
|
1083
1107
|
@summary[:format_mask] = @format_mask
|
1084
1108
|
@summary[:unique] = @unique if @unique
|
1085
|
-
|
1109
|
+
|
1086
1110
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1087
1111
|
|
1088
1112
|
lines = case raw_lines.first.rstrip
|
@@ -1092,10 +1116,10 @@ EOF
|
|
1092
1116
|
yaml = YAML.load raw_lines.join("\n")
|
1093
1117
|
|
1094
1118
|
yamlize = lambda {|x| (x.is_a? Array) ? x.to_yaml : x}
|
1095
|
-
|
1119
|
+
|
1096
1120
|
yprocs = {
|
1097
1121
|
Hash: lambda {|y|
|
1098
|
-
y.map do |k,v|
|
1122
|
+
y.map do |k,v|
|
1099
1123
|
procs = {Hash: proc {|x| x.values}, Array: proc {v}}
|
1100
1124
|
values = procs[v.class.to_s.to_sym].call(v).map(&yamlize)
|
1101
1125
|
[k, *values]
|
@@ -1104,23 +1128,23 @@ EOF
|
|
1104
1128
|
Array: lambda {|y| y.map {|x2| x2.map(&yamlize)} }
|
1105
1129
|
}
|
1106
1130
|
|
1107
|
-
yprocs[yaml.class.to_s.to_sym].call yaml
|
1108
|
-
|
1131
|
+
yprocs[yaml.class.to_s.to_sym].call yaml
|
1132
|
+
|
1109
1133
|
when '--+'
|
1110
1134
|
|
1111
1135
|
rowx(raw_lines)
|
1112
|
-
|
1136
|
+
|
1113
1137
|
when '--#'
|
1114
1138
|
|
1115
1139
|
self.summary[:rawdoc_type] = 'sectionx'
|
1116
1140
|
raw_lines.shift
|
1117
1141
|
|
1118
1142
|
raw_lines.join.lstrip.split(/(?=^#[^#])/).map {|x| [x.rstrip]}
|
1119
|
-
|
1143
|
+
|
1120
1144
|
else
|
1121
1145
|
|
1122
1146
|
raw_lines = raw_lines.join("\n").gsub(/^(\s*#[^\n]+|\n)/,'').lines.to_a
|
1123
|
-
|
1147
|
+
|
1124
1148
|
if @linked then
|
1125
1149
|
|
1126
1150
|
parse_links(raw_lines)
|
@@ -1129,42 +1153,42 @@ EOF
|
|
1129
1153
|
a2 = raw_lines.map.with_index do |x,i|
|
1130
1154
|
|
1131
1155
|
next if x[/^\s+$|\n\s*#/]
|
1132
|
-
|
1156
|
+
|
1133
1157
|
begin
|
1134
|
-
|
1158
|
+
|
1135
1159
|
field_names, field_values = RXRawLineParser.new(@format_mask).parse(x)
|
1136
1160
|
rescue
|
1137
1161
|
raise "input file parser error at line " + (i + 1).to_s + ' --> ' + x
|
1138
1162
|
end
|
1139
1163
|
field_values
|
1140
1164
|
end
|
1141
|
-
|
1165
|
+
|
1142
1166
|
a2.compact!
|
1143
1167
|
a3 = a2.compact.map(&:first)
|
1144
|
-
|
1168
|
+
|
1145
1169
|
if a3 != a3.uniq then
|
1146
|
-
|
1170
|
+
|
1147
1171
|
if @unique then
|
1148
1172
|
raise DynarexException, "Duplicate id found"
|
1149
1173
|
else
|
1150
|
-
add_id(a2)
|
1174
|
+
add_id(a2)
|
1151
1175
|
end
|
1152
|
-
|
1176
|
+
|
1153
1177
|
end
|
1154
|
-
|
1178
|
+
|
1155
1179
|
a2
|
1156
|
-
end
|
1180
|
+
end
|
1157
1181
|
|
1158
1182
|
end
|
1159
1183
|
|
1160
|
-
a = lines.map.with_index do |x,i|
|
1161
|
-
|
1184
|
+
a = lines.map.with_index do |x,i|
|
1185
|
+
|
1162
1186
|
created = Time.now.to_s
|
1163
1187
|
|
1164
1188
|
h = Hash[
|
1165
1189
|
@fields.zip(
|
1166
1190
|
x.map do |t|
|
1167
|
-
|
1191
|
+
|
1168
1192
|
t.to_s[/^---(?:\s|\n)/] ? YAML.load(t[/^---(?:\s|\n)(.*)/,1]) : unescape(t.to_s)
|
1169
1193
|
end
|
1170
1194
|
)
|
@@ -1186,12 +1210,12 @@ EOF
|
|
1186
1210
|
item[:body].each do |k,v|
|
1187
1211
|
h[key][:body][k.to_sym] = v
|
1188
1212
|
end
|
1189
|
-
else
|
1213
|
+
else
|
1190
1214
|
item[:id] = (@order == 'descending' ? (h2.count) - i : i+ 1).to_s
|
1191
1215
|
i += 1
|
1192
1216
|
h[key] = item.clone
|
1193
|
-
end
|
1194
|
-
end
|
1217
|
+
end
|
1218
|
+
end
|
1195
1219
|
|
1196
1220
|
h.each {|key, item| h.delete(key) if not h2.has_key? key}
|
1197
1221
|
|
@@ -1200,9 +1224,9 @@ EOF
|
|
1200
1224
|
rebuild_doc
|
1201
1225
|
self
|
1202
1226
|
end
|
1203
|
-
|
1227
|
+
|
1204
1228
|
def sort_records_by!(&element_blk)
|
1205
|
-
|
1229
|
+
|
1206
1230
|
refresh_doc
|
1207
1231
|
a = @doc.root.xpath('records/*').sort_by &element_blk
|
1208
1232
|
@doc.root.delete('records')
|
@@ -1215,33 +1239,36 @@ EOF
|
|
1215
1239
|
|
1216
1240
|
load_records if @dirty_flag
|
1217
1241
|
self
|
1218
|
-
end
|
1242
|
+
end
|
1219
1243
|
|
1220
1244
|
def unescape(s)
|
1221
1245
|
s.gsub('<', '<').gsub('>','>')
|
1222
1246
|
end
|
1223
1247
|
|
1224
1248
|
def dynarex_new(s, default_key: nil)
|
1225
|
-
|
1249
|
+
|
1226
1250
|
@schema = schema = s
|
1227
1251
|
@default_key = default_key if default_key
|
1228
|
-
|
1252
|
+
|
1229
1253
|
ptrn = %r((\w+)\[?([^\]]+)?\]?\/(\w+)\(([^\)]+)\))
|
1230
1254
|
|
1231
1255
|
if s.match(ptrn) then
|
1232
|
-
|
1233
|
-
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1256
|
+
|
1257
|
+
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1258
|
+
reserved = %w(require parent gem)
|
1259
|
+
|
1260
|
+
raise 'reserved keyword: ' + record_name if reserved.include? record_name
|
1234
1261
|
summary, fields = [raw_summary || '',raw_fields].map {|x| x.split(/,/).map &:strip}
|
1235
|
-
|
1262
|
+
|
1236
1263
|
if fields.include? 'id' then
|
1237
|
-
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1264
|
+
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1238
1265
|
end
|
1239
|
-
|
1266
|
+
|
1240
1267
|
create_find fields
|
1241
|
-
|
1242
|
-
|
1268
|
+
|
1269
|
+
|
1243
1270
|
raise 'reserved keyword' if (fields & reserved).any?
|
1244
|
-
|
1271
|
+
|
1245
1272
|
else
|
1246
1273
|
ptrn = %r((\w+)\[?([^\]]+)?\]?)
|
1247
1274
|
@root_name, raw_summary = s.match(ptrn).captures
|
@@ -1264,36 +1291,36 @@ EOF
|
|
1264
1291
|
def attach_record_methods()
|
1265
1292
|
create_find @fields
|
1266
1293
|
end
|
1267
|
-
|
1294
|
+
|
1268
1295
|
def openx(s)
|
1269
1296
|
#@logger.debug 'inside openx'
|
1270
1297
|
if s[/</] then # xml
|
1271
1298
|
#@logger.debug 'regular string'
|
1272
1299
|
#@logger.debug 's: ' + s.inspect
|
1273
1300
|
buffer = s
|
1274
|
-
|
1301
|
+
|
1275
1302
|
elsif s[/[\[\(]/] # schema
|
1276
1303
|
|
1277
1304
|
dynarex_new(s)
|
1278
|
-
|
1305
|
+
|
1279
1306
|
elsif s[/^https?:\/\//] then # url
|
1280
|
-
buffer, type = RXFHelper.read s, {username: @username,
|
1281
|
-
password: @password, auto: false}
|
1282
|
-
elsif s[/^dfs?:\/\//] then
|
1283
|
-
|
1284
|
-
@local_filepath = s
|
1307
|
+
buffer, type = RXFHelper.read s, {username: @username,
|
1308
|
+
password: @password, auto: false}
|
1309
|
+
elsif s[/^dfs?:\/\//] then
|
1310
|
+
|
1311
|
+
@local_filepath = s
|
1285
1312
|
|
1286
1313
|
if FileX.exists? s then
|
1287
1314
|
buffer = FileX.read s
|
1288
1315
|
elsif @schema
|
1289
|
-
dynarex_new @schema, default_key: @default_key
|
1290
|
-
end
|
1291
|
-
|
1316
|
+
dynarex_new @schema, default_key: @default_key
|
1317
|
+
end
|
1318
|
+
|
1292
1319
|
else # local file
|
1293
|
-
|
1320
|
+
|
1294
1321
|
@local_filepath = s
|
1295
|
-
|
1296
|
-
if File.exists? s then
|
1322
|
+
|
1323
|
+
if File.exists? s then
|
1297
1324
|
buffer = File.read s
|
1298
1325
|
elsif @schema
|
1299
1326
|
dynarex_new @schema, default_key: @default_key
|
@@ -1302,18 +1329,18 @@ EOF
|
|
1302
1329
|
end
|
1303
1330
|
end
|
1304
1331
|
#@logger.debug 'buffer: ' + buffer[0..120]
|
1305
|
-
|
1332
|
+
|
1306
1333
|
return import(buffer) if buffer =~ /^<\?dynarex\b/
|
1307
1334
|
|
1308
1335
|
if buffer then
|
1309
1336
|
|
1310
1337
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1311
1338
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1312
|
-
|
1313
|
-
@doc = Rexle.new(buffer) unless @doc
|
1339
|
+
|
1340
|
+
@doc = Rexle.new(buffer) unless @doc
|
1314
1341
|
#@logger.debug 'openx/@doc : ' + @doc.xml.inspect
|
1315
1342
|
end
|
1316
|
-
|
1343
|
+
|
1317
1344
|
return if @doc.root.nil?
|
1318
1345
|
e = @doc.root.element('summary')
|
1319
1346
|
|
@@ -1322,20 +1349,20 @@ EOF
|
|
1322
1349
|
@summary = summary_to_h
|
1323
1350
|
|
1324
1351
|
summary_methods = (@summary.keys - self.public_methods)
|
1325
|
-
|
1352
|
+
|
1326
1353
|
summary_methods.each do |x|
|
1327
|
-
|
1354
|
+
|
1328
1355
|
instance_eval "
|
1329
|
-
|
1356
|
+
|
1330
1357
|
def #{x.to_sym}()
|
1331
1358
|
@summary[:#{x}]
|
1332
1359
|
end
|
1333
|
-
|
1360
|
+
|
1334
1361
|
def #{x.to_s}=(v)
|
1335
1362
|
@summary[:#{x}] = v
|
1336
1363
|
@doc.root.element('summary/#{x.to_s}').text = v
|
1337
1364
|
end
|
1338
|
-
"
|
1365
|
+
"
|
1339
1366
|
end
|
1340
1367
|
|
1341
1368
|
@order = @summary[:order] if @summary.has_key? :order
|
@@ -1357,7 +1384,7 @@ EOF
|
|
1357
1384
|
|
1358
1385
|
if @fields then
|
1359
1386
|
|
1360
|
-
@default_key = @fields[0] unless @default_key
|
1387
|
+
@default_key = @fields[0] unless @default_key
|
1361
1388
|
# load the record query handler methods
|
1362
1389
|
attach_record_methods
|
1363
1390
|
else
|
@@ -1365,46 +1392,46 @@ EOF
|
|
1365
1392
|
#jr080912 @default_key = @doc.root.xpath('records/*/*').first.name
|
1366
1393
|
@default_key = @doc.root.element('records/./.[1]').name
|
1367
1394
|
end
|
1368
|
-
|
1395
|
+
|
1369
1396
|
@summary[:default_key] = @default_key.to_s
|
1370
|
-
|
1397
|
+
|
1371
1398
|
if @doc.root.xpath('records/*').length > 0 then
|
1372
|
-
@record_name = @doc.root.element('records/*[1]').name
|
1399
|
+
@record_name = @doc.root.element('records/*[1]').name
|
1373
1400
|
#jr240913 load_records
|
1374
1401
|
@dirty_flag = true
|
1375
1402
|
end
|
1376
1403
|
|
1377
|
-
end
|
1404
|
+
end
|
1378
1405
|
|
1379
1406
|
def load_records
|
1380
|
-
|
1407
|
+
|
1381
1408
|
puts 'inside load_records'.info if @debug
|
1382
|
-
|
1409
|
+
|
1383
1410
|
@dirty_flag = false
|
1384
|
-
|
1411
|
+
|
1385
1412
|
if @summary[:order] then
|
1386
|
-
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1413
|
+
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1387
1414
|
sort_records_by! {|x| x.element(orderfield).text } if orderfield
|
1388
1415
|
end
|
1389
|
-
|
1416
|
+
|
1390
1417
|
@records = records_to_h
|
1391
|
-
|
1418
|
+
|
1392
1419
|
@records.instance_eval do
|
1393
1420
|
def delete_item(i)
|
1394
1421
|
self.delete self.keys[i]
|
1395
1422
|
end
|
1396
1423
|
end
|
1397
|
-
|
1424
|
+
|
1398
1425
|
#Returns a ready-only snapshot of records as a simple Hash.
|
1399
1426
|
@flat_records = @records.values.map{|x| x[:body]}
|
1400
1427
|
|
1401
1428
|
end
|
1402
|
-
|
1429
|
+
|
1403
1430
|
|
1404
1431
|
def display()
|
1405
1432
|
puts @doc.to_s
|
1406
1433
|
end
|
1407
|
-
|
1434
|
+
|
1408
1435
|
def records_to_h(order=:ascending)
|
1409
1436
|
|
1410
1437
|
i = @doc.root.xpath('max(records/*/attribute::id)') || 0
|
@@ -1425,25 +1452,25 @@ EOF
|
|
1425
1452
|
end
|
1426
1453
|
|
1427
1454
|
body = (@fields - ['uid']).inject({}) do |r,field|
|
1428
|
-
|
1455
|
+
|
1429
1456
|
node = row.element field.to_s
|
1430
1457
|
|
1431
1458
|
if node then
|
1432
1459
|
text = node.text ? node.text.unescape : ''
|
1433
1460
|
|
1434
|
-
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1461
|
+
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1435
1462
|
YAML.load(text[/^---(?:\s|\n)(.*)/,1]) : text)
|
1436
1463
|
else
|
1437
1464
|
r
|
1438
1465
|
end
|
1439
1466
|
end
|
1440
|
-
|
1467
|
+
|
1441
1468
|
body[:uid] = id if @default_key == 'uid'
|
1442
1469
|
|
1443
1470
|
attributes = row.attributes
|
1444
1471
|
result.merge body[@default_key.to_sym] => attributes.merge({id: id, body: body})
|
1445
1472
|
end
|
1446
|
-
|
1473
|
+
|
1447
1474
|
puts 'records_to_h a: ' + a.inspect if @debug
|
1448
1475
|
#@logger.debug 'a: ' + a.inspect
|
1449
1476
|
a
|
@@ -1459,56 +1486,56 @@ EOF
|
|
1459
1486
|
|
1460
1487
|
# get the fields
|
1461
1488
|
a4 = a3.map{|x| x.scan(/^\w+(?=:)/)}.flatten(1).uniq
|
1462
|
-
|
1489
|
+
|
1463
1490
|
abbrv_fields = a4.all? {|x| x.length == 1}
|
1464
|
-
|
1491
|
+
|
1465
1492
|
a5 = a3.map do |xlines|
|
1466
|
-
|
1493
|
+
|
1467
1494
|
puts 'xlines: ' + xlines.inspect if @debug
|
1468
|
-
|
1495
|
+
|
1469
1496
|
missing_fields = a4 - xlines.scan(/^\w+(?=:)/)
|
1470
1497
|
|
1471
1498
|
r = xlines.split(/\n(\w+:.*)/m)
|
1472
1499
|
puts 'r: ' + r.inspect if @debug
|
1473
|
-
|
1500
|
+
|
1474
1501
|
missing_fields.map!{|x| x + ":"}
|
1475
1502
|
key = (abbrv_fields ? @fields[0].to_s[0] : @fields.first.to_s) + ':'
|
1476
|
-
|
1503
|
+
|
1477
1504
|
if missing_fields.include? key
|
1478
1505
|
r.unshift key
|
1479
1506
|
missing_fields.delete key
|
1480
1507
|
end
|
1481
|
-
|
1508
|
+
|
1482
1509
|
r += missing_fields
|
1483
1510
|
r.join("\n")
|
1484
|
-
|
1511
|
+
|
1485
1512
|
end
|
1486
1513
|
puts 'a5: ' + a5.inspect if @debug
|
1487
|
-
|
1514
|
+
|
1488
1515
|
xml = RowX.new(a5.join("\n").strip, level: 0).to_xml
|
1489
1516
|
puts 'xml: ' + xml.inspect if @debug
|
1490
|
-
|
1491
|
-
a2 = Rexle.new(xml).root.xpath('item').inject([]) do |r,x|
|
1517
|
+
|
1518
|
+
a2 = Rexle.new(xml).root.xpath('item').inject([]) do |r,x|
|
1492
1519
|
|
1493
1520
|
r << @fields.map do |field|
|
1494
1521
|
x.text(abbrv_fields ? field.to_s.chr : field.to_s )
|
1495
1522
|
end
|
1496
|
-
|
1523
|
+
|
1497
1524
|
end
|
1498
1525
|
|
1499
|
-
a2.compact!
|
1500
|
-
|
1501
|
-
# if there is no field value for the first field then
|
1526
|
+
a2.compact!
|
1527
|
+
|
1528
|
+
# if there is no field value for the first field then
|
1502
1529
|
# the default_key is invalid. The default_key is changed to an ID.
|
1503
1530
|
if a2.detect {|x| x.first == ''} then
|
1504
1531
|
add_id(a2)
|
1505
1532
|
else
|
1506
1533
|
|
1507
1534
|
a3 = a2.map(&:first)
|
1508
|
-
add_id(a2) if a3 != a3.uniq
|
1509
|
-
|
1535
|
+
add_id(a2) if a3 != a3.uniq
|
1536
|
+
|
1510
1537
|
end
|
1511
|
-
|
1538
|
+
|
1512
1539
|
a2
|
1513
1540
|
|
1514
1541
|
end
|
@@ -1544,13 +1571,13 @@ XSL
|
|
1544
1571
|
@doc = Rexle.new(Rexslt.new(xsl, self.to_xml).to_s)
|
1545
1572
|
@dirty_flag = true
|
1546
1573
|
end
|
1547
|
-
|
1574
|
+
|
1548
1575
|
def summary_to_h
|
1549
1576
|
|
1550
1577
|
h = {recordx_type: 'dynarex'}
|
1551
|
-
|
1578
|
+
|
1552
1579
|
@doc.root.xpath('summary/*').inject(h) do |r,node|
|
1553
|
-
r.merge node.name.to_s.to_sym =>
|
1580
|
+
r.merge node.name.to_s.to_sym =>
|
1554
1581
|
node.text ? node.text.unescape : node.text.to_s
|
1555
1582
|
end
|
1556
1583
|
end
|