callable_tree 0.3.1 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c16eb0b2fd83ffd98d61bca938bd449dac9c004e8240c4f1a3b61242bf841163
4
- data.tar.gz: 9919ffcda275a5a5bcf81b0bfae40087cae1f701fc0b7b915fece81c21a79d6b
3
+ metadata.gz: 8cdb3e4595a6233e401511b3a1cb371cacc3bcf6aa38aa78779928a532124103
4
+ data.tar.gz: abfb837062826d1c3ad644b127eac6b54241106b6feb29f4750add2104676750
5
5
  SHA512:
6
- metadata.gz: 98c022cc2b12dccf2333f1a1fc079febe80f597bbbfbd4565384b88987c92c2426d7986ee80c11e1361139b95d495fdff9237e4f986d57dbb7eb355ce8244a0b
7
- data.tar.gz: bcee44379ab11292a5c3bba4b0d37f2bdc2a6f587f9a2a757c11c6093d29fdbd1fe20bd9e0ee6561d98785121222ae1959b412ca8b4ecb5ddf579504f5a704c4
6
+ metadata.gz: a44400b690e3b04f9f1abef9eacc7ddd648121015c3d0e919cf4a0bfab8f4ffa30ffa55dc71b9eb8a4eb174be64ab83a46f1c71457107169f32271182998fceb
7
+ data.tar.gz: 52ece74206ae1cb94cd53e9920a8cdc29aa00874dee0f4a4c214dcf679d1d0d2374217585828eebf642374ca4676a503e819b4a16fbf5c26fa7004b81da971ff
@@ -11,7 +11,7 @@ jobs:
11
11
  - uses: ruby/setup-ruby@v1
12
12
  with:
13
13
  ruby-version: ${{ matrix.ruby }}
14
- - run: gem install bundler:2.3.3
14
+ - run: gem install bundler:2.3.7
15
15
  - uses: actions/cache@v2
16
16
  with:
17
17
  path: vendor/bundle
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.0
1
+ 3.1.1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.4] - 2022-03-13
4
+
5
+ - Add `CallableTree::Node::Internal::Builder`. (experimental)
6
+ See `examples/builder/*.rb` for details.
7
+ - Add `CallableTree::Node::External::Builder`. (experimental)
8
+ See `examples/builder/*.rb` for details.
9
+
10
+ ## [0.3.3] - 2022-02-19
11
+
12
+ - Add `recursive` option to `CallableTree::Node::Internal#reject` and `CallableTree::Node::Internal#reject!`.
13
+ - Add `CallableTree::Node::Internal#find` to return the first node evaluated as `true` by block.
14
+
15
+ ## [0.3.2] - 2022-02-05
16
+
17
+ - Change `CallableTree::Node::Hooks::Call#before_call` to return a new instance.
18
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#before_call!` that makes destructive change.
19
+ - Change `CallableTree::Node::Hooks::Call#around_call` to return a new instance.
20
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#around_call!` that makes destructive change.
21
+ - Change `CallableTree::Node::Hooks::Call#after_call` to return a new instance.
22
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#after_call!` that makes destructive change.
23
+
3
24
  ## [0.3.1] - 2022-01-10
4
25
 
5
26
  - Add `CallableTree::Node::Internal#seek?` to check whether the node's strategy is `seek` or not.
data/Gemfile.lock CHANGED
@@ -1,30 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- callable_tree (0.3.1)
4
+ callable_tree (0.3.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.5.0)
10
10
  rake (13.0.6)
11
- rspec (3.10.0)
12
- rspec-core (~> 3.10.0)
13
- rspec-expectations (~> 3.10.0)
14
- rspec-mocks (~> 3.10.0)
15
- rspec-core (3.10.1)
16
- rspec-support (~> 3.10.0)
17
- rspec-expectations (3.10.1)
11
+ rspec (3.11.0)
12
+ rspec-core (~> 3.11.0)
13
+ rspec-expectations (~> 3.11.0)
14
+ rspec-mocks (~> 3.11.0)
15
+ rspec-core (3.11.0)
16
+ rspec-support (~> 3.11.0)
17
+ rspec-expectations (3.11.0)
18
18
  diff-lcs (>= 1.2.0, < 2.0)
19
- rspec-support (~> 3.10.0)
20
- rspec-mocks (3.10.2)
19
+ rspec-support (~> 3.11.0)
20
+ rspec-mocks (3.11.0)
21
21
  diff-lcs (>= 1.2.0, < 2.0)
22
- rspec-support (~> 3.10.0)
23
- rspec-support (3.10.3)
22
+ rspec-support (~> 3.11.0)
23
+ rspec-support (3.11.0)
24
24
 
25
25
  PLATFORMS
26
- x86_64-darwin-19
27
- x86_64-darwin-20
26
+ x86_64-darwin-21
28
27
 
29
28
  DEPENDENCIES
30
29
  callable_tree!
@@ -32,4 +31,4 @@ DEPENDENCIES
32
31
  rspec (~> 3.0)
33
32
 
34
33
  BUNDLED WITH
35
- 2.3.3
34
+ 2.3.7
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+
5
+ Root =
6
+ CallableTree::Node::Internal::Builder
7
+ .new
8
+ .hookable
9
+ .build
10
+
11
+ Root
12
+ .new
13
+ .before_call do |input, **_options|
14
+ puts "before_call input: #{input}"
15
+ input + 1
16
+ end
17
+ .append(
18
+ # anonymous external node
19
+ lambda do |input, **_options|
20
+ puts "external input: #{input}"
21
+ input * 2
22
+ end
23
+ )
24
+ .around_call do |input, **_options, &block|
25
+ puts "around_call input: #{input}"
26
+ output = block.call
27
+ puts "around_call output: #{output}"
28
+ output * input
29
+ end
30
+ .after_call do |output, **_options|
31
+ puts "after_call output: #{output}"
32
+ output * 2
33
+ end
34
+ .tap do |tree|
35
+ options = { foo: :bar }
36
+ output = tree.call(1, **options)
37
+ puts "result: #{output}"
38
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+
5
+ less_than = proc do |num|
6
+ # The following block call is equivalent to calling `super` in the class style.
7
+ proc { |input, &block| block.call(input) && input < num }
8
+ end
9
+
10
+ LessThan5 =
11
+ CallableTree::Node::Internal::Builder
12
+ .new
13
+ .matcher(&less_than.call(5))
14
+ .build
15
+
16
+ LessThan10 =
17
+ CallableTree::Node::Internal::Builder
18
+ .new
19
+ .matcher(&less_than.call(10))
20
+ .build
21
+
22
+ add = proc do |num|
23
+ proc { |input| input + num }
24
+ end
25
+
26
+ Add1 =
27
+ CallableTree::Node::External::Builder
28
+ .new
29
+ .caller(&add.call(1))
30
+ .build
31
+
32
+ subtract = proc do |num|
33
+ proc { |input| input - num }
34
+ end
35
+
36
+ Subtract1 =
37
+ CallableTree::Node::External::Builder
38
+ .new
39
+ .caller(&subtract.call(1))
40
+ .build
41
+
42
+ multiply = proc do |num|
43
+ proc { |input| input * num }
44
+ end
45
+
46
+ Multiply2 =
47
+ CallableTree::Node::External::Builder
48
+ .new
49
+ .caller(&multiply.call(2))
50
+ .build
51
+
52
+ Multiply3 =
53
+ CallableTree::Node::External::Builder
54
+ .new
55
+ .caller(&multiply.call(3))
56
+ .build
57
+
58
+ tree = CallableTree::Node::Root.new.broadcast.append(
59
+ LessThan5.new.broadcast.append(
60
+ Multiply2.new,
61
+ Add1.new
62
+ ),
63
+ LessThan10.new.broadcast.append(
64
+ Multiply3.new,
65
+ Subtract1.new
66
+ )
67
+ )
68
+
69
+ (0..10).each do |input|
70
+ output = tree.call(input)
71
+ puts "#{input} -> #{output}"
72
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+
5
+ less_than = proc do |num|
6
+ # The following block call is equivalent to calling `super` in the class style.
7
+ proc { |input, &block| block.call(input) && input < num }
8
+ end
9
+
10
+ LessThan5 =
11
+ CallableTree::Node::Internal::Builder
12
+ .new
13
+ .matcher(&less_than.call(5))
14
+ .build
15
+
16
+ LessThan10 =
17
+ CallableTree::Node::Internal::Builder
18
+ .new
19
+ .matcher(&less_than.call(10))
20
+ .build
21
+
22
+ add = proc do |num|
23
+ proc { |input| input + num }
24
+ end
25
+
26
+ Add1 =
27
+ CallableTree::Node::External::Builder
28
+ .new
29
+ .caller(&add.call(1))
30
+ .build
31
+
32
+ subtract = proc do |num|
33
+ proc { |input| input - num }
34
+ end
35
+
36
+ Subtract1 =
37
+ CallableTree::Node::External::Builder
38
+ .new
39
+ .caller(&subtract.call(1))
40
+ .build
41
+
42
+ multiply = proc do |num|
43
+ proc { |input| input * num }
44
+ end
45
+
46
+ Multiply2 =
47
+ CallableTree::Node::External::Builder
48
+ .new
49
+ .caller(&multiply.call(2))
50
+ .build
51
+
52
+ Multiply3 =
53
+ CallableTree::Node::External::Builder
54
+ .new
55
+ .caller(&multiply.call(3))
56
+ .build
57
+
58
+ tree = CallableTree::Node::Root.new.compose.append(
59
+ LessThan5.new.compose.append(
60
+ Multiply2.new,
61
+ Add1.new
62
+ ),
63
+ LessThan10.new.compose.append(
64
+ Multiply3.new,
65
+ Subtract1.new
66
+ )
67
+ )
68
+
69
+ (0..10).each do |input|
70
+ output = tree.call(input)
71
+ puts "#{input} -> #{output}"
72
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'callable_tree'
4
+ require 'json'
5
+ require 'rexml/document'
6
+
7
+ module JSONParser
8
+ def self.build
9
+ CallableTree::Node::Internal::Builder
10
+ .new
11
+ .matcher do |input, **_options|
12
+ File.extname(input) == '.json'
13
+ end
14
+ .caller do |input, **options, &block|
15
+ File.open(input) do |file|
16
+ json = ::JSON.load(file)
17
+ # The following block call is equivalent to calling `super` in the class style.
18
+ block.call(json, **options)
19
+ end
20
+ end
21
+ .terminater do
22
+ true
23
+ end
24
+ .build
25
+ end
26
+ end
27
+
28
+ module XMLParser
29
+ def self.build
30
+ CallableTree::Node::Internal::Builder
31
+ .new
32
+ .matcher do |input, **_options|
33
+ File.extname(input) == '.xml'
34
+ end
35
+ .caller do |input, **options, &block|
36
+ File.open(input) do |file|
37
+ # The following block call is equivalent to calling `super` in the class style.
38
+ block.call(REXML::Document.new(file), **options)
39
+ end
40
+ end
41
+ .terminater do
42
+ true
43
+ end
44
+ .build
45
+ end
46
+ end
47
+
48
+ module JSONScraper
49
+ def self.build(type)
50
+ CallableTree::Node::External::Builder
51
+ .new
52
+ .matcher do |input, **_options|
53
+ !!input[type.to_s]
54
+ end
55
+ .caller do |input, **_options|
56
+ input[type.to_s]
57
+ .map { |element| [element['name'], element['emoji']] }
58
+ .to_h
59
+ end
60
+ .build
61
+ end
62
+ end
63
+
64
+ module XMLScraper
65
+ def self.build(type)
66
+ CallableTree::Node::External::Builder
67
+ .new
68
+ .matcher do |input, **_options|
69
+ !input.get_elements("//#{type}").empty?
70
+ end
71
+ .caller do |input, **_options|
72
+ input
73
+ .get_elements("//#{type}")
74
+ .first
75
+ .map { |element| [element['name'], element['emoji']] }
76
+ .to_h
77
+ end
78
+ .build
79
+ end
80
+ end
81
+
82
+ tree = CallableTree::Node::Root.new.append(
83
+ JSONParser.build.new.append(
84
+ JSONScraper.build(:animals).new,
85
+ JSONScraper.build(:fruits).new
86
+ ),
87
+ XMLParser.build.new.append(
88
+ XMLScraper.build(:animals).new,
89
+ XMLScraper.build(:fruits).new
90
+ )
91
+ )
92
+
93
+ Dir.glob("#{__dir__}/../docs/*") do |file|
94
+ options = { foo: :bar }
95
+ pp tree.call(file, **options)
96
+ puts '---'
97
+ end
@@ -9,9 +9,10 @@ module Node
9
9
  end
10
10
  end
11
11
 
12
- Node::HooksSample.new
12
+ Node::HooksSample
13
+ .new
13
14
  .before_call do |input, **_options|
14
- puts "before_call input: #{input}";
15
+ puts "before_call input: #{input}"
15
16
  input + 1
16
17
  end
17
18
  .append(
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module Builder
6
+ def matcher(&block)
7
+ @matcher = block
8
+ self
9
+ end
10
+
11
+ def caller(&block)
12
+ @caller = block
13
+ self
14
+ end
15
+
16
+ def terminater(&block)
17
+ @terminater = block
18
+ self
19
+ end
20
+
21
+ def hookable(hookable = true)
22
+ @hookable = hookable
23
+ self
24
+ end
25
+
26
+ def build(node_type:)
27
+ matcher = @matcher
28
+ caller = @caller
29
+ terminater = @terminater
30
+ hookable = @hookable
31
+
32
+ validate(
33
+ matcher: matcher,
34
+ caller: caller,
35
+ terminater: terminater
36
+ )
37
+
38
+ ::Class
39
+ .new do
40
+ include node_type
41
+ prepend Hooks::Call if hookable
42
+
43
+ if matcher
44
+ define_method(:match?) do |*inputs, **options|
45
+ matcher.call(*inputs, **options) do |*inputs, **options|
46
+ super(*inputs, **options)
47
+ end
48
+ end
49
+ end
50
+
51
+ if caller
52
+ define_method(:call) do |*inputs, **options|
53
+ caller.call(*inputs, **options) do |*inputs, **options|
54
+ super(*inputs, **options)
55
+ end
56
+ end
57
+ end
58
+
59
+ if terminater
60
+ define_method(:terminate?) do |output, *inputs, **options|
61
+ terminater.call(output, *inputs, **options) do |output, *inputs, **options|
62
+ super(output, *inputs, **options)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def validate(matcher:, caller:, terminater:)
72
+ raise ::CallableTree::Error, 'Not implemented'
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module External
6
+ class Builder
7
+ include Node::Builder
8
+
9
+ class Error < StandardError; end
10
+
11
+ def build
12
+ super(node_type: External)
13
+ end
14
+
15
+ private
16
+
17
+ def validate(matcher:, caller:, terminater:)
18
+ raise Error 'caller is required' unless caller
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -9,16 +9,28 @@ module CallableTree
9
9
  end
10
10
 
11
11
  def before_call(&block)
12
+ clone.before_call!(&block)
13
+ end
14
+
15
+ def before_call!(&block)
12
16
  before_callbacks << block
13
17
  self
14
18
  end
15
19
 
16
20
  def around_call(&block)
21
+ clone.around_call!(&block)
22
+ end
23
+
24
+ def around_call!(&block)
17
25
  around_callbacks << block
18
26
  self
19
27
  end
20
28
 
21
29
  def after_call(&block)
30
+ clone.after_call!(&block)
31
+ end
32
+
33
+ def after_call!(&block)
22
34
  after_callbacks << block
23
35
  self
24
36
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module Internal
6
+ class Builder
7
+ include Node::Builder
8
+
9
+ def build
10
+ super(node_type: Internal)
11
+ end
12
+
13
+ private
14
+
15
+ def validate(matcher:, caller:, terminater:)
16
+ # noop
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -17,9 +17,7 @@ module CallableTree
17
17
  end
18
18
 
19
19
  def append(*callables)
20
- clone.tap do |node|
21
- node.append!(*callables)
22
- end
20
+ clone.append!(*callables)
23
21
  end
24
22
 
25
23
  def append!(*callables)
@@ -30,21 +28,38 @@ module CallableTree
30
28
  self
31
29
  end
32
30
 
33
- def reject(&block)
34
- clone.tap do |node|
35
- node.reject!(&block)
31
+ def find(recursive: false, &block)
32
+ node = child_nodes.find(&block)
33
+ return node if node
34
+
35
+ if recursive
36
+ child_nodes
37
+ .lazy
38
+ .select { |node| node.is_a?(Internal) }
39
+ .map { |node| node.find(recursive: true, &block) }
40
+ .reject(&:nil?)
41
+ .first
36
42
  end
37
43
  end
38
44
 
39
- def reject!(&block)
45
+ def reject(recursive: false, &block)
46
+ clone.reject!(recursive: recursive, &block)
47
+ end
48
+
49
+ def reject!(recursive: false, &block)
40
50
  child_nodes.reject!(&block)
51
+
52
+ if recursive
53
+ child_nodes.each do |node|
54
+ node.reject!(recursive: true, &block) if node.is_a?(Internal)
55
+ end
56
+ end
57
+
41
58
  self
42
59
  end
43
60
 
44
61
  def shake(&block)
45
- clone.tap do |node|
46
- node.shake!(&block)
47
- end
62
+ clone.shake!(&block)
48
63
  end
49
64
 
50
65
  def shake!(&block)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.3.1'
4
+ VERSION = '0.3.4'
5
5
  end
data/lib/callable_tree.rb CHANGED
@@ -15,4 +15,7 @@ require_relative 'callable_tree/node/internal/strategy/compose'
15
15
  require_relative 'callable_tree/node/external/verbose'
16
16
  require_relative 'callable_tree/node/external'
17
17
  require_relative 'callable_tree/node/internal'
18
+ require_relative 'callable_tree/node/builder'
19
+ require_relative 'callable_tree/node/internal/builder'
20
+ require_relative 'callable_tree/node/external/builder'
18
21
  require_relative 'callable_tree/node/root'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: callable_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-10 00:00:00.000000000 Z
11
+ date: 2022-03-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Builds a tree by linking callable nodes. The nodes that match the conditions
14
14
  are called in a chain from the root node to the leaf node. These are like nested
@@ -33,6 +33,10 @@ files:
33
33
  - bin/console
34
34
  - bin/setup
35
35
  - callable_tree.gemspec
36
+ - examples/builder/hooks-call.rb
37
+ - examples/builder/internal-broadcast.rb
38
+ - examples/builder/internal-compose.rb
39
+ - examples/builder/internal-seek.rb
36
40
  - examples/docs/animals.json
37
41
  - examples/docs/animals.xml
38
42
  - examples/docs/fruits.json
@@ -46,10 +50,13 @@ files:
46
50
  - examples/logging.rb
47
51
  - lib/callable_tree.rb
48
52
  - lib/callable_tree/node.rb
53
+ - lib/callable_tree/node/builder.rb
49
54
  - lib/callable_tree/node/external.rb
55
+ - lib/callable_tree/node/external/builder.rb
50
56
  - lib/callable_tree/node/external/verbose.rb
51
57
  - lib/callable_tree/node/hooks/call.rb
52
58
  - lib/callable_tree/node/internal.rb
59
+ - lib/callable_tree/node/internal/builder.rb
53
60
  - lib/callable_tree/node/internal/strategy.rb
54
61
  - lib/callable_tree/node/internal/strategy/broadcast.rb
55
62
  - lib/callable_tree/node/internal/strategy/compose.rb
@@ -62,7 +69,7 @@ licenses:
62
69
  metadata:
63
70
  homepage_uri: https://github.com/jsmmr/ruby_callable_tree
64
71
  source_code_uri: https://github.com/jsmmr/ruby_callable_tree
65
- changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.1/CHANGELOG.md
72
+ changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.4/CHANGELOG.md
66
73
  post_install_message:
67
74
  rdoc_options: []
68
75
  require_paths:
@@ -78,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
85
  - !ruby/object:Gem::Version
79
86
  version: '0'
80
87
  requirements: []
81
- rubygems_version: 3.3.3
88
+ rubygems_version: 3.3.7
82
89
  signing_key:
83
90
  specification_version: 4
84
91
  summary: Builds a tree by linking callable nodes. The nodes that match the conditions