callable_tree 0.3.1 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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