flor 0.0.1 → 0.9.0

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