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
@@ -13,9 +13,9 @@ class Flor::Pro::Cmp < Flor::Procedure
13
13
  payload['ret'] =
14
14
  if @node['rets'].size > 1
15
15
  case tree[0]
16
- when '=', '==' then check_equal
17
- when '<', '>' then check_lesser
18
- else true
16
+ when '=', '==' then check_equal
17
+ when '<', '>' then check_lesser
18
+ else true
19
19
  end
20
20
  else
21
21
  true
@@ -36,10 +36,10 @@ class Flor::Pro::Cmp < Flor::Procedure
36
36
  a, b = @node['rets'][-2], @node['rets'][-1]
37
37
 
38
38
  case tree[0]
39
- when '<' then return false if a >= b
40
- when '<=' then return false if a > b
41
- when '>' then return false if a <= b
42
- when '>=' then return false if a < b
39
+ when '<' then return false if a >= b
40
+ when '<=' then return false if a > b
41
+ when '>' then return false if a <= b
42
+ when '>=' then return false if a < b
43
43
  end
44
44
 
45
45
  true
@@ -0,0 +1,50 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Collect < Flor::Macro::Iterator
6
+ #
7
+ # Collect is a simplified version of [map](map.md).
8
+ #
9
+ # ```
10
+ # map [ 1, 2, 3 ]
11
+ # def x
12
+ # + x 3
13
+ # #
14
+ # # becomes
15
+ # #
16
+ # collect [ 1, 2, 3 ]
17
+ # + elt 3
18
+ # ```
19
+ # Collect accepts, instead of a function, a block, where `elt` contains
20
+ # the current element and `idx` the current index.
21
+ #
22
+ # ```
23
+ # collect [ 'a', 'b' ]
24
+ # [ idx, elt ]
25
+ # ```
26
+ #
27
+ # ## iterating blocks
28
+ #
29
+ # Iterating blocks are given 3 to 4 local variables.
30
+ #
31
+ # A block iterating over an array will receive `elt` (the current element
32
+ # of the iteration), `idx` (the zero-based index of the current element),
33
+ # and `len` (the length of the array).
34
+ #
35
+ # A block iterating over an object will receive `key` (the current string
36
+ # key), `val` (the current value), `idx` (the zero-based index of the
37
+ # current key/val), and `len` (the length of the object).
38
+ #
39
+ # ## see also
40
+ #
41
+ # Map.
42
+
43
+ name 'collect'
44
+
45
+ def rewrite_tree
46
+
47
+ rewrite_iterator_tree('map')
48
+ end
49
+ end
50
+
@@ -19,11 +19,25 @@ class Flor::Pro::Cond < Flor::Procedure
19
19
  # ```
20
20
  # set a 11
21
21
  # cond
22
- # a < 4 ;; "less than four"
23
- # a < 7 ;; "less than seven"
24
- # else ;; "ten or bigger"
22
+ # a < 4 ; "less than four"
23
+ # a < 7 ; "less than seven"
24
+ # else ; "ten or bigger"
25
25
  # ```
26
26
  # will yield "ten or bigger".
27
+ #
28
+ # The semicolon is used to place condition and clause on the same line.
29
+ # A pipe can be used instead of a semicolon.
30
+ # ```
31
+ # set a 11
32
+ # cond
33
+ # a < 4 | "less than four"
34
+ # a < 7 | "less than seven"
35
+ # else | "ten or bigger"
36
+ # ```
37
+ #
38
+ # ## see also
39
+ #
40
+ # If, match.
27
41
 
28
42
  name 'cond'
29
43
 
@@ -43,6 +43,10 @@ class Flor::Pro::Cursor < Flor::Procedure
43
43
  # do-that _ # got skipped
44
44
  # do-that-other-thing _
45
45
  # ```
46
+ #
47
+ # ## see also
48
+ #
49
+ # Break, continue, loop.
46
50
 
47
51
  name 'cursor'
48
52
 
@@ -122,14 +126,16 @@ class Flor::Pro::Cursor < Flor::Procedure
122
126
 
123
127
  to = @message['to']
124
128
 
125
- fail("move target #{to.inspect} is not a string") unless to.is_a?(String)
129
+ fail Flor::FlorError.new(
130
+ "move target #{to.inspect} is not a string", self
131
+ ) unless to.is_a?(String)
126
132
 
127
133
  find_tag_target(to) ||
128
134
  find_string_arg_target(to) ||
129
135
  find_string_target(to) ||
130
136
  find_name_target(to) ||
131
137
  find_att_target(to) ||
132
- fail("move target #{to.inspect} not found")
138
+ fail(Flor::FlorError.new("move target #{to.inspect} not found", self))
133
139
  end
134
140
 
135
141
  def is_tag_tree?(t, tagname)
@@ -0,0 +1,45 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Detect < Flor::Macro::Iterator
6
+ #
7
+ # Detect is a simplified version of [find](find.md).
8
+ #
9
+ # ```
10
+ # detect [ 1, 2, 3 ]
11
+ # (elt % 2) == 0
12
+ # # f.ret --> 2
13
+ # ```
14
+ #
15
+ # With objects (maps), it returns the first matching entry (pair).
16
+ # ```
17
+ # detect { a: 'A', b: 'B', c: 'C' }
18
+ # val == 'B'
19
+ # # f.ret --> [ 'b', 'B' ]
20
+ # ```
21
+ #
22
+ # ## iterating blocks
23
+ #
24
+ # Iterating blocks are given 3 to 4 local variables.
25
+ #
26
+ # A block iterating over an array will receive `elt` (the current element
27
+ # of the iteration), `idx` (the zero-based index of the current element),
28
+ # and `len` (the length of the array).
29
+ #
30
+ # A block iterating over an object will receive `key` (the current string
31
+ # key), `val` (the current value), `idx` (the zero-based index of the
32
+ # current key/val), and `len` (the length of the object).
33
+ #
34
+ # ## see also
35
+ #
36
+ # find.
37
+
38
+ name 'detect'
39
+
40
+ def rewrite_tree
41
+
42
+ rewrite_iterator_tree('find')
43
+ end
44
+ end
45
+
@@ -0,0 +1,52 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Each < Flor::Macro::Iterator
6
+ #
7
+ # Each is a simplified version of [for-each](for_each.md).
8
+ #
9
+ # Calls a function for each element in the argument collection.
10
+ #
11
+ # When the "each" ends, `f.ret` is pointing back to the argument
12
+ # collection.
13
+ #
14
+ # ```
15
+ # set l []
16
+ # each [ 0 1 2 3 4 5 6 7 ]
17
+ # pushr l (2 * elt) if elt % 2 == 0
18
+ # ```
19
+ # the var `l` will yield `[ 0, 4, 8, 12 ]` after the `each`
20
+ # the field `ret` will yield `[ 0, 1, 2, 3, 4, 5, 6, 7 ]`.
21
+ #
22
+ # ```
23
+ # set l []
24
+ # each { a: 'A', b: 'B', c: 'C' }
25
+ # pushr l (+ key val idx)
26
+ # ```
27
+ # the var `l` will yield `[ 'aA0', 'bB1', 'cC2' ]` after the `each`
28
+ #
29
+ # ## iterating blocks
30
+ #
31
+ # Iterating blocks are given 3 to 4 local variables.
32
+ #
33
+ # A block iterating over an array will receive `elt` (the current element
34
+ # of the iteration), `idx` (the zero-based index of the current element),
35
+ # and `len` (the length of the array).
36
+ #
37
+ # A block iterating over an object will receive `key` (the current string
38
+ # key), `val` (the current value), `idx` (the zero-based index of the
39
+ # current key/val), and `len` (the length of the object).
40
+ #
41
+ # ## see also
42
+ #
43
+ # for-each.
44
+
45
+ name 'each'
46
+
47
+ def rewrite_tree
48
+
49
+ rewrite_iterator_tree('for-each')
50
+ end
51
+ end
52
+
@@ -0,0 +1,60 @@
1
+
2
+ class Flor::Pro::Empty < Flor::Procedure
3
+ #
4
+ # Returns true if the given collection or string is empty.
5
+ #
6
+ # Returns true of the given argument is null, returns false for any
7
+ # other non-collection, non-string argument.
8
+ #
9
+ # ```
10
+ # empty? [] # --> true
11
+ # empty? {} # --> true
12
+ # empty? '' # --> true
13
+ # empty? null # --> true
14
+ #
15
+ # empty? [ 1, 2, 3 ] # --> false
16
+ # empty? { a: 'A' } # --> false
17
+ # empty? 0 # --> false
18
+ # empty? 'aaa' # --> false
19
+ # ```
20
+ #
21
+ # If the argument is not an array, an object, a string or null, an
22
+ # error is triggered.
23
+ #
24
+ # If there is no argument to the "empty?", the incoming payload['ret']
25
+ # is considered
26
+ #
27
+ # ```
28
+ # {}
29
+ # empty? _ # --> true
30
+ #
31
+ # [ 1, 2, 3 ]
32
+ # empty? _ # --> false
33
+ # ```
34
+ #
35
+ # ## see also
36
+ #
37
+ # any?
38
+
39
+ name 'empty?'
40
+
41
+ def pre_execute
42
+
43
+ unatt_unkeyed_children
44
+ end
45
+
46
+ def receive_last
47
+
48
+ ret =
49
+ case r = payload['ret']
50
+ when Array, Hash, String then r.empty?
51
+ when nil then true
52
+ else
53
+ fail Flor::FlorError.new(
54
+ 'argument is not an array, an object, a string or null', self)
55
+ end
56
+
57
+ wrap_reply('ret' => ret)
58
+ end
59
+ end
60
+
@@ -0,0 +1,94 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Filter < Flor::Pro::Iterator
6
+ #
7
+ # Filters a collection
8
+ #
9
+ # Expects a function in its arguments and a collection to filter
10
+ # in its arguments or as the incoming "ret".
11
+ #
12
+ # Fails if the collection or the function is missing.
13
+ #
14
+ # ```
15
+ # filter [ 1, 2, 3, 4, 5 ]
16
+ # def x
17
+ # = (x % 2) 1
18
+ #
19
+ # # f.ret --> [ 1, 3, 5 ]
20
+ # ```
21
+ #
22
+ # ## with objects (hashes)
23
+ #
24
+ # ```
25
+ # filter { a: 'A', b: 'B', c: 'C', d: 'D' }
26
+ # def k v i
27
+ # #or (k == 'a') (v == 'C') (i == 3)
28
+ # k == 'a' or v == 'C' or i == 3
29
+ #
30
+ # # f.ret --> { 'a' => 'A', 'c' => 'C', 'd' => 'D' }
31
+ # ```
32
+ #
33
+ # ## filter-out
34
+ #
35
+ # Is the negative sibling of "filter".
36
+ #
37
+ # ```
38
+ # filter-out [ 1, 2, 3, 4, 5 ]
39
+ # def x
40
+ # = (x % 2) 0
41
+ #
42
+ # # f.ret --> [ 1, 3, 5 ]
43
+ # ```
44
+ #
45
+ # ## incoming ret
46
+ #
47
+ # When not given directly a collection, `filter` takes it from the
48
+ # incoming "ret"
49
+ #
50
+ # ```
51
+ # { a: 'A', b: 'B', c: 'C', d: 'D' }
52
+ # filter
53
+ # def k v i l # key, value, index, length
54
+ # i = (l - 1) or i = (l - 2)
55
+ # # f.ret --> { 'c' => 'C', 'd' => 'D' }
56
+ # ```
57
+ #
58
+ # ## iterating and functions
59
+ #
60
+ # Iterating functions accept 0 to 3 arguments when iterating over an
61
+ # array and 0 to 4 arguments when iterating over an object.
62
+ #
63
+ # Those arguments are `[ value, index, length ]` for arrays.
64
+ # They are `[ key, value, index, length ]` for objects.
65
+ #
66
+ # The corresponding `key`, `val`, `idx` and `len` variables are also
67
+ # set in the closure for the function call.
68
+ #
69
+ # ## see also
70
+ #
71
+ # map, select, and reject.
72
+
73
+ names %w[ filter filter-out ]
74
+
75
+ protected
76
+
77
+ def receive_iteration
78
+
79
+ @node['res'] << @node['col'][@node['idx']] \
80
+ if (
81
+ (heap == 'filter' && Flor.true?(payload['ret'])) ||
82
+ (heap == 'filter-out' && Flor.false?(payload['ret'])))
83
+ end
84
+
85
+ def iterator_result
86
+
87
+ if @node['ocol'].is_a?(Hash)
88
+ Hash[@node['res']]
89
+ else
90
+ @node['res']
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,67 @@
1
+
2
+ require 'flor/pcore/iterator'
3
+
4
+
5
+ class Flor::Pro::Find < Flor::Pro::Iterator
6
+ #
7
+ # Finds the first matching element.
8
+ #
9
+ # ```
10
+ # find [ 1, 2, 3 ]
11
+ # def elt
12
+ # (elt % 2) == 0
13
+ # # f.ret --> 2
14
+ # ```
15
+ #
16
+ # With objects (maps), it returns the first matching entry (pair).
17
+ # ```
18
+ # find { a: 'A', b: 'B', c: 'C' }
19
+ # def key, val
20
+ # val == 'B'
21
+ # # f.ret --> [ 'b', 'B' ]
22
+ # ```
23
+ #
24
+ # ## iterating and functions
25
+ #
26
+ # Iterating functions accept 0 to 3 arguments when iterating over an
27
+ # array and 0 to 4 arguments when iterating over an object.
28
+ #
29
+ # Those arguments are `[ value, index, length ]` for arrays.
30
+ # They are `[ key, value, index, length ]` for objects.
31
+ #
32
+ # The corresponding `key`, `val`, `idx` and `len` variables are also
33
+ # set in the closure for the function call.
34
+ #
35
+ # ## see also
36
+ #
37
+ # Map and detect, any?.
38
+
39
+ name 'find'
40
+
41
+ protected
42
+
43
+ def pre_iterator
44
+
45
+ # nothing to do
46
+ end
47
+
48
+ def receive_iteration
49
+
50
+ # nothing to do
51
+ end
52
+
53
+ def iterator_over?
54
+
55
+ super || (@node['idx'] > 0 && Flor.true?(payload['ret']))
56
+ end
57
+
58
+ def iterator_result
59
+
60
+ if Flor.true?(payload['ret'])
61
+ @node['col'][@node['idx'] - 1]
62
+ else
63
+ nil
64
+ end
65
+ end
66
+ end
67
+