dynarex 1.8.27 → 1.9.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 +342 -321
- 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,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,
|
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
|
|
@@ -98,7 +98,7 @@ class Dynarex
|
|
98
98
|
username, password, schema, 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
|
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,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,47 +728,47 @@ 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
748
|
xslif = Rexle.new("<xsl:if test='position() < #{h[:limit]}'/>").root
|
749
|
-
|
750
|
-
|
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
|
|
@@ -776,7 +776,7 @@ EOF
|
|
776
776
|
File.write '/tmp/blog.xml', doc.root.xml
|
777
777
|
puts ('xslt:' + xslt.inspect) if @debug
|
778
778
|
File.write '/tmp/blog.xslt', xslt
|
779
|
-
|
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,30 @@ 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
|
+
|
976
997
|
xml.send(@record_name, attributes) do
|
977
|
-
item[:body].each do |name,value|
|
998
|
+
item[:body].each do |name,value|
|
978
999
|
|
979
1000
|
if reserved_keywords.include? name then
|
980
|
-
name = ('._' + name.to_s).to_sym
|
1001
|
+
name = ('._' + name.to_s).to_sym
|
981
1002
|
end
|
982
|
-
|
1003
|
+
|
983
1004
|
val = value.send(value.is_a?(String) ? :to_s : :to_yaml)
|
984
1005
|
xml.send(name, val.gsub('>','>')\
|
985
1006
|
.gsub('<','<')\
|
986
|
-
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
1007
|
+
.gsub(/(&\s|&[a-zA-Z\.]+;?)/) do |x|
|
987
1008
|
x[-1] == ';' ? x : x.sub('&','&')
|
988
1009
|
end
|
989
1010
|
)
|
@@ -998,22 +1019,22 @@ EOF
|
|
998
1019
|
end
|
999
1020
|
|
1000
1021
|
doc = Rexle.new(a)
|
1001
|
-
|
1022
|
+
|
1002
1023
|
puts ('@xslt: ' + @xslt.inspect).debug if @debug
|
1003
|
-
|
1024
|
+
|
1004
1025
|
if @xslt then
|
1005
|
-
doc.instructions = [['xml-stylesheet',
|
1026
|
+
doc.instructions = [['xml-stylesheet',
|
1006
1027
|
"title='XSL_formatting' type='text/xsl' href='#{@xslt}'"]]
|
1007
1028
|
end
|
1008
1029
|
|
1009
1030
|
return doc if state != :internal
|
1010
1031
|
@doc = doc
|
1011
|
-
end
|
1012
|
-
|
1032
|
+
end
|
1033
|
+
|
1013
1034
|
def string_parse(buffer)
|
1014
|
-
|
1035
|
+
|
1015
1036
|
if @spaces_delimited then
|
1016
|
-
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1037
|
+
buffer = buffer.lines.map{|x| x.gsub(/\s{2,}/,' # ')}.join
|
1017
1038
|
end
|
1018
1039
|
|
1019
1040
|
buffer.gsub!("\r",'')
|
@@ -1024,25 +1045,25 @@ EOF
|
|
1024
1045
|
buffer.gsub!(/<./) {|x| x[1] != '?' ? x.sub(/</,'<') : x }
|
1025
1046
|
|
1026
1047
|
@raw_header = buffer[/<\?dynarex[^>]+>/]
|
1027
|
-
|
1048
|
+
|
1028
1049
|
if buffer[/<\?/] then
|
1029
1050
|
|
1030
1051
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1031
1052
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1032
1053
|
@raw_header = buffer.slice!(/<\?dynarex[^>]+>/) + "\n"
|
1033
|
-
|
1054
|
+
|
1034
1055
|
header = @raw_header[/<?dynarex (.*)?>/,1]
|
1035
1056
|
|
1036
1057
|
r1 = /([\w\-]+\s*\=\s*'[^']*)'/
|
1037
1058
|
r2 = /([\w\-]+\s*\=\s*"[^"]*)"/
|
1038
1059
|
|
1039
|
-
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1060
|
+
r = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten
|
1040
1061
|
|
1041
1062
|
r.each do |x|
|
1042
1063
|
|
1043
1064
|
attr, val = x.split(/\s*=\s*["']/,2)
|
1044
1065
|
name = (attr + '=').to_sym
|
1045
|
-
|
1066
|
+
|
1046
1067
|
if self.public_methods.include? name then
|
1047
1068
|
self.method(name).call(unescape val)
|
1048
1069
|
else
|
@@ -1062,7 +1083,7 @@ EOF
|
|
1062
1083
|
if raw_summary then
|
1063
1084
|
|
1064
1085
|
a_summary = raw_summary.split(',').map(&:strip)
|
1065
|
-
|
1086
|
+
|
1066
1087
|
@summary ||= {}
|
1067
1088
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1068
1089
|
|
@@ -1082,7 +1103,7 @@ EOF
|
|
1082
1103
|
@summary[:schema] = @schema
|
1083
1104
|
@summary[:format_mask] = @format_mask
|
1084
1105
|
@summary[:unique] = @unique if @unique
|
1085
|
-
|
1106
|
+
|
1086
1107
|
raw_lines.shift while raw_lines.first.strip.empty?
|
1087
1108
|
|
1088
1109
|
lines = case raw_lines.first.rstrip
|
@@ -1092,10 +1113,10 @@ EOF
|
|
1092
1113
|
yaml = YAML.load raw_lines.join("\n")
|
1093
1114
|
|
1094
1115
|
yamlize = lambda {|x| (x.is_a? Array) ? x.to_yaml : x}
|
1095
|
-
|
1116
|
+
|
1096
1117
|
yprocs = {
|
1097
1118
|
Hash: lambda {|y|
|
1098
|
-
y.map do |k,v|
|
1119
|
+
y.map do |k,v|
|
1099
1120
|
procs = {Hash: proc {|x| x.values}, Array: proc {v}}
|
1100
1121
|
values = procs[v.class.to_s.to_sym].call(v).map(&yamlize)
|
1101
1122
|
[k, *values]
|
@@ -1104,23 +1125,23 @@ EOF
|
|
1104
1125
|
Array: lambda {|y| y.map {|x2| x2.map(&yamlize)} }
|
1105
1126
|
}
|
1106
1127
|
|
1107
|
-
yprocs[yaml.class.to_s.to_sym].call yaml
|
1108
|
-
|
1128
|
+
yprocs[yaml.class.to_s.to_sym].call yaml
|
1129
|
+
|
1109
1130
|
when '--+'
|
1110
1131
|
|
1111
1132
|
rowx(raw_lines)
|
1112
|
-
|
1133
|
+
|
1113
1134
|
when '--#'
|
1114
1135
|
|
1115
1136
|
self.summary[:rawdoc_type] = 'sectionx'
|
1116
1137
|
raw_lines.shift
|
1117
1138
|
|
1118
1139
|
raw_lines.join.lstrip.split(/(?=^#[^#])/).map {|x| [x.rstrip]}
|
1119
|
-
|
1140
|
+
|
1120
1141
|
else
|
1121
1142
|
|
1122
1143
|
raw_lines = raw_lines.join("\n").gsub(/^(\s*#[^\n]+|\n)/,'').lines.to_a
|
1123
|
-
|
1144
|
+
|
1124
1145
|
if @linked then
|
1125
1146
|
|
1126
1147
|
parse_links(raw_lines)
|
@@ -1129,42 +1150,42 @@ EOF
|
|
1129
1150
|
a2 = raw_lines.map.with_index do |x,i|
|
1130
1151
|
|
1131
1152
|
next if x[/^\s+$|\n\s*#/]
|
1132
|
-
|
1153
|
+
|
1133
1154
|
begin
|
1134
|
-
|
1155
|
+
|
1135
1156
|
field_names, field_values = RXRawLineParser.new(@format_mask).parse(x)
|
1136
1157
|
rescue
|
1137
1158
|
raise "input file parser error at line " + (i + 1).to_s + ' --> ' + x
|
1138
1159
|
end
|
1139
1160
|
field_values
|
1140
1161
|
end
|
1141
|
-
|
1162
|
+
|
1142
1163
|
a2.compact!
|
1143
1164
|
a3 = a2.compact.map(&:first)
|
1144
|
-
|
1165
|
+
|
1145
1166
|
if a3 != a3.uniq then
|
1146
|
-
|
1167
|
+
|
1147
1168
|
if @unique then
|
1148
1169
|
raise DynarexException, "Duplicate id found"
|
1149
1170
|
else
|
1150
|
-
add_id(a2)
|
1171
|
+
add_id(a2)
|
1151
1172
|
end
|
1152
|
-
|
1173
|
+
|
1153
1174
|
end
|
1154
|
-
|
1175
|
+
|
1155
1176
|
a2
|
1156
|
-
end
|
1177
|
+
end
|
1157
1178
|
|
1158
1179
|
end
|
1159
1180
|
|
1160
|
-
a = lines.map.with_index do |x,i|
|
1161
|
-
|
1181
|
+
a = lines.map.with_index do |x,i|
|
1182
|
+
|
1162
1183
|
created = Time.now.to_s
|
1163
1184
|
|
1164
1185
|
h = Hash[
|
1165
1186
|
@fields.zip(
|
1166
1187
|
x.map do |t|
|
1167
|
-
|
1188
|
+
|
1168
1189
|
t.to_s[/^---(?:\s|\n)/] ? YAML.load(t[/^---(?:\s|\n)(.*)/,1]) : unescape(t.to_s)
|
1169
1190
|
end
|
1170
1191
|
)
|
@@ -1186,12 +1207,12 @@ EOF
|
|
1186
1207
|
item[:body].each do |k,v|
|
1187
1208
|
h[key][:body][k.to_sym] = v
|
1188
1209
|
end
|
1189
|
-
else
|
1210
|
+
else
|
1190
1211
|
item[:id] = (@order == 'descending' ? (h2.count) - i : i+ 1).to_s
|
1191
1212
|
i += 1
|
1192
1213
|
h[key] = item.clone
|
1193
|
-
end
|
1194
|
-
end
|
1214
|
+
end
|
1215
|
+
end
|
1195
1216
|
|
1196
1217
|
h.each {|key, item| h.delete(key) if not h2.has_key? key}
|
1197
1218
|
|
@@ -1200,9 +1221,9 @@ EOF
|
|
1200
1221
|
rebuild_doc
|
1201
1222
|
self
|
1202
1223
|
end
|
1203
|
-
|
1224
|
+
|
1204
1225
|
def sort_records_by!(&element_blk)
|
1205
|
-
|
1226
|
+
|
1206
1227
|
refresh_doc
|
1207
1228
|
a = @doc.root.xpath('records/*').sort_by &element_blk
|
1208
1229
|
@doc.root.delete('records')
|
@@ -1215,33 +1236,33 @@ EOF
|
|
1215
1236
|
|
1216
1237
|
load_records if @dirty_flag
|
1217
1238
|
self
|
1218
|
-
end
|
1239
|
+
end
|
1219
1240
|
|
1220
1241
|
def unescape(s)
|
1221
1242
|
s.gsub('<', '<').gsub('>','>')
|
1222
1243
|
end
|
1223
1244
|
|
1224
1245
|
def dynarex_new(s, default_key: nil)
|
1225
|
-
|
1246
|
+
|
1226
1247
|
@schema = schema = s
|
1227
1248
|
@default_key = default_key if default_key
|
1228
|
-
|
1249
|
+
|
1229
1250
|
ptrn = %r((\w+)\[?([^\]]+)?\]?\/(\w+)\(([^\)]+)\))
|
1230
1251
|
|
1231
1252
|
if s.match(ptrn) then
|
1232
|
-
|
1233
|
-
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1253
|
+
|
1254
|
+
@root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
1234
1255
|
summary, fields = [raw_summary || '',raw_fields].map {|x| x.split(/,/).map &:strip}
|
1235
|
-
|
1256
|
+
|
1236
1257
|
if fields.include? 'id' then
|
1237
|
-
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1258
|
+
raise 'Dynarex#dynarex_new: schema field id is a reserved keyword'
|
1238
1259
|
end
|
1239
|
-
|
1260
|
+
|
1240
1261
|
create_find fields
|
1241
|
-
|
1262
|
+
|
1242
1263
|
reserved = %w(require parent)
|
1243
1264
|
raise 'reserved keyword' if (fields & reserved).any?
|
1244
|
-
|
1265
|
+
|
1245
1266
|
else
|
1246
1267
|
ptrn = %r((\w+)\[?([^\]]+)?\]?)
|
1247
1268
|
@root_name, raw_summary = s.match(ptrn).captures
|
@@ -1264,36 +1285,36 @@ EOF
|
|
1264
1285
|
def attach_record_methods()
|
1265
1286
|
create_find @fields
|
1266
1287
|
end
|
1267
|
-
|
1288
|
+
|
1268
1289
|
def openx(s)
|
1269
1290
|
#@logger.debug 'inside openx'
|
1270
1291
|
if s[/</] then # xml
|
1271
1292
|
#@logger.debug 'regular string'
|
1272
1293
|
#@logger.debug 's: ' + s.inspect
|
1273
1294
|
buffer = s
|
1274
|
-
|
1295
|
+
|
1275
1296
|
elsif s[/[\[\(]/] # schema
|
1276
1297
|
|
1277
1298
|
dynarex_new(s)
|
1278
|
-
|
1299
|
+
|
1279
1300
|
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
|
1301
|
+
buffer, type = RXFHelper.read s, {username: @username,
|
1302
|
+
password: @password, auto: false}
|
1303
|
+
elsif s[/^dfs?:\/\//] then
|
1304
|
+
|
1305
|
+
@local_filepath = s
|
1285
1306
|
|
1286
1307
|
if FileX.exists? s then
|
1287
1308
|
buffer = FileX.read s
|
1288
1309
|
elsif @schema
|
1289
|
-
dynarex_new @schema, default_key: @default_key
|
1290
|
-
end
|
1291
|
-
|
1310
|
+
dynarex_new @schema, default_key: @default_key
|
1311
|
+
end
|
1312
|
+
|
1292
1313
|
else # local file
|
1293
|
-
|
1314
|
+
|
1294
1315
|
@local_filepath = s
|
1295
|
-
|
1296
|
-
if File.exists? s then
|
1316
|
+
|
1317
|
+
if File.exists? s then
|
1297
1318
|
buffer = File.read s
|
1298
1319
|
elsif @schema
|
1299
1320
|
dynarex_new @schema, default_key: @default_key
|
@@ -1302,18 +1323,18 @@ EOF
|
|
1302
1323
|
end
|
1303
1324
|
end
|
1304
1325
|
#@logger.debug 'buffer: ' + buffer[0..120]
|
1305
|
-
|
1326
|
+
|
1306
1327
|
return import(buffer) if buffer =~ /^<\?dynarex\b/
|
1307
1328
|
|
1308
1329
|
if buffer then
|
1309
1330
|
|
1310
1331
|
raw_stylesheet = buffer.slice!(/<\?xml-stylesheet[^>]+>/)
|
1311
1332
|
@xslt = raw_stylesheet[/href=["']([^"']+)/,1] if raw_stylesheet
|
1312
|
-
|
1313
|
-
@doc = Rexle.new(buffer) unless @doc
|
1333
|
+
|
1334
|
+
@doc = Rexle.new(buffer) unless @doc
|
1314
1335
|
#@logger.debug 'openx/@doc : ' + @doc.xml.inspect
|
1315
1336
|
end
|
1316
|
-
|
1337
|
+
|
1317
1338
|
return if @doc.root.nil?
|
1318
1339
|
e = @doc.root.element('summary')
|
1319
1340
|
|
@@ -1322,20 +1343,20 @@ EOF
|
|
1322
1343
|
@summary = summary_to_h
|
1323
1344
|
|
1324
1345
|
summary_methods = (@summary.keys - self.public_methods)
|
1325
|
-
|
1346
|
+
|
1326
1347
|
summary_methods.each do |x|
|
1327
|
-
|
1348
|
+
|
1328
1349
|
instance_eval "
|
1329
|
-
|
1350
|
+
|
1330
1351
|
def #{x.to_sym}()
|
1331
1352
|
@summary[:#{x}]
|
1332
1353
|
end
|
1333
|
-
|
1354
|
+
|
1334
1355
|
def #{x.to_s}=(v)
|
1335
1356
|
@summary[:#{x}] = v
|
1336
1357
|
@doc.root.element('summary/#{x.to_s}').text = v
|
1337
1358
|
end
|
1338
|
-
"
|
1359
|
+
"
|
1339
1360
|
end
|
1340
1361
|
|
1341
1362
|
@order = @summary[:order] if @summary.has_key? :order
|
@@ -1357,7 +1378,7 @@ EOF
|
|
1357
1378
|
|
1358
1379
|
if @fields then
|
1359
1380
|
|
1360
|
-
@default_key = @fields[0] unless @default_key
|
1381
|
+
@default_key = @fields[0] unless @default_key
|
1361
1382
|
# load the record query handler methods
|
1362
1383
|
attach_record_methods
|
1363
1384
|
else
|
@@ -1365,46 +1386,46 @@ EOF
|
|
1365
1386
|
#jr080912 @default_key = @doc.root.xpath('records/*/*').first.name
|
1366
1387
|
@default_key = @doc.root.element('records/./.[1]').name
|
1367
1388
|
end
|
1368
|
-
|
1389
|
+
|
1369
1390
|
@summary[:default_key] = @default_key.to_s
|
1370
|
-
|
1391
|
+
|
1371
1392
|
if @doc.root.xpath('records/*').length > 0 then
|
1372
|
-
@record_name = @doc.root.element('records/*[1]').name
|
1393
|
+
@record_name = @doc.root.element('records/*[1]').name
|
1373
1394
|
#jr240913 load_records
|
1374
1395
|
@dirty_flag = true
|
1375
1396
|
end
|
1376
1397
|
|
1377
|
-
end
|
1398
|
+
end
|
1378
1399
|
|
1379
1400
|
def load_records
|
1380
|
-
|
1401
|
+
|
1381
1402
|
puts 'inside load_records'.info if @debug
|
1382
|
-
|
1403
|
+
|
1383
1404
|
@dirty_flag = false
|
1384
|
-
|
1405
|
+
|
1385
1406
|
if @summary[:order] then
|
1386
|
-
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1407
|
+
orderfield = @summary[:order][/(\w+)\s+(?:ascending|descending)/,1]
|
1387
1408
|
sort_records_by! {|x| x.element(orderfield).text } if orderfield
|
1388
1409
|
end
|
1389
|
-
|
1410
|
+
|
1390
1411
|
@records = records_to_h
|
1391
|
-
|
1412
|
+
|
1392
1413
|
@records.instance_eval do
|
1393
1414
|
def delete_item(i)
|
1394
1415
|
self.delete self.keys[i]
|
1395
1416
|
end
|
1396
1417
|
end
|
1397
|
-
|
1418
|
+
|
1398
1419
|
#Returns a ready-only snapshot of records as a simple Hash.
|
1399
1420
|
@flat_records = @records.values.map{|x| x[:body]}
|
1400
1421
|
|
1401
1422
|
end
|
1402
|
-
|
1423
|
+
|
1403
1424
|
|
1404
1425
|
def display()
|
1405
1426
|
puts @doc.to_s
|
1406
1427
|
end
|
1407
|
-
|
1428
|
+
|
1408
1429
|
def records_to_h(order=:ascending)
|
1409
1430
|
|
1410
1431
|
i = @doc.root.xpath('max(records/*/attribute::id)') || 0
|
@@ -1425,25 +1446,25 @@ EOF
|
|
1425
1446
|
end
|
1426
1447
|
|
1427
1448
|
body = (@fields - ['uid']).inject({}) do |r,field|
|
1428
|
-
|
1449
|
+
|
1429
1450
|
node = row.element field.to_s
|
1430
1451
|
|
1431
1452
|
if node then
|
1432
1453
|
text = node.text ? node.text.unescape : ''
|
1433
1454
|
|
1434
|
-
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1455
|
+
r.merge node.name.to_sym => (text[/^---(?:\s|\n)/] ?
|
1435
1456
|
YAML.load(text[/^---(?:\s|\n)(.*)/,1]) : text)
|
1436
1457
|
else
|
1437
1458
|
r
|
1438
1459
|
end
|
1439
1460
|
end
|
1440
|
-
|
1461
|
+
|
1441
1462
|
body[:uid] = id if @default_key == 'uid'
|
1442
1463
|
|
1443
1464
|
attributes = row.attributes
|
1444
1465
|
result.merge body[@default_key.to_sym] => attributes.merge({id: id, body: body})
|
1445
1466
|
end
|
1446
|
-
|
1467
|
+
|
1447
1468
|
puts 'records_to_h a: ' + a.inspect if @debug
|
1448
1469
|
#@logger.debug 'a: ' + a.inspect
|
1449
1470
|
a
|
@@ -1459,56 +1480,56 @@ EOF
|
|
1459
1480
|
|
1460
1481
|
# get the fields
|
1461
1482
|
a4 = a3.map{|x| x.scan(/^\w+(?=:)/)}.flatten(1).uniq
|
1462
|
-
|
1483
|
+
|
1463
1484
|
abbrv_fields = a4.all? {|x| x.length == 1}
|
1464
|
-
|
1485
|
+
|
1465
1486
|
a5 = a3.map do |xlines|
|
1466
|
-
|
1487
|
+
|
1467
1488
|
puts 'xlines: ' + xlines.inspect if @debug
|
1468
|
-
|
1489
|
+
|
1469
1490
|
missing_fields = a4 - xlines.scan(/^\w+(?=:)/)
|
1470
1491
|
|
1471
1492
|
r = xlines.split(/\n(\w+:.*)/m)
|
1472
1493
|
puts 'r: ' + r.inspect if @debug
|
1473
|
-
|
1494
|
+
|
1474
1495
|
missing_fields.map!{|x| x + ":"}
|
1475
1496
|
key = (abbrv_fields ? @fields[0].to_s[0] : @fields.first.to_s) + ':'
|
1476
|
-
|
1497
|
+
|
1477
1498
|
if missing_fields.include? key
|
1478
1499
|
r.unshift key
|
1479
1500
|
missing_fields.delete key
|
1480
1501
|
end
|
1481
|
-
|
1502
|
+
|
1482
1503
|
r += missing_fields
|
1483
1504
|
r.join("\n")
|
1484
|
-
|
1505
|
+
|
1485
1506
|
end
|
1486
1507
|
puts 'a5: ' + a5.inspect if @debug
|
1487
|
-
|
1508
|
+
|
1488
1509
|
xml = RowX.new(a5.join("\n").strip, level: 0).to_xml
|
1489
1510
|
puts 'xml: ' + xml.inspect if @debug
|
1490
|
-
|
1491
|
-
a2 = Rexle.new(xml).root.xpath('item').inject([]) do |r,x|
|
1511
|
+
|
1512
|
+
a2 = Rexle.new(xml).root.xpath('item').inject([]) do |r,x|
|
1492
1513
|
|
1493
1514
|
r << @fields.map do |field|
|
1494
1515
|
x.text(abbrv_fields ? field.to_s.chr : field.to_s )
|
1495
1516
|
end
|
1496
|
-
|
1517
|
+
|
1497
1518
|
end
|
1498
1519
|
|
1499
|
-
a2.compact!
|
1500
|
-
|
1501
|
-
# if there is no field value for the first field then
|
1520
|
+
a2.compact!
|
1521
|
+
|
1522
|
+
# if there is no field value for the first field then
|
1502
1523
|
# the default_key is invalid. The default_key is changed to an ID.
|
1503
1524
|
if a2.detect {|x| x.first == ''} then
|
1504
1525
|
add_id(a2)
|
1505
1526
|
else
|
1506
1527
|
|
1507
1528
|
a3 = a2.map(&:first)
|
1508
|
-
add_id(a2) if a3 != a3.uniq
|
1509
|
-
|
1529
|
+
add_id(a2) if a3 != a3.uniq
|
1530
|
+
|
1510
1531
|
end
|
1511
|
-
|
1532
|
+
|
1512
1533
|
a2
|
1513
1534
|
|
1514
1535
|
end
|
@@ -1544,13 +1565,13 @@ XSL
|
|
1544
1565
|
@doc = Rexle.new(Rexslt.new(xsl, self.to_xml).to_s)
|
1545
1566
|
@dirty_flag = true
|
1546
1567
|
end
|
1547
|
-
|
1568
|
+
|
1548
1569
|
def summary_to_h
|
1549
1570
|
|
1550
1571
|
h = {recordx_type: 'dynarex'}
|
1551
|
-
|
1572
|
+
|
1552
1573
|
@doc.root.xpath('summary/*').inject(h) do |r,node|
|
1553
|
-
r.merge node.name.to_s.to_sym =>
|
1574
|
+
r.merge node.name.to_s.to_sym =>
|
1554
1575
|
node.text ? node.text.unescape : node.text.to_s
|
1555
1576
|
end
|
1556
1577
|
end
|