kvx 0.9.10 → 1.0.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/kvx.rb +206 -141
  4. data.tar.gz.sig +0 -0
  5. metadata +11 -10
  6. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 109d12cb0e82c682e94c369c81726331070e2a7e57d6d88fea4c1701701c7c1e
4
- data.tar.gz: f84bdb9a378f13abb834f6e7be36924812ad1028b7c6846c002c44f3e4b69ead
3
+ metadata.gz: 59fe7880fcbc6fb271deaa4a861cc59bfbc5c5066ad1ce3bcf8f5118500772da
4
+ data.tar.gz: 80add92b8de605c41f52b3d980c1dbef1e0ab36528967ee4afd01f6d489aa29b
5
5
  SHA512:
6
- metadata.gz: 5769d109589a3c4d5d65131ef45cc78a27d3e63c82029a86d60cb12adcd2be2ec5da7b0c5fde77646fee357072fad8c58934ac1d413d97e2c313905c3cd8c709
7
- data.tar.gz: 56982a372339f230ea947a8ac0f2d0e0cd5e297c86b1cd4fd38aec1a0557e6a273bbe25e0cfc5c7cb959af73a56fcf972387ec595a73eae7327d49302bfaa19b
6
+ metadata.gz: c0c42b50055513832cd28efd095fd924359c396af986fc5769b28efb867bf64bcf1175653e1b414b5790184d9feba8500ff4b9a480128d3b38f6ada8e8db1bfa
7
+ data.tar.gz: cc230dcef1e3eeb604523676e1d335243706b86d691e210d2cc4fc82a81f14c33cefe1977fb1db1907d7634625b0f008748bdd118d30abfb5720fba0b2441ea0
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/kvx.rb CHANGED
@@ -16,7 +16,7 @@ hkey_gems
16
16
  require kvx
17
17
  class Kvx
18
18
  media_type kvx
19
- '
19
+ '
20
20
  end
21
21
  end
22
22
 
@@ -40,19 +40,19 @@ class Kvx
40
40
  @identifier = 'kvx'
41
41
  @summary = {}
42
42
  @ignore_blank_lines ||= false
43
-
43
+
44
44
  @attributes, @debug = attributes, debug
45
-
45
+
46
46
  h = {
47
- hash: :passthru,
48
- :'rexle::element' => :xml_to_h,
47
+ hash: :passthru,
48
+ :'rexle::element' => :xml_to_h,
49
49
  string: :parse_string,
50
50
  rexle: :doc_to_h,
51
51
  :"rexle::element::value" => :parse_string
52
52
  }
53
-
53
+
54
54
  if x then
55
-
55
+
56
56
  sym = h[x.class.to_s.downcase.to_sym]
57
57
  puts 'sym: ' + sym.inspect if @debug
58
58
  @body = method(sym).call x
@@ -60,132 +60,188 @@ class Kvx
60
60
  end
61
61
 
62
62
  end
63
-
63
+
64
64
  def import(s)
65
65
  @body = parse_string(s)
66
66
  methodize(@body)
67
67
  end
68
-
68
+
69
69
  def item()
70
70
  @body
71
71
  end
72
-
73
- alias body item
74
-
72
+
73
+ alias body item
74
+
75
75
  def save(filename)
76
76
  FileX.write filename, self.to_s
77
77
  end
78
-
79
- # flattening is helpful when passing the Hash object to
78
+
79
+ # flattening is helpful when passing the Hash object to
80
80
  # RecordX as a new record
81
81
  #
82
82
  def to_h(flatten: false)
83
-
83
+
84
84
  if @summary.empty? then
85
-
85
+
86
86
  deep_clone @body
87
-
87
+
88
88
  else
89
-
89
+
90
90
  if flatten then
91
91
  @summary.merge @body
92
92
  else
93
93
  {summary: deep_clone(@summary), body: deep_clone(@body)}
94
94
  end
95
-
95
+
96
96
  end
97
-
97
+
98
98
  end
99
-
99
+
100
100
  def to_doc()
101
-
101
+
102
102
  a = if @summary.empty? then
103
-
104
- [self.class.to_s.downcase, @attributes, '', *make_xml(@body)]
105
-
103
+
104
+ [self.class.to_s.downcase, @attributes, '', *make_xml(@body)]
105
+
106
106
  else
107
-
107
+
108
108
  summary = make_xml(@summary)
109
-
109
+
110
110
  tags_found = summary.assoc(:tags)
111
-
111
+
112
112
  if tags_found then
113
113
  tags = tags_found.pop
114
- tags_found.push *tags.split.map {|x| [:tag,{},x]}
114
+ tags_found.push *tags.split.map {|x| [:tag,{},x]}
115
115
  end
116
116
 
117
117
  summary = [:summary, {}, *summary]
118
-
118
+
119
119
  # -- use the nested description Hash object if there are multiple lines
120
120
  h = {}
121
-
121
+
122
122
  @body.each do |key, value|
123
-
123
+
124
124
  h[key] = value.is_a?(String) ? value : value[:description]
125
-
125
+
126
126
  end
127
-
127
+
128
128
  body = [:body, {}, *make_xml(h)]
129
- [self.class.to_s.downcase, @attributes, '', summary, body]
130
-
131
- end
132
-
129
+ [self.class.to_s.downcase, @attributes, '', summary, body]
130
+
131
+ end
132
+
133
133
  puts 'a: ' + a.inspect if @debug
134
134
  doc = Rexle.new a
135
135
  doc.instructions = @instructions || []
136
136
  doc
137
-
137
+
138
138
  end
139
-
139
+
140
140
  def to_s()
141
-
141
+
142
142
  header = ''
143
-
143
+
144
144
  if @header or (@summary and @summary.any?) then
145
-
145
+
146
146
  attr = @attributes ? ' ' + @attributes\
147
147
  .map {|x| "%s='%s'" % x }.join(' ') : ''
148
148
  header = '<?' + @identifier
149
149
  header += attr
150
150
  header += "?>\n"
151
-
151
+
152
152
  if @summary and @summary.any? then
153
153
  header += scan_to_s @summary
154
154
  header += "\n----------------------------------\n\n"
155
155
  end
156
-
156
+
157
157
  end
158
158
 
159
159
  # -- use the nested description Hash object if there are multiple lines
160
160
  h = {}
161
-
161
+
162
162
  @body.each do |key, value|
163
-
163
+
164
164
  h[key] = if value.is_a?(String) then
165
-
165
+
166
166
  if value.lines.length < 2 then
167
- value
167
+ value
168
168
  else
169
- "\n" + value.lines.map {|x| ' ' + x }.join
169
+ "\n" + value.lines.map {|x| ' ' + x }.join
170
170
  end
171
-
171
+
172
172
  else
173
173
  "\n" + value[:description].lines.map {|x| ' ' + x }.join
174
174
  end
175
-
176
- end
177
-
175
+
176
+ end
177
+
178
178
  header + scan_to_s(h)
179
179
 
180
- end
180
+ end
181
181
 
182
182
  def to_xml(options={pretty: true})
183
-
183
+
184
184
  doc = self.to_doc
185
185
  doc.xml(options)
186
186
 
187
187
  end
188
-
188
+
189
+ def to_xslt()
190
+
191
+ summary = self.summary.keys.map do |key|
192
+ " <xsl:element name='#{key}'><xsl:value-of select='#{key}' /></xsl:element>"
193
+ end.join("\n")
194
+
195
+ body = self.body.keys.map do |key|
196
+ " <xsl:element name='#{key}'><xsl:value-of select='#{key}' /></xsl:element>"
197
+ end.join("\n")
198
+
199
+ s = "
200
+ <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
201
+
202
+ <xsl:template match='kvx'>
203
+
204
+ <xsl:element name='kvx'>
205
+
206
+ <xsl:attribute name='created'>
207
+ <xsl:value-of select='@created'/>
208
+ </xsl:attribute>
209
+ <xsl:attribute name='last_modified'>
210
+ <xsl:value-of select='@last_modified'/>
211
+ </xsl:attribute>
212
+
213
+ <xsl:apply-templates select='summary' />
214
+ <xsl:apply-templates select='body' />
215
+
216
+ </xsl:element>
217
+
218
+ </xsl:template>
219
+
220
+ <xsl:template match='summary'>
221
+
222
+ <xsl:element name='summary'>
223
+
224
+ #{summary}
225
+
226
+ </xsl:element>
227
+
228
+ </xsl:template>
229
+
230
+ <xsl:template match='body'>
231
+
232
+ <xsl:element name='body'>
233
+
234
+ #{body}
235
+
236
+ </xsl:element>
237
+
238
+ </xsl:template>
239
+
240
+ </xsl:stylesheet>
241
+ "
242
+
243
+ end
244
+
189
245
  # used by RecordX to update a KVX record
190
246
  # id is unnecssary because there is only 1 record mapped to RecordX
191
247
  #
@@ -194,9 +250,9 @@ class Kvx
194
250
  end
195
251
 
196
252
  private
197
-
253
+
198
254
  def deep_clone(h)
199
-
255
+
200
256
  h.inject({}) do |r, x|
201
257
 
202
258
  h2 = if x.last.is_a? Hash then
@@ -206,31 +262,31 @@ class Kvx
206
262
  end
207
263
  r.merge h2[0] => h2[1]
208
264
  end
209
-
210
- end
211
-
265
+
266
+ end
267
+
212
268
  def doc_to_h(doc)
213
269
  xml_to_h(doc.root)
214
270
  end
215
271
 
216
272
  def get_attributes(raw_attributes)
217
- #
273
+ #
218
274
  r1 = /([\w\-:]+\='[^']*)'/
219
275
  r2 = /([\w\-:]+\="[^"]*)"/
220
-
276
+
221
277
  r = raw_attributes.scan(/#{r1}|#{r2}/).map(&:compact)\
222
278
  .flatten.inject(Attributes.new) do |r, x|
223
- attr_name, raw_val = x.split(/=/,2)
279
+ attr_name, raw_val = x.split(/=/,2)
224
280
  val = attr_name != 'class' ? raw_val[1..-1] : raw_val[1..-1].split
225
281
  r.merge(attr_name.to_sym => val)
226
282
  end
227
283
 
228
284
  return r
229
285
  end
230
-
286
+
231
287
  def hashify(e)
232
288
 
233
- v = if e.has_elements? then
289
+ v = if e.has_elements? then
234
290
  e.elements.inject({}) do |r, x|
235
291
  r.merge hashify(x)
236
292
  end
@@ -239,194 +295,203 @@ class Kvx
239
295
  end
240
296
 
241
297
  {e.name.to_sym => v}
242
- end
298
+ end
243
299
 
244
300
  def make_xml(h)
245
-
301
+
246
302
  puts 'inside make_xml: ' + h.inspect if @debug
247
303
  h2 = h.clone
248
304
  h2.each {|key,value| value.delete :items if value.is_a?(Hash) }
249
305
 
250
306
  RexleBuilder.new(h2, debug: false).to_a[3..-1]
251
307
  end
252
-
308
+
253
309
  def parse_string(s)
254
-
310
+
255
311
  buffer, type = RXFHelper.read(s)
256
312
  puts ('buffer: ' + buffer.inspect).debug if @debug
257
-
258
- if buffer.lstrip =~ /^<\?xml/ then
259
- doc = Rexle.new(buffer)
313
+
314
+ if buffer.force_encoding("UTF-8").lstrip =~ /^<\?xml/ then
315
+
316
+ s = buffer.force_encoding("UTF-8")
317
+ doc = Rexle.new(s)
260
318
  @instructions = doc.instructions
261
319
  puts '@instructions: ' + @instructions.inspect if @debug
320
+
262
321
  xml_to_h(doc.root)
322
+
263
323
  else
264
324
  parse_to_h(buffer)
265
325
  end
266
-
326
+
267
327
  end
268
-
328
+
269
329
  def methodize(h)
270
-
330
+
271
331
  h.each do |k,v|
332
+
272
333
  define_singleton_method(k){v} unless self.methods.include? k
273
- end
274
-
334
+
335
+ unless self.methods.include? (k.to_s + '=').to_sym then
336
+ define_singleton_method((k.to_s + '=').to_sym){|x| h[k] = x}
337
+ end
338
+
339
+ end
340
+
275
341
  end
276
342
 
277
343
  def parse_to_h(s, header_pattern: %r(^<\?kvx[\s\?]))
278
344
 
279
- raw_txt, _ = RXFHelper.read(s)
345
+ raw_txt, _ = RXFHelper.read(s).force_encoding("UTF-8")
280
346
 
281
- # does the raw_txt contain header information?
347
+ # does the raw_txt contain header information?
282
348
  a = s.strip.lines
283
349
 
284
350
  txt = if a[0] =~ header_pattern then
285
-
351
+
286
352
  raw_header = a.shift
287
353
  attr = get_attributes(raw_header)
288
-
354
+
289
355
  if attr[:created] then
290
356
  attr[:last_modified] = Time.now.to_s
291
357
  else
292
- attr[:created] = Time.now.to_s
358
+ attr[:created] = Time.now.to_s
293
359
  end
294
-
360
+
295
361
  @attributes.merge! attr
296
362
  @header = true
297
- body, summary = a.join.strip.split(/^----*$/).reverse
363
+ body, summary = a.join.strip.split(/^----*$/).reverse
298
364
  @summary = scan_to_h summary if summary
299
-
365
+
300
366
  body
301
367
  else
302
368
  raw_txt
303
369
  end
304
-
370
+
305
371
  scan_to_h(txt)
306
372
  end
307
373
 
308
374
  def passthru(x)
309
-
375
+
310
376
  if x[:summary] and x[:body]
311
377
  @summary = deep_clone x[:summary]
312
378
  deep_clone x[:body]
313
- else
379
+ else
314
380
  deep_clone x
315
381
  end
316
-
382
+
317
383
  end
318
-
384
+
319
385
  def pretty_print(a, indent='')
320
-
321
- a.map do |x|
386
+
387
+ a.map do |x|
322
388
  (x.is_a?(String) or x.nil?) ? x.to_s : pretty_print(x, indent + ' ')
323
389
  end.join("\n" + indent)
324
-
390
+
325
391
  end
326
-
327
-
392
+
393
+
328
394
  def scan_to_h(txt)
329
-
395
+
330
396
  txt.gsub!(/^\w+:(?=$)/,'\0 ')
331
397
  puts 'txt:' + txt.inspect if @debug
332
-
398
+
333
399
  # auto indent any multiline values which aren't already indented
334
-
400
+
335
401
  indent = ''
336
402
 
337
403
  lines = txt.gsub(/^-+$/m,'').lines.map do |line|
338
404
 
339
- if not line[/^ *\w+:|^ +/] then
405
+ if not line[/^ *[^:]+:|^ +/] then
340
406
  indent + ' ' + line
341
407
  else
342
408
  indent = line[/^ +/] || ''
343
409
  line
344
410
  end
345
411
 
346
- end
412
+ end
347
413
  puts ('lines: ' + lines.inspect).debug if @debug
348
-
414
+
349
415
  puts ('inside scan_to_h').info if @debug
350
- raw_a = LineTree.new(lines.join.gsub(/(^-*$)|(?<=\S) +#.*/,'').strip,
416
+ raw_a = LineTree.new(lines.join.gsub(/(^-*$)|(?<=\S) +#.*/,'').strip,
351
417
  ignore_blank_lines: @ignore_blank_lines).to_a
352
418
  puts ('raw_a: ' + raw_a.inspect).debug if @debug
353
-
354
- # if there are any orphan lines which aren't nested underneath a
419
+
420
+ # if there are any orphan lines which aren't nested underneath a
355
421
  # label, they will be fixed using the following statement
356
-
422
+
357
423
  a = raw_a.chunk {|x| x[0][/^[^:]+:/]}.inject([]) do |r,y|
358
424
 
359
-
425
+
360
426
  puts 'r: ' + r.inspect if @debug
361
-
427
+
362
428
  if r.last and !y.first[/[^:]+:/] then
363
429
  r.last << y.last[-1]
364
430
  else
365
431
  puts 'y: ' + y.inspect if @debug
366
432
  r << y.last[-1]
367
433
  end
368
-
434
+
369
435
  r
370
-
436
+
371
437
  end
372
438
 
373
439
  @body = a.inject({}) do |r, line|
374
-
440
+
375
441
  s = line.shift
376
442
  puts ('s: ' + s.inspect).debug if @debug
377
-
443
+
378
444
  if line.join.length > 0 then
379
-
445
+
380
446
  puts 'line: ' + line.inspect if @debug
381
-
382
- padding = line[0].length < 2 ? "\n" : "\n "
447
+
448
+ padding = line[0].length < 2 ? "\n" : "\n "
383
449
  s10 = line.map{|x| x.join(padding)}.join("\n")
384
-
450
+
385
451
  r2 = if s10[/^ *\w+:[\n ]/] then
386
-
452
+
387
453
  scan_to_h(s10)
388
-
454
+
389
455
  else
390
456
 
391
- desc = pretty_print(line).split(/\n(?=\w+: )/)
457
+ desc = pretty_print(line).split(/\n(?=\w+: )/)
392
458
 
393
459
  txt2, remaining = desc
394
460
 
395
- h = txt2.lines.inject([]) do |r, x|
461
+ h = txt2.lines.inject([]) do |r, x|
396
462
  x.chomp!
397
463
  x.length > 0 ? r << x : r
398
464
  end
399
-
465
+
400
466
  r3 = {description: txt2, items: h}
401
- puts 'remaining: ' + remaining.inspect if @debug
402
467
 
403
468
  if remaining then
404
469
  r3.merge!(scan_to_h remaining + "\n ")
405
470
  end
406
-
471
+
407
472
  r3
408
473
  end
409
474
 
410
475
  r.merge({s[/[^:]+/].to_sym => r2})
411
-
476
+
412
477
  else
413
-
478
+
414
479
  value, name = s.split(/: */,2).reverse
415
- name ||= 'description'
480
+ name ||= 'description'
416
481
  v = value =~ /^\{\s*\}$/ ? {} : value.to_s
417
-
482
+
418
483
  r.merge({name.to_sym => v})
419
- end
484
+ end
420
485
 
421
486
  end
422
-
487
+
423
488
  puts ('@body: ' + @body.inspect).debug if @debug
424
489
  @body
425
490
 
426
- end
427
-
428
- def scan_to_s(h, indent='')
429
-
491
+ end
492
+
493
+ def scan_to_s(h, indent='')
494
+
430
495
  a = h.inject([]) do |r, x|
431
496
  if x.last.is_a? Hash then
432
497
  r << x.first.to_s + ":\n" + scan_to_s(x.last, ' ')
@@ -434,27 +499,27 @@ class Kvx
434
499
  r << "%s%s: %s" % [indent, *x]
435
500
  end
436
501
  end
437
-
502
+
438
503
  @to_s = a.join("\n")
439
504
  end
440
-
505
+
441
506
  def xml_to_h(node)
442
-
507
+
443
508
  puts 'node: ' + node.xml.inspect if @debug
444
509
  @attributes = node.attributes.to_h
445
-
510
+
446
511
  summary = node.element('summary')
447
-
512
+
448
513
  if summary then
449
514
 
450
515
  etags = summary.element 'tags'
451
-
516
+
452
517
  if etags then
453
518
 
454
519
  tags = etags.xpath('tag/text()')
455
520
  etags.delete 'tag'
456
521
  etags.text = tags.join(' ') if tags.any?
457
-
522
+
458
523
  end
459
524
 
460
525
  @summary = hashify(summary)[:summary]
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kvx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.10
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -35,7 +35,7 @@ cert_chain:
35
35
  m/+jxdgFjKKGxeZqunu9cp5ca9wSjjtKh/VA/3xZtPwokCa7vCMB+ZxUP0jvd++u
36
36
  OTXy8k/zqddw/VfD/It1UUK4
37
37
  -----END CERTIFICATE-----
38
- date: 2021-06-06 00:00:00.000000000 Z
38
+ date: 2022-02-18 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: line-tree
@@ -46,7 +46,7 @@ dependencies:
46
46
  version: '0.9'
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 0.9.1
49
+ version: 0.9.3
50
50
  type: :runtime
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
@@ -56,29 +56,29 @@ dependencies:
56
56
  version: '0.9'
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 0.9.1
59
+ version: 0.9.3
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: rxfhelper
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '1.0'
66
+ version: '1.3'
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 1.0.0
69
+ version: 1.3.3
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: '1.0'
76
+ version: '1.3'
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: 1.0.0
79
+ version: 1.3.3
80
80
  description:
81
- email: james@jamesrobertson.eu
81
+ email: digital.robertson@gmail.com
82
82
  executables: []
83
83
  extensions: []
84
84
  extra_rdoc_files: []
@@ -103,7 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.1.2
106
+ rubyforge_project:
107
+ rubygems_version: 2.7.10
107
108
  signing_key:
108
109
  specification_version: 4
109
110
  summary: Kvx (Keys, Values, and XML) makes it convenient to store and retrieve the
metadata.gz.sig CHANGED
Binary file