flor 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/CREDITS.md +21 -0
  4. data/LICENSE.txt +4 -1
  5. data/Makefile +4 -0
  6. data/README.md +8 -0
  7. data/flor.gemspec +10 -10
  8. data/lib/flor.rb +2 -2
  9. data/lib/flor/changes.rb +3 -3
  10. data/lib/flor/colours.rb +14 -8
  11. data/lib/flor/conf.rb +63 -58
  12. data/lib/flor/core.rb +4 -4
  13. data/lib/flor/core/executor.rb +65 -29
  14. data/lib/flor/core/node.rb +37 -20
  15. data/lib/flor/core/procedure.rb +182 -40
  16. data/lib/flor/core/texecutor.rb +125 -52
  17. data/lib/flor/djan.rb +111 -82
  18. data/lib/flor/dollar.rb +31 -30
  19. data/lib/flor/flor.rb +314 -237
  20. data/lib/flor/id.rb +7 -2
  21. data/lib/flor/log.rb +250 -245
  22. data/lib/flor/parser.rb +72 -38
  23. data/lib/flor/pcore/_arr.rb +10 -10
  24. data/lib/flor/pcore/_att.rb +49 -14
  25. data/lib/flor/pcore/_coll.rb +18 -0
  26. data/lib/flor/pcore/_obj.rb +23 -7
  27. data/lib/flor/pcore/_pat_.rb +1 -1
  28. data/lib/flor/pcore/_pat_guard.rb +8 -0
  29. data/lib/flor/pcore/_pat_obj.rb +3 -3
  30. data/lib/flor/pcore/_pat_or.rb +4 -0
  31. data/lib/flor/pcore/_pat_regex.rb +24 -0
  32. data/lib/flor/pcore/_skip.rb +4 -0
  33. data/lib/flor/pcore/_val.rb +0 -1
  34. data/lib/flor/pcore/all.rb +111 -0
  35. data/lib/flor/pcore/any.rb +83 -0
  36. data/lib/flor/pcore/arith.rb +35 -6
  37. data/lib/flor/pcore/break.rb +39 -1
  38. data/lib/flor/pcore/case.rb +82 -4
  39. data/lib/flor/pcore/cmp.rb +7 -7
  40. data/lib/flor/pcore/collect.rb +50 -0
  41. data/lib/flor/pcore/cond.rb +17 -3
  42. data/lib/flor/pcore/cursor.rb +8 -2
  43. data/lib/flor/pcore/detect.rb +45 -0
  44. data/lib/flor/pcore/each.rb +52 -0
  45. data/lib/flor/pcore/empty.rb +60 -0
  46. data/lib/flor/pcore/filter.rb +94 -0
  47. data/lib/flor/pcore/find.rb +67 -0
  48. data/lib/flor/pcore/for_each.rb +65 -0
  49. data/lib/flor/pcore/includes.rb +32 -0
  50. data/lib/flor/pcore/inject.rb +55 -0
  51. data/lib/flor/pcore/iterator.rb +151 -0
  52. data/lib/flor/pcore/keys.rb +60 -0
  53. data/lib/flor/pcore/length.rb +34 -7
  54. data/lib/flor/pcore/logo.rb +18 -0
  55. data/lib/flor/pcore/loop.rb +4 -0
  56. data/lib/flor/pcore/map.rb +77 -46
  57. data/lib/flor/pcore/match.rb +8 -2
  58. data/lib/flor/pcore/matchr.rb +4 -5
  59. data/lib/flor/pcore/move.rb +3 -3
  60. data/lib/flor/pcore/noeval.rb +13 -0
  61. data/lib/flor/pcore/not.rb +16 -0
  62. data/lib/flor/pcore/on.rb +172 -0
  63. data/lib/flor/pcore/on_cancel.rb +54 -0
  64. data/lib/flor/pcore/on_error.rb +68 -0
  65. data/lib/flor/pcore/rand.rb +2 -2
  66. data/lib/flor/pcore/range.rb +2 -1
  67. data/lib/flor/pcore/reduce.rb +124 -0
  68. data/lib/flor/pcore/reverse.rb +46 -0
  69. data/lib/flor/pcore/select.rb +72 -0
  70. data/lib/flor/pcore/set.rb +8 -0
  71. data/lib/flor/pcore/stall.rb +10 -0
  72. data/lib/flor/pcore/to_array.rb +61 -0
  73. data/lib/flor/pcore/until.rb +34 -0
  74. data/lib/flor/punit/cancel.rb +30 -5
  75. data/lib/flor/punit/ccollect.rb +11 -0
  76. data/lib/flor/punit/cmap.rb +10 -5
  77. data/lib/flor/punit/concurrence.rb +42 -51
  78. data/lib/flor/punit/cron.rb +33 -0
  79. data/lib/flor/punit/do_trap.rb +42 -0
  80. data/lib/flor/punit/every.rb +48 -13
  81. data/lib/flor/punit/graft.rb +3 -3
  82. data/lib/flor/punit/on_timeout.rb +38 -0
  83. data/lib/flor/punit/schedule.rb +69 -6
  84. data/lib/flor/punit/signal.rb +54 -0
  85. data/lib/flor/punit/sleep.rb +1 -1
  86. data/lib/flor/punit/task.rb +4 -1
  87. data/lib/flor/punit/trap.rb +188 -13
  88. data/lib/flor/tools/shell.rb +408 -62
  89. data/lib/flor/tools/shell_out.rb +31 -0
  90. data/lib/flor/unit.rb +1 -1
  91. data/lib/flor/unit/caller.rb +177 -0
  92. data/lib/flor/unit/executor.rb +1 -0
  93. data/lib/flor/unit/ganger.rb +15 -21
  94. data/lib/flor/unit/hook.rb +1 -1
  95. data/lib/flor/unit/hooker.rb +22 -10
  96. data/lib/flor/unit/loader.rb +22 -22
  97. data/lib/flor/unit/logger.rb +63 -36
  98. data/lib/flor/unit/models.rb +6 -1
  99. data/lib/flor/unit/models/execution.rb +12 -1
  100. data/lib/flor/unit/models/message.rb +7 -0
  101. data/lib/flor/unit/models/trap.rb +31 -17
  102. data/lib/flor/unit/scheduler.rb +18 -10
  103. data/lib/flor/unit/storage.rb +83 -23
  104. data/lib/flor/unit/waiter.rb +1 -2
  105. metadata +96 -52
  106. data/lib/flor/deep.rb +0 -144
  107. data/lib/flor/punit/on.rb +0 -57
  108. data/lib/flor/unit/runner.rb +0 -84
  109. data/match.md +0 -22
@@ -0,0 +1,65 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::ForEach < Flor::Pro::Iterator
6
+ #
7
+ # Calls a function for each element in the argument collection.
8
+ #
9
+ # When the "for-each" ends, `f.ret` is pointing back to the argument
10
+ # collection.
11
+ #
12
+ # ```
13
+ # set l []
14
+ # for-each [ 0 1 2 3 4 5 6 7 ]
15
+ # def x
16
+ # pushr l (2 * x) if x % 2 == 0
17
+ # ```
18
+ # the var `l` will yield `[ 0, 4, 8, 12 ]` after the `for-each`
19
+ # the field `ret` will yield `[ 0, 1, 2, 3, 4, 5, 6, 7 ]`.
20
+ #
21
+ # ```
22
+ # set r []
23
+ # for-each { a: 'A', b: 'B', c: 'C' }
24
+ # def k v i l # key, val, idx, len
25
+ # pushr r (+ k v (+ i 1) '/' l)
26
+ # ```
27
+ # the var `r` will yield `[ 'aA1/3', 'bB2/3', 'cC3/3' ]` after the `for-each`
28
+ # the field `ret` will yield `{ 'a': 'A', 'b': 'B', 'c': 'C' }`.
29
+ #
30
+ # ## iterating and functions
31
+ #
32
+ # Iterating functions accept 0 to 3 arguments when iterating over an
33
+ # array and 0 to 4 arguments when iterating over an object.
34
+ #
35
+ # Those arguments are `[ value, index, length ]` for arrays.
36
+ # They are `[ key, value, index, length ]` for objects.
37
+ #
38
+ # The corresponding `key`, `val`, `idx` and `len` variables are also
39
+ # set in the closure for the function call.
40
+ #
41
+ # ## see also
42
+ #
43
+ # each.
44
+
45
+ name 'for-each'
46
+
47
+ protected
48
+
49
+ def pre_iterator
50
+
51
+ # nothing to do
52
+ end
53
+
54
+ def receive_iteration
55
+
56
+ # nothing to do
57
+ end
58
+
59
+ def iterator_result
60
+
61
+ @node['ocol']
62
+ # back to the original collection
63
+ end
64
+ end
65
+
@@ -0,0 +1,32 @@
1
+
2
+ class Flor::Pro::Includes < Flor::Procedure
3
+
4
+ name 'includes?'
5
+
6
+ def pre_execute
7
+
8
+ @node['rets'] = []
9
+
10
+ unatt_unkeyed_children
11
+ end
12
+
13
+ def receive_last
14
+
15
+ col = nil
16
+ elt = :nil
17
+
18
+ @node['rets'].each do |ret|
19
+ if col == nil && (ret.is_a?(Array) || ret.is_a?(Hash))
20
+ col = ret
21
+ elsif elt == :nil
22
+ elt = ret
23
+ end
24
+ end
25
+
26
+ fail Flor::FlorError.new('missing collection', self) if col == nil
27
+ fail Flor::FlorError.new('missing element', self) if elt == :nil
28
+
29
+ wrap_reply('ret' => col.include?(elt))
30
+ end
31
+ end
32
+
@@ -0,0 +1,55 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Inject < Flor::Macro::Iterator
6
+ #
7
+ # Inject is a simplified version of [reduce](reduce.md).
8
+ #
9
+ # Inject takes a collection and a block. It reduces the collection
10
+ # to a single result thanks to the block.
11
+ #
12
+ # The block is run for each element in the collection, it's passed
13
+ # `res` and `elt`. `res` is the result, the accumulator, `elt`
14
+ # is the current element in the collection.
15
+ #
16
+ # The block must return the result for the next iteration.
17
+ #
18
+ # ```
19
+ # inject [ '0', 1, 'b', 3 ]
20
+ # res + elt
21
+ # # --> "01b3"
22
+ # ```
23
+ #
24
+ # An initial value is accepted (generally after the collection)
25
+ #
26
+ # ```
27
+ # inject [ 0, 1, 2, 3, 4 ] 10
28
+ # res + elt
29
+ # # --> 20
30
+ # ```
31
+ #
32
+ # ## iterating blocks
33
+ #
34
+ # Iterating blocks are given 3 to 4 local variables.
35
+ #
36
+ # A block iterating over an array will receive `elt` (the current element
37
+ # of the iteration), `idx` (the zero-based index of the current element),
38
+ # and `len` (the length of the array).
39
+ #
40
+ # A block iterating over an object will receive `key` (the current string
41
+ # key), `val` (the current value), `idx` (the zero-based index of the
42
+ # current key/val), and `len` (the length of the object).
43
+ #
44
+ # ## see also
45
+ #
46
+ # Reduce.
47
+
48
+ name 'inject'
49
+
50
+ def rewrite_tree
51
+
52
+ rewrite_iterator_tree('reduce')
53
+ end
54
+ end
55
+
@@ -0,0 +1,151 @@
1
+
2
+ class Flor::Pro::Iterator < Flor::Procedure
3
+
4
+ def pre_execute
5
+
6
+ @node['vars'] ||= {}
7
+
8
+ @node['args'] = [] # before iterating, arguments are collected
9
+
10
+ @node['ocol'] = nil # original collection
11
+ @node['fun'] = nil # function
12
+
13
+ @node['col'] = nil # collection
14
+ @node['idx'] = -1
15
+
16
+ unatt_unkeyed_children
17
+ end
18
+
19
+ def receive_non_att
20
+
21
+ if @node['args']
22
+ receive_argument
23
+ else
24
+ receive_iteration
25
+ iterate
26
+ end
27
+ end
28
+
29
+ protected
30
+
31
+ def receive_argument
32
+
33
+ @node['args'] << payload['ret']
34
+
35
+ if children[@ncid]
36
+ execute_child(@ncid)
37
+ else
38
+ iterate
39
+ end
40
+ end
41
+
42
+ def iterate
43
+
44
+ prepare_iterations unless @node['ocol']
45
+
46
+ return no_iterate unless @node['fun']
47
+
48
+ @node['idx'] += 1
49
+ @node['mtime'] = Flor.tstamp
50
+
51
+ return end_iterator if iterator_over?
52
+
53
+ apply_iteration
54
+ end
55
+
56
+ def function_mandatory?
57
+
58
+ true
59
+ end
60
+
61
+ def prepare_iterations
62
+
63
+ prepare_iterator
64
+
65
+ @node['args']
66
+ .each { |a|
67
+ if Flor.is_func_tree?(a)
68
+ @node['fun'] ||= a
69
+ elsif a.is_a?(Array) || a.is_a?(Hash)
70
+ @node['ocol'] ||= a
71
+ end }
72
+
73
+ @node['ocol'] ||= node_payload_ret
74
+ ocol = @node['ocol']
75
+
76
+ fail Flor::FlorError.new(
77
+ "function not given to #{heap.inspect}", self
78
+ ) if function_mandatory? && ( ! @node['fun'])
79
+ fail Flor::FlorError.new(
80
+ "collection not given to #{heap.inspect}", self
81
+ ) unless ocol.is_a?(Array) || ocol.is_a?(Hash)
82
+
83
+ @node['col'] = Flor.to_coll(@node['ocol']) if @node['fun']
84
+ @node['args'] = nil
85
+ end
86
+
87
+ def prepare_iterator
88
+
89
+ @node['res'] = []
90
+ end
91
+
92
+ def apply_iteration
93
+
94
+ vars = determine_iteration_vars
95
+
96
+ args = vars.values
97
+ vars.each { |k, v| @node['vars'][k] = v }
98
+
99
+ apply(@node['fun'], args, tree[2])
100
+ end
101
+
102
+ def determine_iteration_vars
103
+
104
+ idx = @node['idx']
105
+ elt = @node['col'][idx]
106
+ len = @node['col'].length
107
+
108
+ if @node['ocol'].is_a?(Array)
109
+ { 'elt' => elt, 'idx' => idx, 'len' => len }
110
+ else
111
+ { 'key' => elt[0], 'val' => elt[1], 'idx' => idx, 'len' => len }
112
+ end
113
+ end
114
+
115
+ def iterator_over?
116
+
117
+ @node['idx'] == @node['col'].size
118
+ end
119
+
120
+ def end_iterator
121
+
122
+ wrap_reply('ret' => iterator_result)
123
+ end
124
+ end
125
+
126
+
127
+ class Flor::Macro::Iterator < Flor::Macro
128
+
129
+ def rewrite_iterator_tree(procedure_name)
130
+
131
+ atts = att_children
132
+
133
+ l = tree[2]
134
+
135
+ th = [ procedure_name, [], l, *tree[3] ]
136
+ atts.each { |ac| th[1] << Flor.dup(ac) }
137
+
138
+ if non_att_children.any?
139
+
140
+ td = [ 'def', [], l ]
141
+ td[1] << [ '_att', [ [ 'res', [], l ] ], l ] if procedure_name == 'reduce'
142
+ td[1] << [ '_att', [ [ 'elt', [], l ] ], l ]
143
+ non_att_children.each { |nac| td[1] << Flor.dup(nac) }
144
+
145
+ th[1] << td
146
+ end
147
+
148
+ th
149
+ end
150
+ end
151
+
@@ -0,0 +1,60 @@
1
+
2
+ class Flor::Pro::Keys < Flor::Procedure
3
+ #
4
+ # Returns the "keys" or the "values" of an object.
5
+ #
6
+ # ```
7
+ # keys { a: 'A', b: 'B' }
8
+ # # f.ret --> [ 'a', 'b' ]
9
+ # values { a: 'A', b: 'B' }
10
+ # # f.ret --> [ 'A', 'B' ]
11
+ # ```
12
+ #
13
+ # When used against an array, the indexes will be the numerical indexes
14
+ # 0 to array length - 1.
15
+ #
16
+ # ```
17
+ # keys [ 1, 'to', true ]
18
+ # # f.ret -> [ 0, 1, 2 ]
19
+ # values [ 1, 'to', true ]
20
+ # # f.ret -> [ 1, 'to', true ]
21
+ # ```
22
+ #
23
+ # When used against something that is neither an object nor an array
24
+ # it will fail.
25
+ #
26
+ # ## see also
27
+ #
28
+ # length
29
+
30
+ names %w{ keys values }
31
+
32
+ def pre_execute
33
+
34
+ @node['ret'] = receive_payload_ret
35
+
36
+ unatt_unkeyed_children
37
+ end
38
+
39
+ def receive_last
40
+
41
+ ret = @node['ret']
42
+
43
+ fail Flor::FlorError.new(
44
+ "no argument given", self
45
+ ) if ret.nil?
46
+ fail Flor::FlorError.new(
47
+ "received argument of class #{ret.class}, no #{heap}", self
48
+ ) unless ret.is_a?(Array) || ret.is_a?(Hash)
49
+
50
+ r =
51
+ if ret.is_a?(Hash)
52
+ heap == 'keys' ? ret.keys : ret.values
53
+ else
54
+ heap == 'keys' ? (0..ret.length - 1).to_a : ret
55
+ end
56
+
57
+ wrap_reply('ret' => r)
58
+ end
59
+ end
60
+
@@ -1,18 +1,45 @@
1
1
 
2
2
  class Flor::Pro::Length < Flor::Procedure
3
+ #
4
+ # Returns the length of its last collection argument or
5
+ # the length of the incoming f.ret
6
+ #
7
+ # ```
8
+ # length [ 0 1 2 3 ]
9
+ # # f.ret ==> 4
10
+ #
11
+ # { a: 'A', b: 'B', c: 'C' }
12
+ # length _
13
+ # # f.ret ==> 3
14
+ # ```
15
+ #
16
+ # It will fail unless "length" receives a (non-attribute) argument
17
+ # that has a length.
18
+ #
19
+ # Has the "size" alias.
3
20
 
4
- name 'length'
21
+ names %w[ length size ]
5
22
 
6
- def receive_last
23
+ def pre_execute
24
+
25
+ @node['ret'] = receive_payload_ret
26
+
27
+ unatt_unkeyed_children
28
+ end
29
+
30
+ def receive_payload_ret
7
31
 
8
32
  r = payload['ret']
33
+ r.respond_to?(:length) ? r.length : false
34
+ end
35
+
36
+ def receive_last
9
37
 
10
- payload['ret'] =
11
- if r.respond_to?(:length) then r.length
12
- else -1
13
- end
38
+ r =
39
+ @node['ret'] ||
40
+ fail(Flor::FlorError.new('found no argument that has a length', self))
14
41
 
15
- super
42
+ wrap_reply('ret' => r)
16
43
  end
17
44
  end
18
45
 
@@ -1,5 +1,23 @@
1
1
 
2
2
  class Flor::Pro::Logo < Flor::Procedure
3
+ #
4
+ # When `and` evaluates the children and returns false as soon
5
+ # as one of returns a falsy value. Returns true else.
6
+ # When `or` evaluates the children and returns true as soon
7
+ # as one of them returns a trueish value. Returns false else.
8
+ #
9
+ # ```
10
+ # and
11
+ # false
12
+ # true
13
+ # # => evalutes to false
14
+ # ```
15
+ #
16
+ # ```
17
+ # and (check_this _) (check_that _)
18
+ # ```
19
+ #
20
+ # Gives priority to `and` over `or`.
3
21
 
4
22
  names %w[ and or ]
5
23
 
@@ -13,6 +13,10 @@ class Flor::Pro::Loop < Flor::Pro::Cursor
13
13
  # ```
14
14
  #
15
15
  # Accepts `break` and `continue` like `cursor` does.
16
+ #
17
+ # ## see also
18
+ #
19
+ # Cursor, break, continue.
16
20
 
17
21
  name 'loop'
18
22