flor 0.0.1 → 0.9.0

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 (84) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/LICENSE.txt +1 -1
  3. data/Makefile +66 -0
  4. data/README.md +57 -0
  5. data/fail.txt +7 -0
  6. data/flor.gemspec +12 -9
  7. data/intercepted.txt +123 -0
  8. data/lib/flor/colours.rb +140 -0
  9. data/lib/flor/conf.rb +88 -0
  10. data/lib/flor/core/executor.rb +473 -0
  11. data/lib/flor/core/node.rb +397 -0
  12. data/lib/flor/core/procedure.rb +600 -0
  13. data/lib/flor/core/texecutor.rb +209 -0
  14. data/lib/flor/core.rb +93 -0
  15. data/lib/flor/dollar.rb +248 -0
  16. data/lib/flor/errors.rb +36 -0
  17. data/lib/flor/flor.rb +556 -0
  18. data/lib/flor/log.rb +336 -0
  19. data/lib/flor/migrations/0001_tables.rb +122 -0
  20. data/lib/flor/parser.rb +414 -0
  21. data/lib/flor/pcore/_arr.rb +49 -0
  22. data/lib/flor/pcore/_atom.rb +43 -0
  23. data/lib/flor/pcore/_att.rb +160 -0
  24. data/lib/flor/pcore/_dump.rb +60 -0
  25. data/lib/flor/pcore/_err.rb +30 -0
  26. data/lib/flor/pcore/_happly.rb +73 -0
  27. data/lib/flor/pcore/_obj.rb +65 -0
  28. data/lib/flor/pcore/_skip.rb +63 -0
  29. data/lib/flor/pcore/apply.rb +60 -0
  30. data/lib/flor/pcore/arith.rb +46 -0
  31. data/lib/flor/pcore/break.rb +71 -0
  32. data/lib/flor/pcore/cmp.rb +72 -0
  33. data/lib/flor/pcore/cond.rb +57 -0
  34. data/lib/flor/pcore/cursor.rb +223 -0
  35. data/lib/flor/pcore/define.rb +96 -0
  36. data/lib/flor/pcore/fail.rb +45 -0
  37. data/lib/flor/pcore/ife.rb +56 -0
  38. data/lib/flor/pcore/loop.rb +53 -0
  39. data/lib/flor/pcore/map.rb +75 -0
  40. data/lib/flor/pcore/match.rb +70 -0
  41. data/lib/flor/pcore/move.rb +65 -0
  42. data/lib/flor/pcore/noeval.rb +46 -0
  43. data/lib/flor/pcore/noret.rb +47 -0
  44. data/lib/flor/pcore/push.rb +69 -0
  45. data/lib/flor/pcore/sequence.rb +39 -0
  46. data/lib/flor/pcore/set.rb +76 -0
  47. data/lib/flor/pcore/stall.rb +35 -0
  48. data/lib/flor/pcore/until.rb +122 -0
  49. data/lib/flor/pcore/val.rb +40 -0
  50. data/lib/flor/punit/cancel.rb +69 -0
  51. data/lib/flor/punit/cmap.rb +76 -0
  52. data/lib/flor/punit/concurrence.rb +149 -0
  53. data/lib/flor/punit/every.rb +46 -0
  54. data/lib/flor/punit/on.rb +81 -0
  55. data/lib/flor/punit/schedule.rb +68 -0
  56. data/lib/flor/punit/signal.rb +47 -0
  57. data/lib/flor/punit/sleep.rb +53 -0
  58. data/lib/flor/punit/task.rb +109 -0
  59. data/lib/flor/punit/trace.rb +51 -0
  60. data/lib/flor/punit/trap.rb +100 -0
  61. data/lib/flor/to_string.rb +81 -0
  62. data/lib/flor/tools/env.rb +103 -0
  63. data/lib/flor/tools/repl.rb +231 -0
  64. data/lib/flor/unit/executor.rb +260 -0
  65. data/lib/flor/unit/hooker.rb +186 -0
  66. data/lib/flor/unit/journal.rb +52 -0
  67. data/lib/flor/unit/loader.rb +181 -0
  68. data/lib/flor/unit/logger.rb +181 -0
  69. data/lib/flor/unit/models/execution.rb +105 -0
  70. data/lib/flor/unit/models/pointer.rb +31 -0
  71. data/lib/flor/unit/models/timer.rb +52 -0
  72. data/lib/flor/unit/models/trace.rb +31 -0
  73. data/lib/flor/unit/models/trap.rb +130 -0
  74. data/lib/flor/unit/models.rb +106 -0
  75. data/lib/flor/unit/scheduler.rb +419 -0
  76. data/lib/flor/unit/storage.rb +633 -0
  77. data/lib/flor/unit/tasker.rb +191 -0
  78. data/lib/flor/unit/waiter.rb +146 -0
  79. data/lib/flor/unit/wlist.rb +77 -0
  80. data/lib/flor/unit.rb +50 -0
  81. data/lib/flor.rb +40 -3
  82. metadata +152 -22
  83. checksums.yaml +0 -7
  84. data/Rakefile +0 -52
data/lib/flor/flor.rb ADDED
@@ -0,0 +1,556 @@
1
+ #--
2
+ # Copyright (c) 2015-2017, John Mettraux, jmettraux+flor@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Flor
27
+
28
+ #
29
+ # deep
30
+ #
31
+ # functions for deep getting/setting in structures
32
+
33
+ def self.to_index(s)
34
+
35
+ return 0 if s == 'first'
36
+ return -1 if s == 'last'
37
+
38
+ i = s.to_i
39
+ return nil if i.to_s != s
40
+
41
+ i
42
+ end
43
+
44
+ def self.to_a(o)
45
+
46
+ o.nil? ? nil : Array(o)
47
+ end
48
+
49
+ def self.deep_get(o, k) # --> success(boolean), value
50
+
51
+ return [ true, o ] unless k
52
+
53
+ val = o
54
+ ks = k.split('.')
55
+
56
+ loop do
57
+
58
+ break unless kk = ks.shift
59
+
60
+ case val
61
+ when Array
62
+ i = to_index(kk)
63
+ return [ false, nil ] unless i
64
+ val = val[i]
65
+ when Hash
66
+ val = val[kk]
67
+ else
68
+ return [ false, nil ]
69
+ end
70
+ end
71
+
72
+ [ true, val ]
73
+ end
74
+
75
+ def self.deep_set(o, k, v) # --> [ success(boolean), value ]
76
+
77
+ lastdot = k.rindex('.')
78
+ path = lastdot && k[0..lastdot - 1]
79
+ key = lastdot ? k[lastdot + 1..-1] : k
80
+
81
+ b, col = deep_get(o, path)
82
+
83
+ return [ false, v ] unless b
84
+
85
+ case col
86
+ when Array
87
+ i = to_index(key)
88
+ return [ false, v ] unless i
89
+ col[i] = v
90
+ when Hash
91
+ col[key] = v
92
+ else
93
+ return [ false, v ]
94
+ end
95
+
96
+ [ true, v ]
97
+ end
98
+
99
+ def self.deep_has_key?(o, k)
100
+
101
+ val = o
102
+ ks = k.split('.')
103
+
104
+ loop do
105
+
106
+ kk = ks.shift
107
+
108
+ case val
109
+ when Array
110
+ i = to_index(kk)
111
+ return false unless i
112
+ return (i < 0 ? -i < val.length : i < val.length) if ks.empty?
113
+ val = val[i]
114
+ when Hash
115
+ return val.has_key?(kk) if ks.empty?
116
+ val = val[kk]
117
+ else
118
+ return false
119
+ end
120
+ end
121
+ end
122
+
123
+ #
124
+ # djan
125
+ #
126
+ # functions about the "djan" silly version of JSON
127
+
128
+ def self.to_djan(x, opts={})
129
+
130
+ opts[:cl] = opts[:color] || opts[:colour]
131
+
132
+ r =
133
+ case x
134
+ when nil then 'null'
135
+ when String then string_to_d(x, opts)
136
+ when Hash then object_to_d(x, opts)
137
+ when Array then array_to_d(x, opts)
138
+ when TrueClass then c_tru(x.to_s, opts)
139
+ when FalseClass then c_tru(x.to_s, opts)
140
+ else c_num(x.to_s, opts)
141
+ end
142
+ if opts[:inner]
143
+ opts.delete(:inner)
144
+ r = r[1..-2] if r[0, 1] == '[' || r[0, 1] == '{'
145
+ end
146
+ r
147
+ end
148
+
149
+ def self.s_to_d(x, opts={})
150
+
151
+ x.is_a?(String) ? x : to_djan(x, opts)
152
+ end
153
+
154
+ class << self
155
+
156
+ alias to_d to_djan
157
+
158
+ protected # somehow
159
+
160
+ # Black 0;30 Dark Gray 1;30
161
+ # Blue 0;34 Light Blue 1;34
162
+ # Green 0;32 Light Green 1;32
163
+ # Cyan 0;36 Light Cyan 1;36
164
+ # Red 0;31 Light Red 1;31
165
+ # Purple 0;35 Light Purple 1;35
166
+ # Brown 0;33 Yellow 1;33
167
+ # Light Gray 0;37 White 1;37
168
+
169
+ def c_inf(s, opts); opts[:cl] ? "#{s}" : s; end
170
+ def c_str(s, opts); opts[:cl] ? "#{s}" : s; end
171
+ def c_tru(s, opts); opts[:cl] ? "#{s}" : s; end
172
+ def c_fal(s, opts); opts[:cl] ? "#{s}" : s; end
173
+ def c_num(s, opts); opts[:cl] ? "#{s}" : s; end
174
+
175
+ def c_key(s, opts)
176
+
177
+ return s unless opts[:cl]
178
+
179
+ s.match(/\A".*"\z/) ?
180
+ "#{c_inf('"', opts)}#{s[1..-2]}#{c_inf('"', opts)}" :
181
+ "#{s}"
182
+ end
183
+
184
+ def string_to_d(x, opts)
185
+
186
+ if (
187
+ x.match(/\A[^: \b\f\n\r\t"',()\[\]{}#\\]+\z/) == nil ||
188
+ x.to_i.to_s == x ||
189
+ x.to_f.to_s == x
190
+ )
191
+ "#{c_inf('"', opts)}#{c_str(x.inspect[1..-2], opts)}#{c_inf('"', opts)}"
192
+ else
193
+ c_str(x, opts)
194
+ end
195
+ end
196
+
197
+ def object_to_d(x, opts)
198
+
199
+ a = [ '{ ', ': ', ', ', ' }' ]
200
+ a = a.collect(&:strip) if x.empty? || opts[:compact]
201
+ a = a.collect { |s| c_inf(s, opts) }
202
+ a, b, c, d = a
203
+
204
+ a +
205
+ x.collect { |k, v|
206
+ "#{c_key(to_djan(k, {}), opts)}#{b}#{to_djan(v, opts)}"
207
+ }.join(c) +
208
+ d
209
+ end
210
+
211
+ def array_to_d(x, opts)
212
+
213
+ a = [ '[ ', ', ', ' ]' ]
214
+ a = a.collect(&:strip) if x.empty? || opts[:compact]
215
+ a = a.collect { |s| c_inf(s, opts) }
216
+ a, b, c = a
217
+
218
+ a + x.collect { |e| to_djan(e, opts) }.join(b) + c
219
+ end
220
+ end
221
+
222
+
223
+ #
224
+ # ids
225
+ #
226
+ # functions about exids, nids, sub_nids, ...
227
+
228
+ def self.split_fei(fei)
229
+
230
+ if m = fei.match(/\A([^-]+-[^-]+-\d+\.\d+\.[^-]+)-(.*)\z/)
231
+ [ m[1], m[2] ]
232
+ else
233
+ [ nil ]
234
+ end
235
+ end
236
+
237
+ def self.exid(fei)
238
+
239
+ split_fei(fei).first
240
+ end
241
+
242
+ def self.split_nid(nid)
243
+
244
+ nid.split('-')
245
+ end
246
+
247
+ def self.child_id(nid)
248
+
249
+ nid ? nid.split('_').last.split('-').first.to_i : nil
250
+ end
251
+
252
+ def self.next_child_id(nid)
253
+
254
+ child_id(nid) + 1
255
+ end
256
+
257
+ def self.sub_nid(nid, subid)
258
+
259
+ "#{nid.split('-').first}-#{subid}"
260
+ end
261
+
262
+ # Remove the sub_nid if any.
263
+ #
264
+ def self.master_nid(nid)
265
+
266
+ nid.split('-').first
267
+ end
268
+
269
+ def self.child_nid(nid, i, sub=nil)
270
+
271
+ nid, subnid = nid.split('-')
272
+ subnid = sub if sub && sub > 0
273
+
274
+ "#{nid}_#{i}#{subnid ? "-#{subnid}" : ''}"
275
+ end
276
+
277
+ def self.parent_id(nid)
278
+
279
+ if i = nid.rindex('_')
280
+ nid[0, i]
281
+ else
282
+ nil
283
+ end
284
+ end
285
+
286
+ def self.parent_nid(nid, remove_subnid=false)
287
+
288
+ _, sub = nid.split('-')
289
+ i = nid.rindex('_')
290
+
291
+ return nil unless i
292
+ "#{nid[0, i]}#{remove_subnid || sub.nil? ? nil : "-#{sub}"}"
293
+ end
294
+
295
+ def self.is_nid?(s)
296
+
297
+ !! (s.is_a?(String) && s.match(/\A[0-9]+(?:_[0-9]+)*(?:-[0-9]+)?\z/))
298
+ end
299
+
300
+ #
301
+ # misc
302
+ #
303
+ # miscellaneous functions
304
+
305
+ def self.dup(o)
306
+
307
+ Marshal.load(Marshal.dump(o))
308
+ end
309
+
310
+ def self.dup_and_merge(h, hh)
311
+
312
+ self.dup(h).merge(hh)
313
+ end
314
+ def self.dupm(h, hh); self.dup_and_merge(h, hh); end
315
+
316
+ def self.deep_freeze(o)
317
+
318
+ if o.is_a?(Array)
319
+ o.each { |e| e.freeze }
320
+ elsif o.is_a?(Hash)
321
+ o.each { |k, v| k.freeze; v.freeze }
322
+ end
323
+
324
+ o.freeze
325
+ end
326
+
327
+ def self.false?(o)
328
+
329
+ o == nil || o == false
330
+ end
331
+
332
+ def self.true?(o)
333
+
334
+ o != nil && o != false
335
+ end
336
+
337
+ def self.to_error(o)
338
+
339
+ h = {}
340
+ h['kla'] = o.class.to_s
341
+ t = nil
342
+
343
+ if o.is_a?(Exception)
344
+
345
+ h['msg'] = o.message
346
+
347
+ t = o.backtrace
348
+
349
+ if n = o.respond_to?(:node) && o.node
350
+ h['lin'] = n.tree[2]
351
+ #h['tre'] = n.tree
352
+ end
353
+
354
+ else
355
+
356
+ h['msg'] = o.to_s
357
+
358
+ t = caller[1..-1]
359
+ end
360
+
361
+ h['trc'] = t[0..(t.rindex { |l| l.match(/\/lib\/flor\//) }) + 1] if t
362
+
363
+ h
364
+ end
365
+
366
+ def self.const_lookup(s)
367
+
368
+ s.split('::').inject(Kernel) { |k, sk| k.const_get(sk) }
369
+ end
370
+
371
+ def self.to_coll(o)
372
+
373
+ #o.respond_to?(:to_a) ? o.to_a : [ a ]
374
+ Array(o)
375
+ end
376
+
377
+ def self.truncate(s, l)
378
+
379
+ s.length < l ? s : s[0, l] + '...'
380
+ end
381
+
382
+ #
383
+ # functions about time
384
+
385
+ def self.isostamp(show_date, show_time, show_usec, time)
386
+
387
+ t = (time || Time.now).utc
388
+ s = StringIO.new
389
+
390
+ s << t.strftime('%Y-%m-%d') if show_date
391
+ s << t.strftime('T%H:%M:%S') if show_time
392
+ s << sprintf('.%06d', t.usec) if show_time && show_usec
393
+ s << 'Z' if show_time
394
+
395
+ s.string
396
+ end
397
+
398
+ def self.tstamp(t=Time.now)
399
+
400
+ isostamp(true, true, true, t)
401
+ end
402
+
403
+ def self.ststamp(t=Time.now)
404
+
405
+ isostamp(true, true, false, t)
406
+ end
407
+
408
+ def self.dstamp(t=Time.now)
409
+
410
+ isostamp(true, false, false, t)
411
+ end
412
+
413
+ # hour stamp
414
+ #
415
+ def self.hstamp(t=Time.now)
416
+
417
+ isostamp(false, true, true, t)
418
+ end
419
+
420
+ # def self.to_time(ts)
421
+ #
422
+ # m = ts.match(/\A(\d{4})(\d{2})(\d{2})\.(\d{2})(\d{2})(\d{2})(\d+)([uU]?)\z/)
423
+ # fail ArgumentError.new("cannot parse timestamp #{ts.inspect}") unless m
424
+ #
425
+ # return Time.utc(*m[1, 7].collect(&:to_i)) if m[8].length > 0
426
+ # Time.local(*m[1, 7].collect(&:to_i))
427
+ # end
428
+
429
+ #
430
+ # functions about domains and units
431
+
432
+ NAME_REX = '[a-zA-Z0-9_]+'
433
+ UNIT_NAME_REX = /\A#{NAME_REX}\z/
434
+ DOMAIN_NAME_REX = /\A#{NAME_REX}(\.#{NAME_REX})*\z/
435
+ FLOW_NAME_REX = /\A(#{NAME_REX}(?:\.#{NAME_REX})*)\.([a-zA-Z0-9_-]+)\z/
436
+
437
+ def self.potential_unit_name?(s)
438
+
439
+ s.is_a?(String) && s.match(UNIT_NAME_REX)
440
+ end
441
+
442
+ def self.potential_domain_name?(s)
443
+
444
+ s.is_a?(String) && s.match(DOMAIN_NAME_REX)
445
+ end
446
+
447
+ def self.split_flow_name(s)
448
+
449
+ if s.is_a?(String) && m = s.match(FLOW_NAME_REX)
450
+ [ m[1], m[2] ]
451
+ else
452
+ nil
453
+ end
454
+ end
455
+
456
+ def self.is_sub_domain?(dom, sub)
457
+
458
+ fail ArgumentError.new(
459
+ "not a domain #{dom.inspect}"
460
+ ) unless potential_domain_name?(dom)
461
+
462
+ fail ArgumentError.new(
463
+ "not a sub domain #{sub.inspect}"
464
+ ) unless potential_domain_name?(sub)
465
+
466
+ sub == dom || sub[0, dom.length + 1] == dom + '.'
467
+ end
468
+
469
+ DOMAIN_UNIT_REX = /\A(#{NAME_REX}(?:\.#{NAME_REX})*)-(#{NAME_REX})[-\z]/
470
+
471
+ def self.split_domain_unit(s)
472
+
473
+ if m = DOMAIN_UNIT_REX.match(s)
474
+ [ m[1], m[2] ]
475
+ else
476
+ []
477
+ end
478
+ end
479
+
480
+ def self.domain(s)
481
+
482
+ split_domain_unit(s).first
483
+ end
484
+
485
+ def self.unit(s)
486
+
487
+ split_domain_unit(s).last
488
+ end
489
+
490
+ def self.to_pretty_s(o, twidth=79)
491
+
492
+ sio = StringIO.new
493
+ PP.pp(o, sio, twidth)
494
+
495
+ sio.string
496
+ end
497
+
498
+
499
+ #
500
+ # tree
501
+
502
+ def self.is_tree?(t)
503
+
504
+ t.is_a?(Array) &&
505
+ t.size > 2 &&
506
+ (t[0].is_a?(String) || Flor.is_tree?(t[0])) &&
507
+ t[2].is_a?(Integer)
508
+ end
509
+
510
+ def self.is_att_tree?(t)
511
+
512
+ t.is_a?(Array) &&
513
+ t[0] == '_att' &&
514
+ t[1].is_a?(Array)
515
+ end
516
+
517
+ def self.is_array_of_trees?(o)
518
+
519
+ o.is_a?(Array) && o.all? { |e| Flor.is_tree?(e) }
520
+ end
521
+
522
+ def self.is_proc_tree?(o)
523
+
524
+ o.is_a?(Array) &&
525
+ o[0] == '_proc' &&
526
+ o[2].is_a?(Integer) &&
527
+ o[1].is_a?(Hash) &&
528
+ o[1]['proc'].is_a?(String)
529
+ end
530
+
531
+ def self.is_func_tree?(o)
532
+
533
+ o.is_a?(Array) &&
534
+ o[0] == '_func' &&
535
+ o[2].is_a?(Integer) &&
536
+ o[1].is_a?(Hash) && (o[1].keys & %w[ nid cnid fun ]).size == 3
537
+ end
538
+
539
+ def self.is_task_tree?(o)
540
+
541
+ o.is_a?(Array) &&
542
+ o[0] == '_task' &&
543
+ o[2].is_a?(Integer) &&
544
+ o[1].is_a?(Hash) &&
545
+ o[1]['task'].is_a?(String)
546
+ end
547
+
548
+ def self.is_tree_head_tree?(o)
549
+
550
+ o.is_a?(Array) &&
551
+ Flor.is_tree?(o[0]) &&
552
+ Flor.is_array_of_trees?(o[1]) &&
553
+ o[2].is_a?(Integer)
554
+ end
555
+ end
556
+