dynarex 1.8.26 → 1.9.2

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