behave_fun 0.1.1 → 0.2.3

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: fa6285d17ba7200bca3e11fb9cdb7c6fb538a7461f8cb2d9c4496e5a1f885a90
4
- data.tar.gz: 196808930dec23a365d3825da90c20e85e3a4f780a3857b67f768f718595a4fb
3
+ metadata.gz: e526abe95ba12a46398d54816db835b06d7fd637fa12d8532717de73d859b706
4
+ data.tar.gz: 4b8de5a4c3f9614e432c0e4a975f96a7b461e6b4be726f817b6a44ac2188e75e
5
5
  SHA512:
6
- metadata.gz: f1cd5d323dfd2db92b4d9ac41b12cabf14ac9a56a14a317db64f32b23513f92ce0ce31285881d3e2feb0560603627891d392534ffec63ba378303eae244738fc
7
- data.tar.gz: '01139c43255bb5130e327d2152b42964266adac83752314de0923898f2eb543b438e306a0027321b0139b120c2ac06fb6f0aa17138e8f2957df0b70fc36001f8'
6
+ metadata.gz: ce0fb474121dd2a64da415a002a0d02f20cba724def89a3cac06dd05cc1601cb4eb467da4293f748e4bd4985ef25a50b79d864633ec7834e348e33107a69bfb3
7
+ data.tar.gz: 89c72baf8266aad35d239ea8f56e8aff7a2b71ff22533440b771cf98ed90c5c3dd351f5967c560c0a69514d422d0a0ad00f3a5972fb4fdf67578e8d1dfb7c53d
@@ -1,14 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- behave_fun (0.1.1)
4
+ behave_fun (0.2.3)
5
5
  activesupport (~> 6.0.0)
6
+ dry-types (~> 1.4.0)
6
7
  zeitwerk (~> 2.3.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (6.0.3)
12
+ activesupport (6.0.3.1)
12
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
14
  i18n (>= 0.7, < 2)
14
15
  minitest (~> 5.1)
@@ -16,9 +17,31 @@ GEM
16
17
  zeitwerk (~> 2.2, >= 2.2.2)
17
18
  concurrent-ruby (1.1.6)
18
19
  diff-lcs (1.3)
20
+ dry-configurable (0.11.5)
21
+ concurrent-ruby (~> 1.0)
22
+ dry-core (~> 0.4, >= 0.4.7)
23
+ dry-equalizer (~> 0.2)
24
+ dry-container (0.7.2)
25
+ concurrent-ruby (~> 1.0)
26
+ dry-configurable (~> 0.1, >= 0.1.3)
27
+ dry-core (0.4.9)
28
+ concurrent-ruby (~> 1.0)
29
+ dry-equalizer (0.3.0)
30
+ dry-inflector (0.2.0)
31
+ dry-logic (1.0.6)
32
+ concurrent-ruby (~> 1.0)
33
+ dry-core (~> 0.2)
34
+ dry-equalizer (~> 0.2)
35
+ dry-types (1.4.0)
36
+ concurrent-ruby (~> 1.0)
37
+ dry-container (~> 0.3)
38
+ dry-core (~> 0.4, >= 0.4.4)
39
+ dry-equalizer (~> 0.3)
40
+ dry-inflector (~> 0.1, >= 0.1.2)
41
+ dry-logic (~> 1.0, >= 1.0.2)
19
42
  i18n (1.8.2)
20
43
  concurrent-ruby (~> 1.0)
21
- minitest (5.14.0)
44
+ minitest (5.14.1)
22
45
  rake (12.3.3)
23
46
  rspec (3.9.0)
24
47
  rspec-core (~> 3.9.0)
data/README.md CHANGED
@@ -13,36 +13,43 @@ Main features:
13
13
 
14
14
  Add this line to your application's Gemfile:
15
15
 
16
- ```ruby
16
+ ``` ruby
17
17
  gem 'behave_fun'
18
18
  ```
19
19
 
20
20
  And then execute:
21
21
 
22
+ ```
22
23
  $ bundle install
24
+ ```
23
25
 
24
26
  Or install it yourself as:
25
27
 
28
+ ```
26
29
  $ gem install behave_fun
30
+ ```
27
31
 
28
32
  ## Usage
29
33
 
30
34
  To build a behavior tree:
31
35
 
32
36
  ``` ruby
37
+ builder = BehaveFun.build_builder {
38
+ # add_task_type YourCustomTask
39
+ }
33
40
  # ruby dsl
34
- tree = BehaveFun.build_tree { success }
41
+ tree = builder.build_tree { success }
35
42
  # from hash
36
- tree = BehaveFun.build_tree_from_hash(type: :success)
43
+ tree = builder.build_tree_from_hash(type: :success)
37
44
  # from json
38
- tree = BehaveFun.build_tree_from_json(json_string)
45
+ tree = builder.build_tree_from_json(json_string)
39
46
  ```
40
47
 
41
48
  To build a complex behavior tree:
42
49
 
43
50
  ``` ruby
44
51
  # write_spec, write_code, run_spec, git_push and release_gem are customized tasks
45
- tree = BehaveFun.build_tree {
52
+ tree = builder.build_tree {
46
53
  sequence {
47
54
  until_success {
48
55
  sequence {
@@ -57,7 +64,7 @@ tree = BehaveFun.build_tree {
57
64
  }
58
65
  ```
59
66
 
60
- To create customized task, create a class that extends `BehaveFun::Task`. Don't forget call `running` `success` or `fail` in `#execute` method at the end.
67
+ To create customized task, create a class that extends `BehaveFun::Task` (or use a lambda if only need to overwrite `#execute` method). Don't forget call `running` `success` or `fail` in `#execute` method at the end.
61
68
 
62
69
  ``` ruby
63
70
  # a task that increase data by 1, always success
@@ -66,18 +73,17 @@ class Counter < BehaveFun::Task
66
73
  context[:counter] += 1
67
74
  success
68
75
  end
69
-
70
- add_to_task_builder
71
76
  end
72
77
 
73
78
  # a task that detect tree data is even or not
74
- class IsCounterEven < BehaveFun::Task
75
- def execute
76
- context[:counter].even? ? success : fail
77
- end
79
+ is_counter_even = -> { context[:counter].even? ? success : fail }
78
80
 
79
- add_to_task_builder
80
- end
81
+ # add these tasks to your builder
82
+ builder = BehaveFun.build_builder {
83
+ add_task_type Counter
84
+ add_lambda_task_type :is_counter_even, &is_counter_even
85
+ }
86
+ builder.build_tree { counter }
81
87
  ```
82
88
 
83
89
  To run a tree:
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_dependency 'zeitwerk', '~> 2.3.0'
29
29
  spec.add_dependency 'activesupport', '~> 6.0.0'
30
+ spec.add_dependency 'dry-types', '~> 1.4.0'
30
31
  end
@@ -9,29 +9,8 @@ loader.setup
9
9
  module BehaveFun
10
10
  module_function
11
11
 
12
- def build_tree(&block)
13
- builder = TaskBuilder.new(Tree.new)
14
- builder.instance_eval(&block)
15
- builder.control
16
- end
17
-
18
- def build_tree_from_hash(hash)
19
- build_tree do
20
- build_from_hash(hash[:root])
21
- end
22
- end
23
-
24
- def build_tree_from_json(json)
25
- hash = ActiveSupport::JSON.decode(json).deep_symbolize_keys
26
- build_tree_from_hash(hash)
27
- end
28
-
29
- def as_json(tree)
30
- tree.as_json
31
- end
32
-
33
- def to_json(tree)
34
- ActiveSupport::JSON.encode(as_json(tree))
12
+ def build_builder(&block)
13
+ BehaveFun::TaskBuilderFactory.new(&block)
35
14
  end
36
15
 
37
16
  class Error < StandardError; end
@@ -10,6 +10,11 @@ module BehaveFun
10
10
  @current_child.run
11
11
  end
12
12
 
13
+ def start
14
+ super
15
+ @current_child = nil
16
+ end
17
+
13
18
  def child_running
14
19
  running
15
20
  end
@@ -21,7 +26,5 @@ module BehaveFun
21
26
  def child_fail
22
27
  fail
23
28
  end
24
-
25
- add_to_task_builder
26
29
  end
27
30
  end
@@ -16,7 +16,5 @@ module BehaveFun
16
16
  def serializable_status_fields
17
17
  [:current_child_idx, :order]
18
18
  end
19
-
20
- add_to_task_builder
21
19
  end
22
20
  end
@@ -16,7 +16,5 @@ module BehaveFun
16
16
  def serializable_status_fields
17
17
  [:current_child_idx, :order]
18
18
  end
19
-
20
- add_to_task_builder
21
19
  end
22
20
  end
@@ -31,7 +31,5 @@ module BehaveFun
31
31
  def serializable_status_fields
32
32
  [:current_child_idx]
33
33
  end
34
-
35
- add_to_task_builder
36
34
  end
37
35
  end
@@ -31,7 +31,5 @@ module BehaveFun
31
31
  def serializable_status_fields
32
32
  [:current_child_idx]
33
33
  end
34
-
35
- add_to_task_builder
36
34
  end
37
35
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def child_success
4
4
  fail
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def child_fail
4
4
  success
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -7,7 +7,5 @@ module BehaveFun
7
7
  def child_success
8
8
  fail
9
9
  end
10
-
11
- add_to_task_builder
12
10
  end
13
11
  end
@@ -2,19 +2,16 @@ module BehaveFun
2
2
  class Decorators::Repeat < Decorator
3
3
  attr_accessor :counter
4
4
 
5
- def initialize(times: )
6
- super
7
- @times = times
8
- end
9
-
10
5
  def start
11
6
  super
12
7
  @counter = 0
13
8
  end
14
9
 
15
10
  def child_success
11
+ return @children[0].reset unless params[:times]
12
+
16
13
  @counter += 1
17
- if @counter < @times
14
+ if @counter < params[:times]
18
15
  @children[0].reset
19
16
  else
20
17
  success
@@ -29,6 +26,12 @@ module BehaveFun
29
26
  [:counter]
30
27
  end
31
28
 
32
- add_to_task_builder
29
+ def params=(params)
30
+ @params = ParamsSchema[params]
31
+ end
32
+
33
+ ParamsSchema = Types::Hash.schema(
34
+ times: Types::Coercible::Integer.optional.default(nil)
35
+ )
33
36
  end
34
37
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def child_fail
4
4
  success
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def child_success
4
4
  success
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def execute
4
4
  fail
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -3,7 +3,5 @@ module BehaveFun
3
3
  def execute
4
4
  success
5
5
  end
6
-
7
- add_to_task_builder
8
6
  end
9
7
  end
@@ -2,18 +2,13 @@ module BehaveFun
2
2
  class LeafTasks::Wait < Task
3
3
  attr_accessor :counter
4
4
 
5
- def initialize(duration: )
6
- super
7
- @duration = duration
8
- end
9
-
10
5
  def start
11
6
  super
12
7
  @counter = 0
13
8
  end
14
9
 
15
10
  def execute
16
- if @counter < @duration
11
+ if @counter < params[:duration]
17
12
  @counter += 1
18
13
  running
19
14
  else
@@ -25,6 +20,12 @@ module BehaveFun
25
20
  [:counter]
26
21
  end
27
22
 
28
- add_to_task_builder
23
+ def params=(params)
24
+ @params = ParamsSchema[params]
25
+ end
26
+
27
+ ParamsSchema = Types::Hash.schema(
28
+ duration: Types::Coercible::Integer
29
+ )
29
30
  end
30
31
  end
@@ -2,11 +2,11 @@ module BehaveFun
2
2
  class Task
3
3
  include TaskSerializer
4
4
 
5
- attr_accessor :control, :guard
6
- attr_reader :context, :children, :params, :status
5
+ attr_accessor :control, :guard, :params
6
+ attr_reader :context, :children, :status
7
7
 
8
- def initialize(**params)
9
- @params = params
8
+ def initialize(params = {})
9
+ self.params = params
10
10
  @children = []
11
11
  @status = :fresh
12
12
  end
@@ -15,10 +15,6 @@ module BehaveFun
15
15
  name.demodulize.underscore
16
16
  end
17
17
 
18
- def self.add_to_task_builder(name = task_name)
19
- BehaveFun::TaskBuilder.add_task_type(self, name: name)
20
- end
21
-
22
18
  def context=(context)
23
19
  @context = context
24
20
  children.each { _1.context = context }
@@ -119,5 +115,11 @@ module BehaveFun
119
115
  @status = :fresh
120
116
  children.each { |child| child.reset }
121
117
  end
118
+
119
+ def dup
120
+ cloned = self.class.new(params)
121
+ children.each { cloned.add_child(_1.dup) }
122
+ cloned
123
+ end
122
124
  end
123
125
  end
@@ -0,0 +1,132 @@
1
+ module BehaveFun
2
+ class TaskBuilderFactory
3
+ attr_reader :tasks
4
+
5
+ def initialize(&block)
6
+ @tasks = {}
7
+
8
+ add_task_type BehaveFun::LeafTasks::Success
9
+ add_task_type BehaveFun::LeafTasks::Failure
10
+ add_task_type BehaveFun::LeafTasks::Wait
11
+ add_task_type BehaveFun::Decorators::AlwaysSucceed
12
+ add_task_type BehaveFun::Decorators::AlwaysFail
13
+ add_task_type BehaveFun::Decorators::UntilSuccess
14
+ add_task_type BehaveFun::Decorators::UntilFail
15
+ add_task_type BehaveFun::Decorators::Invert
16
+ add_task_type BehaveFun::Decorators::Repeat
17
+ add_task_type BehaveFun::BranchTasks::Sequence
18
+ add_task_type BehaveFun::BranchTasks::Selector
19
+ add_task_type BehaveFun::BranchTasks::RandomSequence
20
+ add_task_type BehaveFun::BranchTasks::RandomSelector
21
+ add_task_type BehaveFun::BranchTasks::DynamicGuardSelector
22
+
23
+ instance_eval(&block) if block_given?
24
+ end
25
+
26
+ def add_task_type(type, name: type.task_name)
27
+ tasks[name.to_sym] = type
28
+ end
29
+
30
+ def add_lambda_task_type(task_name, &block)
31
+ type = Class.new(Task) do
32
+ def name
33
+ task_name
34
+ end
35
+
36
+ define_method(:execute, &block)
37
+ end
38
+ tasks[task_name.to_sym] = type
39
+ end
40
+
41
+ def build_task(&block)
42
+ task = build_tree(&block).root
43
+ task.control = nil
44
+ task
45
+ end
46
+
47
+ def build_tree(&block)
48
+ builder = Builder.new(self, Tree.new)
49
+ builder.instance_eval(&block)
50
+ builder.control
51
+ end
52
+
53
+ def build_task_from_hash(hash)
54
+ hash = hash.deep_symbolize_keys
55
+ tree = build_tree do
56
+ build_from_hash(hash)
57
+ end
58
+ tree.root
59
+ end
60
+
61
+ def build_tree_from_hash(hash)
62
+ hash = hash.deep_symbolize_keys
63
+ build_tree do
64
+ build_from_hash(hash[:root])
65
+ end
66
+ end
67
+
68
+ def build_tree_from_json(json)
69
+ hash = ActiveSupport::JSON.decode(json).deep_symbolize_keys
70
+ build_tree_from_hash(hash)
71
+ end
72
+
73
+ def as_json(tree)
74
+ tree.as_json
75
+ end
76
+
77
+ def to_json(tree)
78
+ ActiveSupport::JSON.encode(as_json(tree))
79
+ end
80
+
81
+ class Builder
82
+ attr_reader :factory, :control
83
+
84
+ def initialize(factory, control)
85
+ @factory = factory
86
+ @control = control
87
+ end
88
+
89
+ def add_task(type, params = {}, &block)
90
+ task = type.new(params)
91
+ @control.add_child(task)
92
+
93
+ if block
94
+ builder = Builder.new(factory, task)
95
+ builder.instance_eval(&block)
96
+ end
97
+ end
98
+
99
+ def guard_with(&block)
100
+ builder = Builder.new(factory, Tree.new)
101
+ builder.instance_eval(&block)
102
+ control.guard = builder.control.root
103
+ end
104
+
105
+ def include(task)
106
+ cloned_task = task.dup
107
+ @control.add_child(cloned_task)
108
+ end
109
+
110
+ def build_from_hash(task_hash)
111
+ type_name, params, guard_with, children =
112
+ task_hash.values_at(:type, :params, :guard_with, :children)
113
+ params ||= {}
114
+ children ||= []
115
+ type = factory.tasks[type_name.to_sym]
116
+ add_task type, **params do
117
+ guard_with { build_from_hash(guard_with) } if guard_with
118
+ children.each { build_from_hash(_1) }
119
+ end
120
+ end
121
+
122
+ def method_missing(name, *args, &block)
123
+ type = factory.tasks[name.to_sym]
124
+ if type
125
+ add_task(type, *args, &block)
126
+ else
127
+ super
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -1,6 +1,6 @@
1
1
  module BehaveFun
2
2
  class Tree < Task
3
- attr_accessor :root
3
+ attr_reader :root
4
4
 
5
5
  def root=(root)
6
6
  @root = root
@@ -56,5 +56,11 @@ module BehaveFun
56
56
  def restore_status(data)
57
57
  root.restore_status(data)
58
58
  end
59
+
60
+ def dup
61
+ cloned = self.class.new(params)
62
+ cloned.root = root.dup
63
+ cloned
64
+ end
59
65
  end
60
66
  end
@@ -0,0 +1,7 @@
1
+ require 'dry-types'
2
+
3
+ module BehaveFun
4
+ module Types
5
+ include Dry.Types()
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module BehaveFun
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.3'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: behave_fun
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ayaya zhao
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-17 00:00:00.000000000 Z
11
+ date: 2020-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 6.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-types
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.0
41
55
  description: A behavior tree library for ruby.
42
56
  email:
43
57
  - ayaya.zhao@gmail.com
@@ -74,9 +88,10 @@ files:
74
88
  - lib/behave_fun/leaf_tasks/success.rb
75
89
  - lib/behave_fun/leaf_tasks/wait.rb
76
90
  - lib/behave_fun/task.rb
77
- - lib/behave_fun/task_builder.rb
91
+ - lib/behave_fun/task_builder_factory.rb
78
92
  - lib/behave_fun/task_serializer.rb
79
93
  - lib/behave_fun/tree.rb
94
+ - lib/behave_fun/types.rb
80
95
  - lib/behave_fun/version.rb
81
96
  homepage: https://github.com/ayamomiji/behave_fun
82
97
  licenses:
@@ -1,48 +0,0 @@
1
- module BehaveFun
2
- class TaskBuilder
3
- attr_reader :control
4
-
5
- def initialize(control)
6
- @control = control
7
- end
8
-
9
- def add_task(type, **params, &block)
10
- task = type.new(**params)
11
- @control.add_child(task)
12
-
13
- if block
14
- builder = TaskBuilder.new(task)
15
- builder.instance_eval(&block)
16
- end
17
- end
18
-
19
- def guard_with(&block)
20
- builder = TaskBuilder.new(Tree.new)
21
- builder.instance_eval(&block)
22
- control.guard = builder.control.root
23
- end
24
-
25
- def build_from_hash(task_hash)
26
- type_name, params, guard_with, children =
27
- task_hash.values_at(:type, :params, :guard_with, :children)
28
- params ||= {}
29
- children ||= []
30
- type = self.class.tasks[type_name.to_sym]
31
- add_task type, **params do
32
- guard_with { build_from_hash(guard_with) } if guard_with
33
- children.each { build_from_hash(_1) }
34
- end
35
- end
36
-
37
- def self.tasks
38
- @tasks ||= {}
39
- end
40
-
41
- def self.add_task_type(type, name: type.task_name)
42
- tasks[name.to_sym] = type
43
- define_method name do |params = {}, &block|
44
- add_task(type, **params, &block)
45
- end
46
- end
47
- end
48
- end