callable_tree 0.3.7 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +7 -0
  3. data/.github/workflows/build.yml +3 -5
  4. data/.github/workflows/codeql-analysis.yml +4 -4
  5. data/.rubocop.yml +6 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +12 -0
  8. data/Gemfile.lock +3 -3
  9. data/README.md +460 -276
  10. data/callable_tree.gemspec +1 -0
  11. data/examples/builder/external-verbosify.rb +87 -0
  12. data/examples/builder/hooks.rb +67 -0
  13. data/examples/builder/identity.rb +91 -0
  14. data/examples/builder/internal-broadcastable.rb +11 -11
  15. data/examples/builder/internal-composable.rb +11 -11
  16. data/examples/builder/internal-seekable.rb +9 -15
  17. data/examples/builder/logging.rb +36 -39
  18. data/examples/{external-verbosify.rb → class/external-verbosify.rb} +3 -5
  19. data/examples/class/hooks.rb +70 -0
  20. data/examples/{identity.rb → class/identity.rb} +3 -5
  21. data/examples/{internal-broadcastable.rb → class/internal-broadcastable.rb} +0 -0
  22. data/examples/{internal-composable.rb → class/internal-composable.rb} +0 -0
  23. data/examples/{internal-seekable.rb → class/internal-seekable.rb} +3 -5
  24. data/examples/{logging.rb → class/logging.rb} +47 -47
  25. data/lib/callable_tree/node/builder.rb +13 -0
  26. data/lib/callable_tree/node/hooks/terminator.rb +99 -0
  27. data/lib/callable_tree/node/internal/strategy/broadcast.rb +19 -2
  28. data/lib/callable_tree/node/internal/strategy/compose.rb +15 -3
  29. data/lib/callable_tree/node/internal/strategy/seek.rb +11 -1
  30. data/lib/callable_tree/node/internal/strategy.rb +10 -2
  31. data/lib/callable_tree/node/internal.rb +22 -28
  32. data/lib/callable_tree/node/root.rb +1 -0
  33. data/lib/callable_tree/version.rb +1 -1
  34. data/lib/callable_tree.rb +1 -0
  35. metadata +17 -11
  36. data/examples/builder/hooks-caller.rb +0 -38
  37. data/examples/hooks-caller.rb +0 -39
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  # For more information and examples about making a new gem, checkout our
34
34
  # guide at: https://bundler.io/guides/creating_gem.html
35
+ spec.metadata['rubygems_mfa_required'] = 'true'
35
36
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+ require 'json'
5
+ require 'rexml/document'
6
+
7
+ JSONParser =
8
+ CallableTree::Node::Internal::Builder
9
+ .new
10
+ .matcher do |input, **_options|
11
+ File.extname(input) == '.json'
12
+ end
13
+ .caller do |input, **options, &block|
14
+ File.open(input) do |file|
15
+ json = ::JSON.load(file)
16
+ # The following block call is equivalent to calling `super` in the class style.
17
+ block.call(json, **options)
18
+ end
19
+ end
20
+ .terminator { true }
21
+ .build
22
+
23
+ XMLParser =
24
+ CallableTree::Node::Internal::Builder
25
+ .new
26
+ .matcher do |input, **_options|
27
+ File.extname(input) == '.xml'
28
+ end
29
+ .caller do |input, **options, &block|
30
+ File.open(input) do |file|
31
+ # The following block call is equivalent to calling `super` in the class style.
32
+ block.call(REXML::Document.new(file), **options)
33
+ end
34
+ end
35
+ .terminator { true }
36
+ .build
37
+
38
+ def build_json_scraper(type)
39
+ CallableTree::Node::External::Builder
40
+ .new
41
+ .matcher do |input, **_options|
42
+ !input[type.to_s].nil?
43
+ end
44
+ .caller do |input, **_options|
45
+ input[type.to_s]
46
+ .to_h { |element| [element['name'], element['emoji']] }
47
+ end
48
+ .build
49
+ end
50
+
51
+ AnimalsJSONScraper = build_json_scraper(:animals)
52
+ FruitsJSONScraper = build_json_scraper(:fruits)
53
+
54
+ def build_xml_scraper(type)
55
+ CallableTree::Node::External::Builder
56
+ .new
57
+ .matcher do |input, **_options|
58
+ !input.get_elements("//#{type}").empty?
59
+ end
60
+ .caller do |input, **_options|
61
+ input
62
+ .get_elements("//#{type}")
63
+ .first
64
+ .to_h { |element| [element['name'], element['emoji']] }
65
+ end
66
+ .build
67
+ end
68
+
69
+ AnimalsXMLScraper = build_xml_scraper(:animals)
70
+ FruitsXMLScraper = build_xml_scraper(:fruits)
71
+
72
+ tree = CallableTree::Node::Root.new.seekable.append(
73
+ JSONParser.new.seekable.append(
74
+ AnimalsJSONScraper.new.verbosify,
75
+ FruitsJSONScraper.new.verbosify
76
+ ),
77
+ XMLParser.new.seekable.append(
78
+ AnimalsXMLScraper.new.verbosify,
79
+ FruitsXMLScraper.new.verbosify
80
+ )
81
+ )
82
+
83
+ Dir.glob("#{__dir__}/../docs/*") do |file|
84
+ options = { foo: :bar }
85
+ pp tree.call(file, **options)
86
+ puts '---'
87
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+
5
+ HooksSample =
6
+ CallableTree::Node::Internal::Builder
7
+ .new
8
+ .hookable
9
+ .build
10
+
11
+ CallableTree::Node::Root.new.append(
12
+ HooksSample
13
+ .new
14
+ .append(
15
+ # anonymous external node
16
+ lambda do |input, **_options|
17
+ puts "external input: #{input}"
18
+ input * 2
19
+ end
20
+ )
21
+ .before_matcher do |input, **_options|
22
+ puts "before_matcher input: #{input}"
23
+ input + 1
24
+ end
25
+ .around_matcher do |input, **_options, &block|
26
+ puts "around_matcher input: #{input}"
27
+ matched = block.call
28
+ puts "around_matcher matched: #{matched}"
29
+ !matched
30
+ end
31
+ .after_matcher do |matched, **_options|
32
+ puts "after_matcher matched: #{matched}"
33
+ !matched
34
+ end
35
+ .before_caller do |input, **_options|
36
+ puts "before_caller input: #{input}"
37
+ input + 1
38
+ end
39
+ .around_caller do |input, **_options, &block|
40
+ puts "around_caller input: #{input}"
41
+ output = block.call
42
+ puts "around_caller output: #{output}"
43
+ output * input
44
+ end
45
+ .after_caller do |output, **_options|
46
+ puts "after_caller output: #{output}"
47
+ output * 2
48
+ end
49
+ .before_terminator do |output, *_inputs, **_options|
50
+ puts "before_terminator output: #{output}"
51
+ output + 1
52
+ end
53
+ .around_terminator do |output, *_inputs, **_options, &block|
54
+ puts "around_terminator output: #{output}"
55
+ terminated = block.call
56
+ puts "around_terminator terminated: #{terminated}"
57
+ !terminated
58
+ end
59
+ .after_terminator do |terminated, **_options|
60
+ puts "after_terminator terminated: #{terminated}"
61
+ !terminated
62
+ end
63
+ ).tap do |tree|
64
+ options = { foo: :bar }
65
+ output = tree.call(1, **options)
66
+ puts "result: #{output}"
67
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+ require 'json'
5
+ require 'rexml/document'
6
+
7
+ JSONParser =
8
+ CallableTree::Node::Internal::Builder
9
+ .new
10
+ .matcher do |input, **_options|
11
+ File.extname(input) == '.json'
12
+ end
13
+ .caller do |input, **options, &block|
14
+ File.open(input) do |file|
15
+ json = ::JSON.load(file)
16
+ # The following block call is equivalent to calling `super` in the class style.
17
+ block.call(json, **options)
18
+ end
19
+ end
20
+ .terminator { true }
21
+ .identifier { |_node_:| _node_.object_id }
22
+ .build
23
+
24
+ XMLParser =
25
+ CallableTree::Node::Internal::Builder
26
+ .new
27
+ .matcher do |input, **_options|
28
+ File.extname(input) == '.xml'
29
+ end
30
+ .caller do |input, **options, &block|
31
+ File.open(input) do |file|
32
+ # The following block call is equivalent to calling `super` in the class style.
33
+ block.call(REXML::Document.new(file), **options)
34
+ end
35
+ end
36
+ .terminator { true }
37
+ .identifier { |_node_:| _node_.object_id }
38
+ .build
39
+
40
+ def build_json_scraper(type)
41
+ CallableTree::Node::External::Builder
42
+ .new
43
+ .matcher do |input, **_options|
44
+ !input[type.to_s].nil?
45
+ end
46
+ .caller do |input, **_options|
47
+ input[type.to_s]
48
+ .to_h { |element| [element['name'], element['emoji']] }
49
+ end
50
+ .identifier { |_node_:| _node_.object_id }
51
+ .build
52
+ end
53
+
54
+ AnimalsJSONScraper = build_json_scraper(:animals)
55
+ FruitsJSONScraper = build_json_scraper(:fruits)
56
+
57
+ def build_xml_scraper(type)
58
+ CallableTree::Node::External::Builder
59
+ .new
60
+ .matcher do |input, **_options|
61
+ !input.get_elements("//#{type}").empty?
62
+ end
63
+ .caller do |input, **_options|
64
+ input
65
+ .get_elements("//#{type}")
66
+ .first
67
+ .to_h { |element| [element['name'], element['emoji']] }
68
+ end
69
+ .identifier { |_node_:| _node_.object_id }
70
+ .build
71
+ end
72
+
73
+ AnimalsXMLScraper = build_xml_scraper(:animals)
74
+ FruitsXMLScraper = build_xml_scraper(:fruits)
75
+
76
+ tree = CallableTree::Node::Root.new.seekable.append(
77
+ JSONParser.new.seekable.append(
78
+ AnimalsJSONScraper.new.verbosify,
79
+ FruitsJSONScraper.new.verbosify
80
+ ),
81
+ XMLParser.new.seekable.append(
82
+ AnimalsXMLScraper.new.verbosify,
83
+ FruitsXMLScraper.new.verbosify
84
+ )
85
+ )
86
+
87
+ Dir.glob("#{__dir__}/../docs/*") do |file|
88
+ options = { foo: :bar }
89
+ pp tree.call(file, **options)
90
+ puts '---'
91
+ end
@@ -2,57 +2,57 @@
2
2
 
3
3
  require 'callable_tree'
4
4
 
5
- less_than = proc do |num|
5
+ def less_than(num)
6
6
  # The following block call is equivalent to calling `super` in the class style.
7
- proc { |input, &block| block.call(input) && input < num }
7
+ proc { |input, &original| original.call(input) && input < num }
8
8
  end
9
9
 
10
10
  LessThan5 =
11
11
  CallableTree::Node::Internal::Builder
12
12
  .new
13
- .matcher(&less_than.call(5))
13
+ .matcher(&method(:less_than).call(5))
14
14
  .build
15
15
 
16
16
  LessThan10 =
17
17
  CallableTree::Node::Internal::Builder
18
18
  .new
19
- .matcher(&less_than.call(10))
19
+ .matcher(&method(:less_than).call(10))
20
20
  .build
21
21
 
22
- add = proc do |num|
22
+ def add(num)
23
23
  proc { |input| input + num }
24
24
  end
25
25
 
26
26
  Add1 =
27
27
  CallableTree::Node::External::Builder
28
28
  .new
29
- .caller(&add.call(1))
29
+ .caller(&method(:add).call(1))
30
30
  .build
31
31
 
32
- subtract = proc do |num|
32
+ def subtract(num)
33
33
  proc { |input| input - num }
34
34
  end
35
35
 
36
36
  Subtract1 =
37
37
  CallableTree::Node::External::Builder
38
38
  .new
39
- .caller(&subtract.call(1))
39
+ .caller(&method(:subtract).call(1))
40
40
  .build
41
41
 
42
- multiply = proc do |num|
42
+ def multiply(num)
43
43
  proc { |input| input * num }
44
44
  end
45
45
 
46
46
  Multiply2 =
47
47
  CallableTree::Node::External::Builder
48
48
  .new
49
- .caller(&multiply.call(2))
49
+ .caller(&method(:multiply).call(2))
50
50
  .build
51
51
 
52
52
  Multiply3 =
53
53
  CallableTree::Node::External::Builder
54
54
  .new
55
- .caller(&multiply.call(3))
55
+ .caller(&method(:multiply).call(3))
56
56
  .build
57
57
 
58
58
  tree = CallableTree::Node::Root.new.broadcastable.append(
@@ -2,57 +2,57 @@
2
2
 
3
3
  require 'callable_tree'
4
4
 
5
- less_than = proc do |num|
5
+ def less_than(num)
6
6
  # The following block call is equivalent to calling `super` in the class style.
7
- proc { |input, &block| block.call(input) && input < num }
7
+ proc { |input, &original| original.call(input) && input < num }
8
8
  end
9
9
 
10
10
  LessThan5 =
11
11
  CallableTree::Node::Internal::Builder
12
12
  .new
13
- .matcher(&less_than.call(5))
13
+ .matcher(&method(:less_than).call(5))
14
14
  .build
15
15
 
16
16
  LessThan10 =
17
17
  CallableTree::Node::Internal::Builder
18
18
  .new
19
- .matcher(&less_than.call(10))
19
+ .matcher(&method(:less_than).call(10))
20
20
  .build
21
21
 
22
- add = proc do |num|
22
+ def add(num)
23
23
  proc { |input| input + num }
24
24
  end
25
25
 
26
26
  Add1 =
27
27
  CallableTree::Node::External::Builder
28
28
  .new
29
- .caller(&add.call(1))
29
+ .caller(&method(:add).call(1))
30
30
  .build
31
31
 
32
- subtract = proc do |num|
32
+ def subtract(num)
33
33
  proc { |input| input - num }
34
34
  end
35
35
 
36
36
  Subtract1 =
37
37
  CallableTree::Node::External::Builder
38
38
  .new
39
- .caller(&subtract.call(1))
39
+ .caller(&method(:subtract).call(1))
40
40
  .build
41
41
 
42
- multiply = proc do |num|
42
+ def multiply(num)
43
43
  proc { |input| input * num }
44
44
  end
45
45
 
46
46
  Multiply2 =
47
47
  CallableTree::Node::External::Builder
48
48
  .new
49
- .caller(&multiply.call(2))
49
+ .caller(&method(:multiply).call(2))
50
50
  .build
51
51
 
52
52
  Multiply3 =
53
53
  CallableTree::Node::External::Builder
54
54
  .new
55
- .caller(&multiply.call(3))
55
+ .caller(&method(:multiply).call(3))
56
56
  .build
57
57
 
58
58
  tree = CallableTree::Node::Root.new.composable.append(
@@ -10,16 +10,14 @@ JSONParser =
10
10
  .matcher do |input, **_options|
11
11
  File.extname(input) == '.json'
12
12
  end
13
- .caller do |input, **options, &block|
13
+ .caller do |input, **options, &original|
14
14
  File.open(input) do |file|
15
15
  json = ::JSON.load(file)
16
16
  # The following block call is equivalent to calling `super` in the class style.
17
- block.call(json, **options)
17
+ original.call(json, **options)
18
18
  end
19
19
  end
20
- .terminator do
21
- true
22
- end
20
+ .terminator { true }
23
21
  .build
24
22
 
25
23
  XMLParser =
@@ -28,27 +26,24 @@ XMLParser =
28
26
  .matcher do |input, **_options|
29
27
  File.extname(input) == '.xml'
30
28
  end
31
- .caller do |input, **options, &block|
29
+ .caller do |input, **options, &original|
32
30
  File.open(input) do |file|
33
31
  # The following block call is equivalent to calling `super` in the class style.
34
- block.call(REXML::Document.new(file), **options)
32
+ original.call(REXML::Document.new(file), **options)
35
33
  end
36
34
  end
37
- .terminator do
38
- true
39
- end
35
+ .terminator { true }
40
36
  .build
41
37
 
42
38
  def build_json_scraper(type)
43
39
  CallableTree::Node::External::Builder
44
40
  .new
45
41
  .matcher do |input, **_options|
46
- !!input[type.to_s]
42
+ !input[type.to_s].nil?
47
43
  end
48
44
  .caller do |input, **_options|
49
45
  input[type.to_s]
50
- .map { |element| [element['name'], element['emoji']] }
51
- .to_h
46
+ .to_h { |element| [element['name'], element['emoji']] }
52
47
  end
53
48
  .build
54
49
  end
@@ -66,8 +61,7 @@ def build_xml_scraper(type)
66
61
  input
67
62
  .get_elements("//#{type}")
68
63
  .first
69
- .map { |element| [element['name'], element['emoji']] }
70
- .to_h
64
+ .to_h { |element| [element['name'], element['emoji']] }
71
65
  end
72
66
  .build
73
67
  end
@@ -10,16 +10,14 @@ JSONParser =
10
10
  .matcher do |input, **_options|
11
11
  File.extname(input) == '.json'
12
12
  end
13
- .caller do |input, **options, &block|
13
+ .caller do |input, **options, &original|
14
14
  File.open(input) do |file|
15
15
  json = ::JSON.load(file)
16
16
  # The following block call is equivalent to calling `super` in the class style.
17
- block.call(json, **options)
17
+ original.call(json, **options)
18
18
  end
19
19
  end
20
- .terminator do
21
- true
22
- end
20
+ .terminator { true }
23
21
  .hookable
24
22
  .build
25
23
 
@@ -29,15 +27,13 @@ XMLParser =
29
27
  .matcher do |input, **_options|
30
28
  File.extname(input) == '.xml'
31
29
  end
32
- .caller do |input, **options, &block|
30
+ .caller do |input, **options, &original|
33
31
  File.open(input) do |file|
34
32
  # The following block call is equivalent to calling `super` in the class style.
35
- block.call(REXML::Document.new(file), **options)
33
+ original.call(REXML::Document.new(file), **options)
36
34
  end
37
35
  end
38
- .terminator do
39
- true
40
- end
36
+ .terminator { true }
41
37
  .hookable
42
38
  .build
43
39
 
@@ -45,12 +41,11 @@ def build_json_scraper(type)
45
41
  CallableTree::Node::External::Builder
46
42
  .new
47
43
  .matcher do |input, **_options|
48
- !!input[type.to_s]
44
+ !input[type.to_s].nil?
49
45
  end
50
46
  .caller do |input, **_options|
51
47
  input[type.to_s]
52
- .map { |element| [element['name'], element['emoji']] }
53
- .to_h
48
+ .to_h { |element| [element['name'], element['emoji']] }
54
49
  end
55
50
  .hookable
56
51
  .build
@@ -69,8 +64,7 @@ def build_xml_scraper(type)
69
64
  input
70
65
  .get_elements("//#{type}")
71
66
  .first
72
- .map { |element| [element['name'], element['emoji']] }
73
- .to_h
67
+ .to_h { |element| [element['name'], element['emoji']] }
74
68
  end
75
69
  .hookable
76
70
  .build
@@ -79,35 +73,38 @@ end
79
73
  AnimalsXMLScraper = build_xml_scraper(:animals)
80
74
  FruitsXMLScraper = build_xml_scraper(:fruits)
81
75
 
82
- loggable = proc do |node|
83
- indent_size = 2
84
- blank = ' '
85
- list_style = '*'
86
-
87
- node.after_matcher! do |matched, _node_:, **|
88
- prefix = list_style.rjust(_node_.depth * indent_size - indent_size + list_style.length, blank)
89
- puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
90
- matched
91
- end
76
+ module Logging
77
+ INDENT_SIZE = 2
78
+ BLANK = ' '
79
+ LIST_STYLE = '*'
80
+ INPUT_LABEL = 'Input :'
81
+ OUTPUT_LABEL = 'Output:'
92
82
 
93
- if node.external?
94
- input_label = 'Input :'
95
- output_label = 'Output:'
83
+ def self.loggable(node)
84
+ node.after_matcher! do |matched, _node_:, **|
85
+ prefix = LIST_STYLE.rjust((_node_.depth * INDENT_SIZE) - INDENT_SIZE + LIST_STYLE.length, BLANK)
86
+ puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
87
+ matched
88
+ end
96
89
 
97
- node
98
- .before_caller! do |input, *, _node_:, **|
99
- input_prefix = input_label.rjust(_node_.depth * indent_size + input_label.length, blank)
100
- puts "#{input_prefix} #{input}"
101
- input
102
- end
103
- .after_caller! do |output, _node_:, **|
104
- output_prefix = output_label.rjust(_node_.depth * indent_size + output_label.length, blank)
105
- puts "#{output_prefix} #{output}"
106
- output
107
- end
90
+ if node.external?
91
+ node
92
+ .before_caller! do |input, *, _node_:, **|
93
+ input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
94
+ puts "#{input_prefix} #{input}"
95
+ input
96
+ end
97
+ .after_caller! do |output, _node_:, **|
98
+ output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
99
+ puts "#{output_prefix} #{output}"
100
+ output
101
+ end
102
+ end
108
103
  end
109
104
  end
110
105
 
106
+ loggable = Logging.method(:loggable)
107
+
111
108
  tree = CallableTree::Node::Root.new.seekable.append(
112
109
  JSONParser.new.tap(&loggable).seekable.append(
113
110
  AnimalsJSONScraper.new.tap(&loggable).verbosify,
@@ -38,8 +38,7 @@ module Node
38
38
 
39
39
  def call(input, **_options)
40
40
  input[@type.to_s]
41
- .map { |element| [element['name'], element['emoji']] }
42
- .to_h
41
+ .to_h { |element| [element['name'], element['emoji']] }
43
42
  end
44
43
  end
45
44
  end
@@ -78,8 +77,7 @@ module Node
78
77
  input
79
78
  .get_elements("//#{@type}")
80
79
  .first
81
- .map { |element| [element['name'], element['emoji']] }
82
- .to_h
80
+ .to_h { |element| [element['name'], element['emoji']] }
83
81
  end
84
82
  end
85
83
  end
@@ -96,7 +94,7 @@ tree = CallableTree::Node::Root.new.append(
96
94
  )
97
95
  )
98
96
 
99
- Dir.glob("#{__dir__}/docs/*") do |file|
97
+ Dir.glob("#{__dir__}/../docs/*") do |file|
100
98
  options = { foo: :bar }
101
99
  pp tree.call(file, **options)
102
100
  puts '---'
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+
5
+ module Node
6
+ class HooksSample
7
+ include CallableTree::Node::Internal
8
+ prepend CallableTree::Node::Hooks::Matcher
9
+ prepend CallableTree::Node::Hooks::Caller
10
+ prepend CallableTree::Node::Hooks::Terminator
11
+ end
12
+ end
13
+
14
+ CallableTree::Node::Root.new.append(
15
+ Node::HooksSample
16
+ .new
17
+ .append(
18
+ # anonymous external node
19
+ lambda do |input, **_options|
20
+ puts "external input: #{input}"
21
+ input * 2
22
+ end
23
+ )
24
+ .before_matcher do |input, **_options|
25
+ puts "before_matcher input: #{input}"
26
+ input + 1
27
+ end
28
+ .around_matcher do |input, **_options, &block|
29
+ puts "around_matcher input: #{input}"
30
+ matched = block.call
31
+ puts "around_matcher matched: #{matched}"
32
+ !matched
33
+ end
34
+ .after_matcher do |matched, **_options|
35
+ puts "after_matcher matched: #{matched}"
36
+ !matched
37
+ end
38
+ .before_caller do |input, **_options|
39
+ puts "before_caller input: #{input}"
40
+ input + 1
41
+ end
42
+ .around_caller do |input, **_options, &block|
43
+ puts "around_caller input: #{input}"
44
+ output = block.call
45
+ puts "around_caller output: #{output}"
46
+ output * input
47
+ end
48
+ .after_caller do |output, **_options|
49
+ puts "after_caller output: #{output}"
50
+ output * 2
51
+ end
52
+ .before_terminator do |output, *_inputs, **_options|
53
+ puts "before_terminator output: #{output}"
54
+ output + 1
55
+ end
56
+ .around_terminator do |output, *_inputs, **_options, &block|
57
+ puts "around_terminator output: #{output}"
58
+ terminated = block.call
59
+ puts "around_terminator terminated: #{terminated}"
60
+ !terminated
61
+ end
62
+ .after_terminator do |terminated, **_options|
63
+ puts "after_terminator terminated: #{terminated}"
64
+ !terminated
65
+ end
66
+ ).tap do |tree|
67
+ options = { foo: :bar }
68
+ output = tree.call(1, **options)
69
+ puts "result: #{output}"
70
+ end