dynarex 1.9.10 → 1.10.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/dynarex.rb +314 -304
- data.tar.gz.sig +0 -0
- metadata +28 -27
- 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,9 +87,9 @@ 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,
|
90
|
+
def initialize(rawx=nil, username: nil, password: nil, schema: nil,
|
91
91
|
default_key: nil, json_out: true, debug: false,
|
92
|
-
delimiter: ' # ', autosave: false, order: 'ascending',
|
92
|
+
delimiter: ' # ', autosave: false, order: 'ascending',
|
93
93
|
unique: false, filepath: nil)
|
94
94
|
|
95
95
|
|
@@ -98,7 +98,7 @@ class Dynarex
|
|
98
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
113
|
openx(rawx.clone)
|
114
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
|
+
|
295
296
|
|
296
|
-
|
297
|
-
def to_doc
|
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 = RXFReader.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
|
puts 'dinddd'
|
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,61 @@ 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
|
+
alias write save
|
516
|
+
|
515
517
|
#Parses 1 or more lines of text to create or update existing records.
|
516
518
|
|
517
519
|
def parse(x=nil)
|
518
520
|
|
519
521
|
@dirty_flag = true
|
520
|
-
|
522
|
+
|
521
523
|
if x.is_a? Array then
|
522
|
-
|
524
|
+
|
523
525
|
unless @schema then
|
524
|
-
cols = x.first.keys.map {|c| c == 'id' ? 'uid' : c}
|
526
|
+
cols = x.first.keys.map {|c| c == 'id' ? 'uid' : c}
|
525
527
|
self.schema = "items/item(%s)" % cols.join(', ')
|
526
528
|
end
|
527
|
-
|
529
|
+
|
528
530
|
x.each {|record| self.create record }
|
529
|
-
return self
|
530
|
-
|
531
|
+
return self
|
532
|
+
|
531
533
|
end
|
532
534
|
raw_buffer, type = RXFReader.read(x, auto: false)
|
533
535
|
|
@@ -535,15 +537,15 @@ EOF
|
|
535
537
|
|
536
538
|
buffer = block_given? ? yield(raw_buffer) : raw_buffer.clone
|
537
539
|
string_parse buffer.force_encoding('UTF-8')
|
538
|
-
|
540
|
+
|
539
541
|
else
|
540
542
|
foreign_import x
|
541
543
|
end
|
542
|
-
|
543
|
-
end
|
544
|
+
|
545
|
+
end
|
544
546
|
|
545
547
|
|
546
|
-
alias import parse
|
548
|
+
alias import parse
|
547
549
|
|
548
550
|
#Create a record from a hash containing the field name, and the field value.
|
549
551
|
# dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
|
@@ -553,8 +555,8 @@ EOF
|
|
553
555
|
|
554
556
|
puts 'inside create' if @debug
|
555
557
|
raise 'Dynarex#create(): input error: no arg provided' unless obj
|
556
|
-
|
557
|
-
case obj.class.to_s.downcase.to_sym
|
558
|
+
|
559
|
+
case obj.class.to_s.downcase.to_sym
|
558
560
|
when :hash
|
559
561
|
hash_create obj, id, attr: custom_attributes
|
560
562
|
when :string
|
@@ -566,7 +568,7 @@ EOF
|
|
566
568
|
end
|
567
569
|
|
568
570
|
@dirty_flag = true
|
569
|
-
|
571
|
+
|
570
572
|
puts 'before save ' + @autosave.inspect if @debug
|
571
573
|
save() if @autosave
|
572
574
|
|
@@ -575,13 +577,13 @@ EOF
|
|
575
577
|
|
576
578
|
#Create a record from a string, given the dynarex document contains a format mask.
|
577
579
|
# dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
|
578
|
-
# dynarex.create_from_line 'Tracy 37 15-Jun-1972'
|
579
|
-
|
580
|
+
# dynarex.create_from_line 'Tracy 37 15-Jun-1972'
|
581
|
+
|
580
582
|
def create_from_line(line, id=nil, attr: '')
|
581
583
|
t = @format_mask.to_s.gsub(/\[!(\w+)\]/, '(.*)').sub(/\[/,'\[')\
|
582
584
|
.sub(/\]/,'\]')
|
583
585
|
line.match(/#{t}/).captures
|
584
|
-
|
586
|
+
|
585
587
|
a = line.match(/#{t}/).captures
|
586
588
|
h = Hash[@fields.zip(a)]
|
587
589
|
create h
|
@@ -596,8 +598,8 @@ EOF
|
|
596
598
|
|
597
599
|
|
598
600
|
#Updates a record from an id and a hash containing field name and field value.
|
599
|
-
# dynarex.update 4, name: Jeff, age: 38
|
600
|
-
|
601
|
+
# dynarex.update 4, name: Jeff, age: 38
|
602
|
+
|
601
603
|
def update(id, obj)
|
602
604
|
|
603
605
|
params = if obj.is_a? Hash then
|
@@ -605,32 +607,32 @@ EOF
|
|
605
607
|
elsif obj.is_a? RecordX
|
606
608
|
obj.to_h
|
607
609
|
end
|
608
|
-
|
610
|
+
|
609
611
|
fields = capture_fields(params)
|
610
612
|
|
611
613
|
# for each field update each record field
|
612
|
-
record = @doc.root.element("records/#{@record_name}[@id='#{id.to_s}']")
|
614
|
+
record = @doc.root.element("records/#{@record_name}[@id='#{id.to_s}']")
|
613
615
|
|
614
616
|
fields.each do |k,v|
|
615
617
|
puts "updating ... %s = '%s'" % [k,v] if @debug
|
616
618
|
record.element(k.to_s).text = v if v
|
617
619
|
end
|
618
|
-
|
620
|
+
|
619
621
|
record.add_attribute(last_modified: Time.now.to_s)
|
620
622
|
|
621
623
|
@dirty_flag = true
|
622
624
|
|
623
625
|
save() if @autosave
|
624
|
-
|
626
|
+
|
625
627
|
self
|
626
628
|
|
627
629
|
end
|
628
630
|
|
629
|
-
|
631
|
+
|
630
632
|
#Delete a record.
|
631
633
|
# dyarex.delete 3 # deletes record with id 3
|
632
|
-
|
633
|
-
def delete(x)
|
634
|
+
|
635
|
+
def delete(x)
|
634
636
|
|
635
637
|
return x.each {|id| self.delete id} if x.is_a? Array
|
636
638
|
|
@@ -639,137 +641,145 @@ EOF
|
|
639
641
|
else
|
640
642
|
@doc.delete x
|
641
643
|
end
|
642
|
-
|
644
|
+
|
643
645
|
@dirty_flag = true
|
644
646
|
save() if @autosave
|
645
|
-
|
647
|
+
|
646
648
|
self
|
647
649
|
end
|
648
650
|
|
649
651
|
def element(x)
|
650
652
|
@doc.root.element x
|
651
|
-
end
|
652
|
-
|
653
|
+
end
|
654
|
+
|
653
655
|
def sort_by!(field=nil, &element_blk)
|
654
656
|
|
655
657
|
blk = field ? ->(x){ x.text(field.to_s).to_s} : element_blk
|
656
658
|
r = sort_records_by! &blk
|
657
|
-
@dirty_flag = true
|
659
|
+
@dirty_flag = true
|
658
660
|
r
|
659
661
|
|
660
|
-
end
|
661
|
-
|
662
|
+
end
|
662
663
|
|
664
|
+
|
663
665
|
def record(id)
|
664
|
-
e = @doc.root.element("records/*[@id='#{id}']")
|
666
|
+
e = @doc.root.element("records/*[@id='#{id}']")
|
665
667
|
recordx_to_record e if e
|
666
668
|
end
|
667
|
-
|
669
|
+
|
668
670
|
alias find record
|
669
671
|
alias find_by_id record
|
670
672
|
|
671
673
|
def record_exists?(id)
|
672
674
|
!@doc.root.element("records/*[@id='#{id}']").nil?
|
673
675
|
end
|
674
|
-
|
676
|
+
|
675
677
|
def refresh()
|
676
678
|
@dirty_flag = true
|
677
679
|
end
|
678
|
-
|
680
|
+
|
679
681
|
def refresh!()
|
680
|
-
(load_records; rebuild_doc) if @dirty_flag == true
|
682
|
+
(load_records; rebuild_doc) if @dirty_flag == true
|
681
683
|
end
|
682
|
-
|
684
|
+
|
683
685
|
# used internally by to_rss()
|
684
686
|
#
|
685
687
|
def rss_xslt(opt={})
|
686
|
-
|
688
|
+
|
687
689
|
h = {limit: 11}.merge(opt)
|
688
690
|
doc = Rexle.new(self.to_xslt)
|
689
691
|
e = doc.element('//xsl:apply-templates[2]')
|
690
|
-
|
692
|
+
|
691
693
|
e2 = doc.root.element('xsl:template[3]')
|
692
694
|
item = e2.element('item')
|
693
695
|
new_item = item.deep_clone
|
694
696
|
item.delete
|
695
|
-
|
697
|
+
|
696
698
|
pubdate = @xslt_schema[/pubDate:/]
|
697
699
|
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
698
700
|
|
699
701
|
if pubdate.nil? then
|
700
702
|
pubdate = Rexle.new("<pubDate><xsl:value-of select='pubDate'>" + \
|
701
703
|
"</xsl:value-of></pubDate>").root
|
702
|
-
new_item.add pubdate
|
704
|
+
new_item.add pubdate
|
703
705
|
end
|
704
706
|
|
705
|
-
xslif.add new_item
|
707
|
+
xslif.add new_item
|
706
708
|
e2.add xslif.root
|
707
|
-
xslt = doc.xml
|
708
|
-
|
709
|
-
xslt
|
709
|
+
xslt = doc.xml
|
710
710
|
|
711
|
+
xslt
|
712
|
+
|
711
713
|
end
|
712
|
-
|
714
|
+
|
713
715
|
def filter(&blk)
|
714
|
-
|
716
|
+
|
715
717
|
dx = Dynarex.new @schema
|
716
718
|
self.all.select(&blk).each {|x| dx.create x}
|
717
719
|
dx
|
718
|
-
|
720
|
+
|
719
721
|
end
|
720
722
|
|
721
|
-
def to_xslt(opt={})
|
723
|
+
def to_xslt(opt={})
|
722
724
|
|
723
725
|
h = {limit: -1}.merge(opt)
|
724
726
|
@xslt_schema = @xslt_schema || self.summary[:xslt_schema]
|
725
727
|
raise 'to_xslt(): xslt_schema nil' unless @xslt_schema
|
728
|
+
puts 'to_xslt: ' + [@schema, @xslt_schema].inspect if @debug
|
726
729
|
|
727
730
|
xslt = DynarexXSLT.new(schema: @schema, xslt_schema: @xslt_schema ).to_xslt
|
728
731
|
|
729
732
|
return xslt
|
730
733
|
end
|
731
|
-
|
734
|
+
|
732
735
|
def to_rss(opt={}, xslt=nil)
|
733
|
-
|
736
|
+
|
734
737
|
puts 'inside to_rss'.info if @debug
|
738
|
+
puts 'xslt: ' + xslt.inspect if @debug
|
735
739
|
|
736
740
|
unless xslt then
|
737
|
-
|
741
|
+
|
738
742
|
h = {limit: 11}.merge(opt)
|
743
|
+
puts 'self.to_xslt:' + self.to_xslt.inspect if @debug
|
739
744
|
doc = Rexle.new(self.to_xslt)
|
745
|
+
puts 'doc: ' + doc.xml if @debug
|
746
|
+
puts 'after xslt doc' if @debug
|
740
747
|
e = doc.element('//xsl:apply-templates[2]')
|
741
748
|
|
742
749
|
e2 = doc.root.element('xsl:template[3]')
|
750
|
+
puts 'e2:' + e2.inspect if @debug
|
743
751
|
item = e2.element('item')
|
752
|
+
puts 'after item' if @debug
|
744
753
|
new_item = item.deep_clone
|
745
754
|
item.delete
|
746
|
-
|
755
|
+
|
747
756
|
pubdate = @xslt_schema[/pubDate:/]
|
748
|
-
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
749
|
-
|
750
757
|
|
758
|
+
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
759
|
+
|
760
|
+
|
751
761
|
if pubdate.nil? then
|
752
762
|
pubdate2 = Rexle.new("<pubDate><xsl:value-of select='pubDate'></xsl:value-of></pubDate>").root
|
753
|
-
new_item.add pubdate2
|
763
|
+
new_item.add pubdate2
|
754
764
|
end
|
755
765
|
|
756
|
-
xslif.add new_item
|
766
|
+
xslif.add new_item
|
757
767
|
e2.add xslif
|
758
|
-
xslt = doc.xml
|
768
|
+
xslt = doc.xml
|
759
769
|
|
760
770
|
xslt
|
761
771
|
end
|
762
|
-
|
772
|
+
|
763
773
|
puts 'before self.to_xml' if @debug
|
764
774
|
doc = Rexle.new(self.to_xml)
|
765
|
-
|
775
|
+
|
766
776
|
puts ('pubdate: ' + pubdate.inspect).debug if @debug
|
767
|
-
|
777
|
+
|
768
778
|
if pubdate.nil? then
|
769
779
|
doc.root.xpath('records/*').each do |x|
|
770
780
|
raw_dt = DateTime.parse x.attributes[:created]
|
771
781
|
dt = raw_dt.strftime("%a, %d %b %Y %H:%M:%S %z")
|
772
|
-
x.add Rexle::Element.new('pubDate').add_text dt.to_s
|
782
|
+
x.add Rexle::Element.new('pubDate').add_text dt.to_s
|
773
783
|
end
|
774
784
|
end
|
775
785
|
|
@@ -777,7 +787,7 @@ EOF
|
|
777
787
|
#File.write '/tmp/blog.xml', doc.root.xml
|
778
788
|
#puts ('xslt:' + xslt.inspect) if @debug
|
779
789
|
#File.write '/tmp/blog.xslt', xslt
|
780
|
-
|
790
|
+
|
781
791
|
puts 'before Rexslt' if @debug
|
782
792
|
out = Rexslt.new(xslt, doc).to_s(declaration: false)
|
783
793
|
puts 'after Rexslt' if @debug
|
@@ -790,23 +800,23 @@ EOF
|
|
790
800
|
xml = doc.xml(pretty: true)
|
791
801
|
xml
|
792
802
|
end
|
793
|
-
|
803
|
+
|
794
804
|
def unique=(bool)
|
795
805
|
self.summary.merge!({unique: bool})
|
796
806
|
@dirty_flag = true
|
797
807
|
@unique = bool
|
798
808
|
end
|
799
|
-
|
809
|
+
|
800
810
|
def xpath(x)
|
801
811
|
@doc.root.xpath x
|
802
812
|
end
|
803
813
|
|
804
814
|
def xslt=(value)
|
805
|
-
|
815
|
+
|
806
816
|
self.summary.merge!({xslt: value})
|
807
817
|
@dirty_flag = true
|
808
818
|
@xslt = value
|
809
|
-
end
|
819
|
+
end
|
810
820
|
|
811
821
|
private
|
812
822
|
|
@@ -814,7 +824,7 @@ EOF
|
|
814
824
|
@default_key = :uid
|
815
825
|
@summary[:default_key] = 'uid'
|
816
826
|
@fields << :uid
|
817
|
-
a.each.with_index{|x,i| x << (i+1).to_s}
|
827
|
+
a.each.with_index{|x,i| x << (i+1).to_s}
|
818
828
|
end
|
819
829
|
|
820
830
|
def create_find(fields)
|
@@ -860,9 +870,9 @@ EOF
|
|
860
870
|
end
|
861
871
|
|
862
872
|
def recordx_to_record(recordx)
|
863
|
-
|
873
|
+
|
864
874
|
h = recordx.attributes
|
865
|
-
|
875
|
+
|
866
876
|
records = recordx.xpath("*").map {|x| x.text ? x.text.unescape.to_s : '' }
|
867
877
|
hash = @fields.zip(records).to_h
|
868
878
|
RecordX.new(hash, self, h[:id], h[:created], h[:last_modified])
|
@@ -884,21 +894,21 @@ EOF
|
|
884
894
|
fields.keys.each {|key| fields[key] = params[key.to_sym] if params.has_key? key.to_sym}
|
885
895
|
fields
|
886
896
|
end
|
887
|
-
|
897
|
+
|
888
898
|
def display_xml(options={})
|
889
899
|
#@logger.debug 'inside display_xml'
|
890
900
|
opt = {unescape_html: false}.merge options
|
891
|
-
|
901
|
+
|
892
902
|
state = :external
|
893
903
|
#@logger.debug 'before diry'
|
894
904
|
if @dirty_flag == true then
|
895
|
-
load_records
|
905
|
+
load_records
|
896
906
|
state = :internal
|
897
907
|
end
|
898
908
|
#@logger.debug 'before rebuilt'
|
899
909
|
doc = rebuild_doc(state)
|
900
910
|
#@logger.debug 'after rebuild_doc'
|
901
|
-
|
911
|
+
|
902
912
|
if opt[:unescape_html] == true then
|
903
913
|
doc.content(opt)
|
904
914
|
else
|
@@ -912,15 +922,15 @@ EOF
|
|
912
922
|
raw_params.merge!(uid: id) if @default_key.to_sym == :uid
|
913
923
|
params = Hash[raw_params.keys.map(&:to_sym).zip(raw_params.values)]
|
914
924
|
|
915
|
-
fields = capture_fields(params)
|
925
|
+
fields = capture_fields(params)
|
916
926
|
record = Rexle::Element.new @record_name
|
917
927
|
|
918
928
|
fields.each do |k,v|
|
919
|
-
element = Rexle::Element.new(k.to_s)
|
929
|
+
element = Rexle::Element.new(k.to_s)
|
920
930
|
element.root.text = v.to_s.gsub('<','<').gsub('>','>') if v
|
921
931
|
record.add element if record
|
922
932
|
end
|
923
|
-
|
933
|
+
|
924
934
|
attributes = {id: id.to_s, created: Time.now.to_s, last_modified: nil}\
|
925
935
|
.merge attr
|
926
936
|
attributes.each {|k,v| record.add_attribute(k, v)}
|
@@ -937,7 +947,7 @@ EOF
|
|
937
947
|
buffer = RXFReader.read(line.chomp, auto: false).first
|
938
948
|
|
939
949
|
doc = Rexle.new buffer
|
940
|
-
|
950
|
+
|
941
951
|
if doc.root.name == 'kvx' then
|
942
952
|
|
943
953
|
kvx = Kvx.new doc
|
@@ -949,17 +959,17 @@ EOF
|
|
949
959
|
end
|
950
960
|
|
951
961
|
end
|
952
|
-
|
962
|
+
|
953
963
|
def rebuild_doc(state=:internal)
|
954
|
-
|
964
|
+
|
955
965
|
puts 'inside rebuild_doc'.info if @debug
|
956
966
|
|
957
|
-
reserved_keywords = (
|
967
|
+
reserved_keywords = (
|
958
968
|
Object.public_methods | \
|
959
969
|
Kernel.public_methods | \
|
960
970
|
public_methods + [:method_missing]
|
961
971
|
)
|
962
|
-
|
972
|
+
|
963
973
|
xml = RexleBuilder.new
|
964
974
|
|
965
975
|
a = xml.send @root_name do
|
@@ -985,33 +995,33 @@ EOF
|
|
985
995
|
#jr160315records.reverse! if @order == 'descending' and state == :external
|
986
996
|
|
987
997
|
xml.records do
|
988
|
-
|
998
|
+
|
989
999
|
records.each do |k, item|
|
990
|
-
|
1000
|
+
|
991
1001
|
attributes = {}
|
992
|
-
|
1002
|
+
|
993
1003
|
item.keys.each do |key|
|
994
1004
|
attributes[key] = item[key] || '' unless key == :body
|
995
1005
|
end
|
996
|
-
|
1006
|
+
|
997
1007
|
if @record_name.nil? then
|
998
1008
|
raise DynarexException, 'record_name can\'t be nil. Check the schema'
|
999
1009
|
end
|
1000
|
-
|
1010
|
+
|
1001
1011
|
puts 'attributes: ' + attributes.inspect if @debug
|
1002
1012
|
puts '@record_name: ' + @record_name.inspect if @debug
|
1003
1013
|
|
1004
1014
|
xml.send(@record_name, attributes) do
|
1005
|
-
item[:body].each do |name,value|
|
1015
|
+
item[:body].each do |name,value|
|
1006
1016
|
|
1007
1017
|
if reserved_keywords.include? name then
|
1008
|
-
name = ('._' + name.to_s).to_sym
|
1018
|
+
name = ('._' + name.to_s).to_sym
|
1009
1019
|
end
|
1010
|
-
|
1020
|
+
|
1011
1021
|
val = value.send(value.is_a?(String) ? :to_s : :to_yaml)
|
1012
1022
|
xml.send(name, val.gsub('>','>')\
|
1013
1023
|
.gsub('<','<')\
|
1014
|
-
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
1024
|
+
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
1015
1025
|
x[-1] == ';' ? x : x.sub('&','&')
|
1016
1026
|
end
|
1017
1027
|
)
|
@@ -1026,24 +1036,24 @@ EOF
|
|
1026
1036
|
end
|
1027
1037
|
|
1028
1038
|
doc = Rexle.new(a)
|
1029
|
-
|
1039
|
+
|
1030
1040
|
puts ('@xslt: ' + @xslt.inspect).debug if @debug
|
1031
|
-
|
1041
|
+
|
1032
1042
|
if @xslt then
|
1033
|
-
doc.instructions = [['xml-stylesheet',
|
1043
|
+
doc.instructions = [['xml-stylesheet',
|
1034
1044
|
"title='XSL_formatting' type='text/xsl' href='#{@xslt}'"]]
|
1035
1045
|
end
|
1036
1046
|
|
1037
1047
|
return doc if state != :internal
|
1038
1048
|
@doc = doc
|
1039
|
-
end
|
1040
|
-
|
1049
|
+
end
|
1050
|
+
|
1041
1051
|
def string_parse(buffer)
|
1042
1052
|
|
1043
1053
|
return openx(buffer.clone) if buffer[/<\?xml/]
|
1044
1054
|
|
1045
1055
|
if @spaces_delimited then
|
1046
|
-
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1056
|
+
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1047
1057
|
end
|
1048
1058
|
|
1049
1059
|
buffer.gsub!("\r",'')
|
@@ -1060,19 +1070,19 @@ EOF
|
|
1060
1070
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1061
1071
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1062
1072
|
@raw_header = buffer.slice!(/<\?dynarex[^>]+>/) + "\n"
|
1063
|
-
|
1073
|
+
|
1064
1074
|
header = @raw_header[/<?dynarex (.*)?>/,1]
|
1065
1075
|
|
1066
1076
|
r1 = /([\w\-]+\s*\=\s*'[^']*)'/
|
1067
1077
|
r2 = /([\w\-]+\s*\=\s*"[^"]*)"/
|
1068
1078
|
|
1069
|
-
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1079
|
+
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1070
1080
|
|
1071
1081
|
r.each do |x|
|
1072
1082
|
|
1073
1083
|
attr, val = x.split(/\s*=\s*["']/,2)
|
1074
1084
|
name = (attr + '=').to_sym
|
1075
|
-
|
1085
|
+
|
1076
1086
|
if self.public_methods.include? name then
|
1077
1087
|
self.method(name).call(unescape val)
|
1078
1088
|
else
|
@@ -1092,7 +1102,7 @@ EOF
|
|
1092
1102
|
if raw_summary then
|
1093
1103
|
|
1094
1104
|
a_summary = raw_summary.split(',').map(&:strip)
|
1095
|
-
|
1105
|
+
|
1096
1106
|
@summary ||= {}
|
1097
1107
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1098
1108
|
|
@@ -1112,7 +1122,7 @@ EOF
|
|
1112
1122
|
@summary[:schema] = @schema
|
1113
1123
|
@summary[:format_mask] = @format_mask
|
1114
1124
|
@summary[:unique] = @unique if @unique
|
1115
|
-
|
1125
|
+
|
1116
1126
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1117
1127
|
|
1118
1128
|
lines = case raw_lines.first.rstrip
|
@@ -1122,10 +1132,10 @@ EOF
|
|
1122
1132
|
yaml = YAML.load raw_lines.join("\n")
|
1123
1133
|
|
1124
1134
|
yamlize = lambda {|x| (x.is_a? Array) ? x.to_yaml : x}
|
1125
|
-
|
1135
|
+
|
1126
1136
|
yprocs = {
|
1127
1137
|
Hash: lambda {|y|
|
1128
|
-
y.map do |k,v|
|
1138
|
+
y.map do |k,v|
|
1129
1139
|
procs = {Hash: proc {|x| x.values}, Array: proc {v}}
|
1130
1140
|
values = procs[v.class.to_s.to_sym].call(v).map(&yamlize)
|
1131
1141
|
[k, *values]
|
@@ -1134,23 +1144,23 @@ EOF
|
|
1134
1144
|
Array: lambda {|y| y.map {|x2| x2.map(&yamlize)} }
|
1135
1145
|
}
|
1136
1146
|
|
1137
|
-
yprocs[yaml.class.to_s.to_sym].call yaml
|
1138
|
-
|
1147
|
+
yprocs[yaml.class.to_s.to_sym].call yaml
|
1148
|
+
|
1139
1149
|
when '--+'
|
1140
1150
|
|
1141
1151
|
rowx(raw_lines)
|
1142
|
-
|
1152
|
+
|
1143
1153
|
when '--#'
|
1144
1154
|
|
1145
1155
|
self.summary[:rawdoc_type] = 'sectionx'
|
1146
1156
|
raw_lines.shift
|
1147
1157
|
|
1148
1158
|
raw_lines.join.lstrip.split(/(?=^#[^#])/).map {|x| [x.rstrip]}
|
1149
|
-
|
1159
|
+
|
1150
1160
|
else
|
1151
1161
|
|
1152
1162
|
raw_lines = raw_lines.join("\n").gsub(/^(\s*#[^\n]+|\n)/,'').lines.to_a
|
1153
|
-
|
1163
|
+
|
1154
1164
|
if @linked then
|
1155
1165
|
|
1156
1166
|
parse_links(raw_lines)
|
@@ -1159,42 +1169,42 @@ EOF
|
|
1159
1169
|
a2 = raw_lines.map.with_index do |x,i|
|
1160
1170
|
|
1161
1171
|
next if x[/^\s+$|\n\s*#/]
|
1162
|
-
|
1172
|
+
|
1163
1173
|
begin
|
1164
|
-
|
1174
|
+
|
1165
1175
|
field_names, field_values = RXRawLineParser.new(@format_mask).parse(x)
|
1166
1176
|
rescue
|
1167
1177
|
raise "input file parser error at line " + (i + 1).to_s + ' --> ' + x
|
1168
1178
|
end
|
1169
1179
|
field_values
|
1170
1180
|
end
|
1171
|
-
|
1181
|
+
|
1172
1182
|
a2.compact!
|
1173
1183
|
a3 = a2.compact.map(&:first)
|
1174
|
-
|
1184
|
+
|
1175
1185
|
if a3 != a3.uniq then
|
1176
|
-
|
1186
|
+
|
1177
1187
|
if @unique then
|
1178
1188
|
raise DynarexException, "Duplicate id found"
|
1179
1189
|
else
|
1180
|
-
add_id(a2)
|
1190
|
+
add_id(a2)
|
1181
1191
|
end
|
1182
|
-
|
1192
|
+
|
1183
1193
|
end
|
1184
|
-
|
1194
|
+
|
1185
1195
|
a2
|
1186
|
-
end
|
1196
|
+
end
|
1187
1197
|
|
1188
1198
|
end
|
1189
1199
|
|
1190
|
-
a = lines.map.with_index do |x,i|
|
1191
|
-
|
1200
|
+
a = lines.map.with_index do |x,i|
|
1201
|
+
|
1192
1202
|
created = Time.now.to_s
|
1193
1203
|
|
1194
1204
|
h = Hash[
|
1195
1205
|
@fields.zip(
|
1196
1206
|
x.map do |t|
|
1197
|
-
|
1207
|
+
|
1198
1208
|
t.to_s[/^---(?:\s|\n)/] ? YAML.load(t[/^---(?:\s|\n)(.*)/,1]) : unescape(t.to_s)
|
1199
1209
|
end
|
1200
1210
|
)
|
@@ -1216,12 +1226,12 @@ EOF
|
|
1216
1226
|
item[:body].each do |k,v|
|
1217
1227
|
h[key][:body][k.to_sym] = v
|
1218
1228
|
end
|
1219
|
-
else
|
1229
|
+
else
|
1220
1230
|
item[:id] = (@order == 'descending' ? (h2.count) - i : i+ 1).to_s
|
1221
1231
|
i += 1
|
1222
1232
|
h[key] = item.clone
|
1223
|
-
end
|
1224
|
-
end
|
1233
|
+
end
|
1234
|
+
end
|
1225
1235
|
|
1226
1236
|
h.each {|key, item| h.delete(key) if not h2.has_key? key}
|
1227
1237
|
|
@@ -1230,9 +1240,9 @@ EOF
|
|
1230
1240
|
rebuild_doc
|
1231
1241
|
self
|
1232
1242
|
end
|
1233
|
-
|
1243
|
+
|
1234
1244
|
def sort_records_by!(&element_blk)
|
1235
|
-
|
1245
|
+
|
1236
1246
|
refresh_doc
|
1237
1247
|
a = @doc.root.xpath('records/*').sort_by &element_blk
|
1238
1248
|
@doc.root.delete('records')
|
@@ -1245,36 +1255,36 @@ EOF
|
|
1245
1255
|
|
1246
1256
|
load_records if @dirty_flag
|
1247
1257
|
self
|
1248
|
-
end
|
1258
|
+
end
|
1249
1259
|
|
1250
1260
|
def unescape(s)
|
1251
1261
|
s.gsub('<', '<').gsub('>','>')
|
1252
1262
|
end
|
1253
1263
|
|
1254
1264
|
def dynarex_new(s, default_key: nil)
|
1255
|
-
|
1265
|
+
|
1256
1266
|
@schema = schema = s
|
1257
1267
|
@default_key = default_key if default_key
|
1258
|
-
|
1268
|
+
|
1259
1269
|
ptrn = %r((\w+)\[?([^\]]+)?\]?\/(\w+)\(([^\)]+)\))
|
1260
1270
|
|
1261
1271
|
if s.match(ptrn) then
|
1262
|
-
|
1263
|
-
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1272
|
+
|
1273
|
+
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1264
1274
|
reserved = %w(require parent gem)
|
1265
1275
|
|
1266
1276
|
raise 'reserved keyword: ' + record_name if reserved.include? record_name
|
1267
1277
|
summary, fields = [raw_summary || '',raw_fields].map {|x| x.split(/,/).map &:strip}
|
1268
|
-
|
1278
|
+
|
1269
1279
|
if fields.include? 'id' then
|
1270
|
-
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1280
|
+
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1271
1281
|
end
|
1272
|
-
|
1282
|
+
|
1273
1283
|
create_find fields
|
1274
|
-
|
1284
|
+
|
1275
1285
|
|
1276
1286
|
raise 'reserved keyword' if (fields & reserved).any?
|
1277
|
-
|
1287
|
+
|
1278
1288
|
else
|
1279
1289
|
ptrn = %r((\w+)\[?([^\]]+)?\]?)
|
1280
1290
|
@root_name, raw_summary = s.match(ptrn).captures
|
@@ -1297,36 +1307,36 @@ EOF
|
|
1297
1307
|
def attach_record_methods()
|
1298
1308
|
create_find @fields
|
1299
1309
|
end
|
1300
|
-
|
1310
|
+
|
1301
1311
|
def openx(s)
|
1302
1312
|
#@logger.debug 'inside openx'
|
1303
1313
|
if s[/</] then # xml
|
1304
1314
|
#@logger.debug 'regular string'
|
1305
1315
|
#@logger.debug 's: ' + s.inspect
|
1306
1316
|
buffer = s
|
1307
|
-
|
1317
|
+
|
1308
1318
|
elsif s[/[\[\(]/] # schema
|
1309
1319
|
|
1310
1320
|
dynarex_new(s)
|
1311
|
-
|
1321
|
+
|
1312
1322
|
elsif s[/^https?:\/\//] then # url
|
1313
1323
|
buffer, type = RXFReader.read s, {username: @username,
|
1314
|
-
password: @password, auto: false}
|
1324
|
+
password: @password, auto: false}
|
1315
1325
|
elsif s[/^dfs?:\/\//] or RXFReadWrite.fs[0..2] == 'dfs' then
|
1326
|
+
|
1327
|
+
@local_filepath = s
|
1316
1328
|
|
1317
|
-
|
1318
|
-
|
1319
|
-
if FileX.exists? s then
|
1329
|
+
if FileX.exist? s then
|
1320
1330
|
buffer = FileX.read(s).force_encoding("UTF-8")
|
1321
1331
|
elsif @schema
|
1322
|
-
dynarex_new @schema, default_key: @default_key
|
1332
|
+
dynarex_new @schema, default_key: @default_key
|
1323
1333
|
end
|
1324
|
-
|
1334
|
+
|
1325
1335
|
else # local file
|
1326
|
-
|
1336
|
+
|
1327
1337
|
@local_filepath = s
|
1328
|
-
|
1329
|
-
if File.
|
1338
|
+
|
1339
|
+
if File.exist? s then
|
1330
1340
|
buffer = File.read s
|
1331
1341
|
elsif @schema
|
1332
1342
|
dynarex_new @schema, default_key: @default_key
|
@@ -1335,18 +1345,18 @@ EOF
|
|
1335
1345
|
end
|
1336
1346
|
end
|
1337
1347
|
#@logger.debug 'buffer: ' + buffer[0..120]
|
1338
|
-
|
1348
|
+
|
1339
1349
|
return import(buffer) if buffer =~ /^<\?dynarex\b/
|
1340
1350
|
|
1341
1351
|
if buffer then
|
1342
1352
|
|
1343
1353
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1344
1354
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1345
|
-
|
1346
|
-
@doc = Rexle.new(buffer) unless @doc
|
1355
|
+
|
1356
|
+
@doc = Rexle.new(buffer) unless @doc
|
1347
1357
|
#@logger.debug 'openx/@doc : ' + @doc.xml.inspect
|
1348
1358
|
end
|
1349
|
-
|
1359
|
+
|
1350
1360
|
return if @doc.root.nil?
|
1351
1361
|
e = @doc.root.element('summary')
|
1352
1362
|
|
@@ -1355,20 +1365,20 @@ EOF
|
|
1355
1365
|
@summary = summary_to_h
|
1356
1366
|
|
1357
1367
|
summary_methods = (@summary.keys - self.public_methods)
|
1358
|
-
|
1368
|
+
|
1359
1369
|
summary_methods.each do |x|
|
1360
|
-
|
1370
|
+
|
1361
1371
|
instance_eval "
|
1362
|
-
|
1372
|
+
|
1363
1373
|
def #{x.to_sym}()
|
1364
1374
|
@summary[:#{x}]
|
1365
1375
|
end
|
1366
|
-
|
1376
|
+
|
1367
1377
|
def #{x.to_s}=(v)
|
1368
1378
|
@summary[:#{x}] = v
|
1369
1379
|
@doc.root.element('summary/#{x.to_s}').text = v
|
1370
1380
|
end
|
1371
|
-
"
|
1381
|
+
"
|
1372
1382
|
end
|
1373
1383
|
|
1374
1384
|
@order = @summary[:order] if @summary.has_key? :order
|
@@ -1390,7 +1400,7 @@ EOF
|
|
1390
1400
|
|
1391
1401
|
if @fields then
|
1392
1402
|
|
1393
|
-
@default_key = @fields[0] unless @default_key
|
1403
|
+
@default_key = @fields[0] unless @default_key
|
1394
1404
|
# load the record query handler methods
|
1395
1405
|
attach_record_methods
|
1396
1406
|
else
|
@@ -1398,46 +1408,46 @@ EOF
|
|
1398
1408
|
#jr080912 @default_key = @doc.root.xpath('records/*/*').first.name
|
1399
1409
|
@default_key = @doc.root.element('records/./.[1]').name
|
1400
1410
|
end
|
1401
|
-
|
1411
|
+
|
1402
1412
|
@summary[:default_key] = @default_key.to_s
|
1403
|
-
|
1413
|
+
|
1404
1414
|
if @doc.root.xpath('records/*').length > 0 then
|
1405
|
-
@record_name = @doc.root.element('records/*[1]').name
|
1415
|
+
@record_name = @doc.root.element('records/*[1]').name
|
1406
1416
|
#jr240913 load_records
|
1407
1417
|
@dirty_flag = true
|
1408
1418
|
end
|
1409
1419
|
|
1410
|
-
end
|
1420
|
+
end
|
1411
1421
|
|
1412
1422
|
def load_records
|
1413
|
-
|
1423
|
+
|
1414
1424
|
puts 'inside load_records'.info if @debug
|
1415
|
-
|
1425
|
+
|
1416
1426
|
@dirty_flag = false
|
1417
|
-
|
1427
|
+
|
1418
1428
|
if @summary[:order] then
|
1419
|
-
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1429
|
+
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1420
1430
|
sort_records_by! {|x| x.element(orderfield).text } if orderfield
|
1421
1431
|
end
|
1422
|
-
|
1432
|
+
|
1423
1433
|
@records = records_to_h
|
1424
|
-
|
1434
|
+
|
1425
1435
|
@records.instance_eval do
|
1426
1436
|
def delete_item(i)
|
1427
1437
|
self.delete self.keys[i]
|
1428
1438
|
end
|
1429
1439
|
end
|
1430
|
-
|
1440
|
+
|
1431
1441
|
#Returns a ready-only snapshot of records as a simple Hash.
|
1432
1442
|
@flat_records = @records.values.map{|x| x[:body]}
|
1433
1443
|
|
1434
1444
|
end
|
1435
|
-
|
1445
|
+
|
1436
1446
|
|
1437
1447
|
def display()
|
1438
1448
|
puts @doc.to_s
|
1439
1449
|
end
|
1440
|
-
|
1450
|
+
|
1441
1451
|
def records_to_h(order=:ascending)
|
1442
1452
|
|
1443
1453
|
i = @doc.root.xpath('max(records/*/attribute::id)') || 0
|
@@ -1458,25 +1468,25 @@ EOF
|
|
1458
1468
|
end
|
1459
1469
|
|
1460
1470
|
body = (@fields - ['uid']).inject({}) do |r,field|
|
1461
|
-
|
1471
|
+
|
1462
1472
|
node = row.element field.to_s
|
1463
1473
|
|
1464
1474
|
if node then
|
1465
1475
|
text = node.text ? node.text.unescape : ''
|
1466
1476
|
|
1467
|
-
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1477
|
+
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1468
1478
|
YAML.load(text[/^---(?:\s|\n)(.*)/,1]) : text)
|
1469
1479
|
else
|
1470
1480
|
r
|
1471
1481
|
end
|
1472
1482
|
end
|
1473
|
-
|
1483
|
+
|
1474
1484
|
body[:uid] = id if @default_key == 'uid'
|
1475
1485
|
|
1476
1486
|
attributes = row.attributes
|
1477
1487
|
result.merge body[@default_key.to_sym] => attributes.merge({id: id, body: body})
|
1478
1488
|
end
|
1479
|
-
|
1489
|
+
|
1480
1490
|
puts 'records_to_h a: ' + a.inspect if @debug
|
1481
1491
|
#@logger.debug 'a: ' + a.inspect
|
1482
1492
|
a
|
@@ -1492,29 +1502,29 @@ EOF
|
|
1492
1502
|
|
1493
1503
|
# get the fields
|
1494
1504
|
a4 = a3.map{|x| x.scan(/^\w+(?=:)/)}.flatten(1).uniq
|
1495
|
-
|
1505
|
+
|
1496
1506
|
abbrv_fields = a4.all? {|x| x.length == 1}
|
1497
1507
|
|
1498
1508
|
a5 = a3.map do |xlines|
|
1499
|
-
|
1509
|
+
|
1500
1510
|
puts 'xlines: ' + xlines.inspect if @debug
|
1501
|
-
|
1511
|
+
|
1502
1512
|
missing_fields = a4 - xlines.scan(/^\w+(?=:)/)
|
1503
1513
|
|
1504
1514
|
r = xlines.split(/\n(\w+:.*)/m)
|
1505
1515
|
puts 'r: ' + r.inspect if @debug
|
1506
|
-
|
1516
|
+
|
1507
1517
|
missing_fields.map!{|x| x + ":"}
|
1508
1518
|
key = (abbrv_fields ? @fields[0].to_s[0] : @fields.first.to_s) + ':'
|
1509
|
-
|
1519
|
+
|
1510
1520
|
if missing_fields.include? key
|
1511
1521
|
r.unshift key
|
1512
1522
|
missing_fields.delete key
|
1513
1523
|
end
|
1514
|
-
|
1524
|
+
|
1515
1525
|
r += missing_fields
|
1516
1526
|
r.join("\n")
|
1517
|
-
|
1527
|
+
|
1518
1528
|
end
|
1519
1529
|
puts 'a5: ' + a5.inspect if @debug
|
1520
1530
|
|
@@ -1526,22 +1536,22 @@ EOF
|
|
1526
1536
|
r << @fields.map do |field|
|
1527
1537
|
x.text(abbrv_fields ? field.to_s.chr : field.to_s )
|
1528
1538
|
end
|
1529
|
-
|
1539
|
+
|
1530
1540
|
end
|
1531
1541
|
|
1532
|
-
a2.compact!
|
1533
|
-
|
1534
|
-
# if there is no field value for the first field then
|
1542
|
+
a2.compact!
|
1543
|
+
|
1544
|
+
# if there is no field value for the first field then
|
1535
1545
|
# the default_key is invalid. The default_key is changed to an ID.
|
1536
1546
|
if a2.detect {|x| x.first == ''} then
|
1537
1547
|
add_id(a2)
|
1538
1548
|
else
|
1539
1549
|
|
1540
1550
|
a3 = a2.map(&:first)
|
1541
|
-
add_id(a2) if a3 != a3.uniq
|
1542
|
-
|
1551
|
+
add_id(a2) if a3 != a3.uniq
|
1552
|
+
|
1543
1553
|
end
|
1544
|
-
|
1554
|
+
|
1545
1555
|
a2
|
1546
1556
|
|
1547
1557
|
end
|
@@ -1577,13 +1587,13 @@ XSL
|
|
1577
1587
|
@doc = Rexle.new(Rexslt.new(xsl, self.to_xml).to_s)
|
1578
1588
|
@dirty_flag = true
|
1579
1589
|
end
|
1580
|
-
|
1590
|
+
|
1581
1591
|
def summary_to_h
|
1582
1592
|
|
1583
1593
|
h = {recordx_type: 'dynarex'}
|
1584
|
-
|
1594
|
+
|
1585
1595
|
@doc.root.xpath('summary/*').inject(h) do |r,node|
|
1586
|
-
r.merge node.name.to_s.to_sym =>
|
1596
|
+
r.merge node.name.to_s.to_sym =>
|
1587
1597
|
node.text ? node.text.unescape : node.text.to_s
|
1588
1598
|
end
|
1589
1599
|
end
|