kvx 0.9.10 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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