callable_tree 0.3.8 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,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
- json = ::JSON.load(file)
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,15 +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
- json = ::JSON.load(file)
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
20
  .terminator { true }
21
- # .identifier { |_node_:| :as_you_like } # optional
22
21
  .hookable
23
22
  .build
24
23
 
@@ -28,14 +27,13 @@ XMLParser =
28
27
  .matcher do |input, **_options|
29
28
  File.extname(input) == '.xml'
30
29
  end
31
- .caller do |input, **options, &block|
30
+ .caller do |input, **options, &original|
32
31
  File.open(input) do |file|
33
32
  # The following block call is equivalent to calling `super` in the class style.
34
- block.call(REXML::Document.new(file), **options)
33
+ original.call(REXML::Document.new(file), **options)
35
34
  end
36
35
  end
37
36
  .terminator { true }
38
- # .identifier { |_node_:| :as_you_like } # optional
39
37
  .hookable
40
38
  .build
41
39
 
@@ -43,14 +41,12 @@ def build_json_scraper(type)
43
41
  CallableTree::Node::External::Builder
44
42
  .new
45
43
  .matcher do |input, **_options|
46
- !!input[type.to_s]
44
+ !input[type.to_s].nil?
47
45
  end
48
46
  .caller do |input, **_options|
49
47
  input[type.to_s]
50
- .map { |element| [element['name'], element['emoji']] }
51
- .to_h
48
+ .to_h { |element| [element['name'], element['emoji']] }
52
49
  end
53
- # .identifier { |_node_:| :as_you_like } # optional
54
50
  .hookable
55
51
  .build
56
52
  end
@@ -68,10 +64,8 @@ def build_xml_scraper(type)
68
64
  input
69
65
  .get_elements("//#{type}")
70
66
  .first
71
- .map { |element| [element['name'], element['emoji']] }
72
- .to_h
67
+ .to_h { |element| [element['name'], element['emoji']] }
73
68
  end
74
- # .identifier { |_node_:| :as_you_like } # optional
75
69
  .hookable
76
70
  .build
77
71
  end
@@ -93,19 +87,19 @@ module Logging
93
87
  matched
94
88
  end
95
89
 
96
- if node.external?
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
108
- end
90
+ return unless node.external?
91
+
92
+ node
93
+ .before_caller! do |input, *, _node_:, **|
94
+ input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
95
+ puts "#{input_prefix} #{input}"
96
+ input
97
+ end
98
+ .after_caller! do |output, _node_:, **|
99
+ output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
100
+ puts "#{output_prefix} #{output}"
101
+ output
102
+ end
109
103
  end
110
104
  end
111
105
 
@@ -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
@@ -55,8 +55,7 @@ module Node
55
55
 
56
56
  def call(input, **_options)
57
57
  input[@type.to_s]
58
- .map { |element| [element['name'], element['emoji']] }
59
- .to_h
58
+ .to_h { |element| [element['name'], element['emoji']] }
60
59
  end
61
60
  end
62
61
  end
@@ -99,8 +98,7 @@ module Node
99
98
  input
100
99
  .get_elements("//#{@type}")
101
100
  .first
102
- .map { |element| [element['name'], element['emoji']] }
103
- .to_h
101
+ .to_h { |element| [element['name'], element['emoji']] }
104
102
  end
105
103
  end
106
104
  end
@@ -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
@@ -58,8 +58,7 @@ module Node
58
58
 
59
59
  def call(input, **_options)
60
60
  input[@type.to_s]
61
- .map { |element| [element['name'], element['emoji']] }
62
- .to_h
61
+ .to_h { |element| [element['name'], element['emoji']] }
63
62
  end
64
63
  end
65
64
  end
@@ -105,8 +104,7 @@ module Node
105
104
  input
106
105
  .get_elements("//#{@type}")
107
106
  .first
108
- .map { |element| [element['name'], element['emoji']] }
109
- .to_h
107
+ .to_h { |element| [element['name'], element['emoji']] }
110
108
  end
111
109
  end
112
110
  end
@@ -126,19 +124,19 @@ module Logging
126
124
  matched
127
125
  end
128
126
 
129
- if node.external?
130
- node
131
- .before_caller! do |input, *, _node_:, **|
132
- input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
133
- puts "#{input_prefix} #{input}"
134
- input
135
- end
136
- .after_caller! do |output, _node_:, **|
137
- output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
138
- puts "#{output_prefix} #{output}"
139
- output
140
- end
141
- end
127
+ return unless node.external?
128
+
129
+ node
130
+ .before_caller! do |input, *, _node_:, **|
131
+ input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
132
+ puts "#{input_prefix} #{input}"
133
+ input
134
+ end
135
+ .after_caller! do |output, _node_:, **|
136
+ output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
137
+ puts "#{output_prefix} #{output}"
138
+ output
139
+ end
142
140
  end
143
141
  end
144
142
 
@@ -6,10 +6,10 @@ module CallableTree
6
6
  include Node
7
7
 
8
8
  def self.included(mod)
9
- if mod.include?(Internal)
10
- raise ::CallableTree::Error,
11
- "#{mod} cannot include #{self} together with #{Internal}"
12
- end
9
+ return unless mod.include?(Internal)
10
+
11
+ raise ::CallableTree::Error,
12
+ "#{mod} cannot include #{self} together with #{Internal}"
13
13
  end
14
14
 
15
15
  def self.proxify(callable)
@@ -7,9 +7,19 @@ module CallableTree
7
7
  class Broadcast
8
8
  include Strategy
9
9
 
10
+ def initialize(matchable: true, terminable: false)
11
+ self.matchable = matchable
12
+ self.terminable = terminable
13
+ end
14
+
10
15
  def call(nodes, *inputs, **options)
11
- nodes.map do |node|
12
- node.call(*inputs, **options) if node.match?(*inputs, **options)
16
+ nodes.each_with_object([]) do |node, outputs|
17
+ output = (node.call(*inputs, **options) if matcher.call(node, *inputs, **options))
18
+ outputs << output
19
+
20
+ break outputs if terminator.call(node, output, *inputs, **options)
21
+
22
+ outputs
13
23
  end
14
24
  end
15
25
  end
@@ -7,12 +7,19 @@ module CallableTree
7
7
  class Compose
8
8
  include Strategy
9
9
 
10
+ def initialize(matchable: true, terminable: false)
11
+ self.matchable = matchable
12
+ self.terminable = terminable
13
+ end
14
+
10
15
  def call(nodes, *inputs, **options)
11
16
  head, *tail = inputs
12
17
  nodes.reduce(head) do |input, node|
13
- inputs = [input, *tail]
14
- if node.match?(*inputs, **options)
15
- node.call(*inputs, **options)
18
+ if matcher.call(node, input, *tail, **options)
19
+ output = node.call(input, *tail, **options)
20
+ break output if terminator.call(node, output, input, *tail, **options)
21
+
22
+ output
16
23
  else
17
24
  input
18
25
  end
@@ -7,13 +7,18 @@ module CallableTree
7
7
  class Seek
8
8
  include Strategy
9
9
 
10
+ def initialize(matchable: true, terminable: true)
11
+ self.matchable = matchable
12
+ self.terminable = terminable
13
+ end
14
+
10
15
  def call(nodes, *inputs, **options)
11
16
  nodes
12
17
  .lazy
13
- .select { |node| node.match?(*inputs, **options) }
18
+ .select { |node| matcher.call(node, *inputs, **options) }
14
19
  .map do |node|
15
20
  output = node.call(*inputs, **options)
16
- terminated = node.terminate?(output, *inputs, **options)
21
+ terminated = terminator.call(node, output, *inputs, **options)
17
22
  [output, terminated]
18
23
  end
19
24
  .select { |_output, terminated| terminated }