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