behave_fun 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b98bf7be91dd32a369c4d44b7b24fa889a795eecce544e2f9ff1e061dcd9d1b9
4
+ data.tar.gz: 79a1c994205b9161b1ca79529740a465e189dbab64d5819617dd42541753698b
5
+ SHA512:
6
+ metadata.gz: 8d9b5140ad575eff28249a80b3ef03ed56b5d21fabce0a2c941122697832d5f323de817b4176de3a7d9896ac5dfbf450ef39742e5e5f6ac925c1fa2d3a76ffac
7
+ data.tar.gz: 948a0acfc738d0536eb3c8ea6414a421f4d9faa86539e0d7e02b9991b8594ea5477fa33dcb04799ef9dec8118c017117852b714ce2a4d367bf1d38529282d100
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.1
6
+ before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at ayaya.zhao@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in behave_fun.gemspec
4
+ gemspec
5
+
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec', '~> 3.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ behave_fun (0.1.0)
5
+ activesupport (~> 6.0.0)
6
+ zeitwerk (~> 2.3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (6.0.3)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 0.7, < 2)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ zeitwerk (~> 2.2, >= 2.2.2)
17
+ concurrent-ruby (1.1.6)
18
+ diff-lcs (1.3)
19
+ i18n (1.8.2)
20
+ concurrent-ruby (~> 1.0)
21
+ minitest (5.14.0)
22
+ rake (12.3.3)
23
+ rspec (3.9.0)
24
+ rspec-core (~> 3.9.0)
25
+ rspec-expectations (~> 3.9.0)
26
+ rspec-mocks (~> 3.9.0)
27
+ rspec-core (3.9.2)
28
+ rspec-support (~> 3.9.3)
29
+ rspec-expectations (3.9.2)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.9.0)
32
+ rspec-mocks (3.9.1)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.9.0)
35
+ rspec-support (3.9.3)
36
+ thread_safe (0.3.6)
37
+ tzinfo (1.2.7)
38
+ thread_safe (~> 0.1)
39
+ zeitwerk (2.3.0)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ behave_fun!
46
+ rake (~> 12.0)
47
+ rspec (~> 3.0)
48
+
49
+ BUNDLED WITH
50
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 ayaya zhao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # BehaveFun
2
+
3
+ BehaveFun is a behavior tree library for Ruby.
4
+
5
+ Main features:
6
+
7
+ * Build behavior tree from Ruby and JSON.
8
+ * Serialize tree status data and can be restored later.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'behave_fun'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install behave_fun
25
+
26
+ ## Usage
27
+
28
+ To build a behavior tree:
29
+
30
+ ``` ruby
31
+ # ruby dsl
32
+ tree = BehaveFun.build_tree { success }
33
+ # from hash
34
+ tree = BehaveFun.build_tree_from_hash(type: :success)
35
+ # from json
36
+ tree = BehaveFun.build_tree_from_json(json_string)
37
+ ```
38
+
39
+ To build a complex behavior tree:
40
+
41
+ ``` ruby
42
+ # write_spec, write_code, run_spec, git_push and release_gem are customized tasks
43
+ tree = BehaveFun.build_tree {
44
+ sequence {
45
+ until_success {
46
+ sequence {
47
+ write_spec
48
+ write_code
49
+ run_spec
50
+ }
51
+ }
52
+ git_push
53
+ release_gem
54
+ }
55
+ }
56
+ ```
57
+
58
+ 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.
59
+
60
+ ``` ruby
61
+ # a task that increase data by 1, always success
62
+ class Counter < BehaveFun::Task
63
+ def execute
64
+ tree.data += 1
65
+ success
66
+ end
67
+
68
+ add_to_task_builder
69
+ end
70
+
71
+ # a task that detect tree data is even or not
72
+ class IsCounterEven < BehaveFun::Task
73
+ def execute
74
+ tree.data.even? ? success : fail
75
+ end
76
+
77
+ add_to_task_builder
78
+ end
79
+ ```
80
+
81
+ To run a tree:
82
+
83
+ ``` ruby
84
+ tree.data = { ... } # provide your data (context) for the tree
85
+ tree.run
86
+ tree.status # :running, :succeeded or :failed
87
+ ```
88
+
89
+ To dump and restore status:
90
+
91
+ ``` ruby
92
+ status = tree.dump_status
93
+ tree.restore_status(status)
94
+ ```
95
+
96
+ For more detail, see spec examples.
97
+
98
+ ## Development
99
+
100
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
101
+
102
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
103
+
104
+ ## Contributing
105
+
106
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ayamomiji/behave_fun. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/ayamomiji/behave_fun/blob/master/CODE_OF_CONDUCT.md).
107
+
108
+
109
+ ## License
110
+
111
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
112
+
113
+ ## Code of Conduct
114
+
115
+ Everyone interacting in the BehaveFun project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ayamomiji/behave_fun/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ require_relative 'lib/behave_fun/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'behave_fun'
5
+ spec.version = BehaveFun::VERSION
6
+ spec.authors = ['ayaya zhao']
7
+ spec.email = ['ayaya.zhao@gmail.com']
8
+
9
+ spec.summary = %q{A behavior tree library for ruby.}
10
+ spec.description = %q{A behavior tree library for ruby.}
11
+ spec.homepage = 'https://github.com/ayamomiji/behave_fun'
12
+ spec.license = 'MIT'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
14
+
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+ spec.metadata['source_code_uri'] = spec.homepage
17
+ spec.metadata['changelog_uri'] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ spec.add_dependency 'zeitwerk', '~> 2.3.0'
29
+ spec.add_dependency 'activesupport', '~> 6.0.0'
30
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "behave_fun"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ module BehaveFun
2
+ class BranchTasks::DynamicGuardSelector < Task
3
+ def execute
4
+ child = @children.find { _1.guard_passed? }
5
+ if @current_child != child
6
+ @current_child.cancel if @current_child
7
+ @current_child = child
8
+ @current_child.reset
9
+ end
10
+ @current_child.run
11
+ end
12
+
13
+ def child_running
14
+ running
15
+ end
16
+
17
+ def child_success
18
+ success
19
+ end
20
+
21
+ def child_fail
22
+ fail
23
+ end
24
+
25
+ add_to_task_builder
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module BehaveFun
2
+ class BranchTasks::RandomSelector < BranchTasks::Selector
3
+ attr_accessor :order
4
+
5
+ def execute
6
+ @order = (0...@children.size).to_a.shuffle unless @order
7
+
8
+ @children[@order[@current_child_idx]].run
9
+ end
10
+
11
+ def start
12
+ super
13
+ @order = nil
14
+ end
15
+
16
+ def serializable_status_fields
17
+ [:current_child_idx, :order]
18
+ end
19
+
20
+ add_to_task_builder
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module BehaveFun
2
+ class BranchTasks::RandomSequence < BranchTasks::Sequence
3
+ attr_accessor :order
4
+
5
+ def execute
6
+ @order = (0...@children.size).to_a.shuffle unless @order
7
+
8
+ @children[@order[@current_child_idx]].run
9
+ end
10
+
11
+ def start
12
+ super
13
+ @order = nil
14
+ end
15
+
16
+ def serializable_status_fields
17
+ [:current_child_idx, :order]
18
+ end
19
+
20
+ add_to_task_builder
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module BehaveFun
2
+ class BranchTasks::Selector < Task
3
+ attr_accessor :current_child_idx
4
+
5
+ def execute
6
+ @children[@current_child_idx].run
7
+ end
8
+
9
+ def start
10
+ super
11
+ @current_child_idx = 0
12
+ end
13
+
14
+ def child_running
15
+ running
16
+ end
17
+
18
+ def child_success
19
+ success
20
+ end
21
+
22
+ def child_fail
23
+ @current_child_idx += 1
24
+ if @current_child_idx >= children.size
25
+ fail
26
+ else
27
+ run
28
+ end
29
+ end
30
+
31
+ def serializable_status_fields
32
+ [:current_child_idx]
33
+ end
34
+
35
+ add_to_task_builder
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ module BehaveFun
2
+ class BranchTasks::Sequence < Task
3
+ attr_accessor :current_child_idx
4
+
5
+ def execute
6
+ @children[@current_child_idx].run
7
+ end
8
+
9
+ def start
10
+ super
11
+ @current_child_idx = 0
12
+ end
13
+
14
+ def child_running
15
+ running
16
+ end
17
+
18
+ def child_success
19
+ @current_child_idx += 1
20
+ if @current_child_idx >= children.size
21
+ success
22
+ else
23
+ run
24
+ end
25
+ end
26
+
27
+ def child_fail
28
+ fail
29
+ end
30
+
31
+ def serializable_status_fields
32
+ [:current_child_idx]
33
+ end
34
+
35
+ add_to_task_builder
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ module BehaveFun
2
+ class Decorator < Task
3
+ def execute
4
+ children[0].run
5
+ end
6
+
7
+ def child_success
8
+ success
9
+ end
10
+
11
+ def child_fail
12
+ fail
13
+ end
14
+
15
+ def child_running
16
+ running
17
+ end
18
+
19
+ def add_child(child)
20
+ if children.size > 0
21
+ raise Error, 'A decorator task cannot have more than one child'
22
+ end
23
+ super
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class Decorators::AlwaysFail < Decorator
3
+ def child_success
4
+ fail
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class Decorators::AlwaysSucceed < Decorator
3
+ def child_fail
4
+ success
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module BehaveFun
2
+ class Decorators::Invert < Decorator
3
+ def child_fail
4
+ success
5
+ end
6
+
7
+ def child_success
8
+ fail
9
+ end
10
+
11
+ add_to_task_builder
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ module BehaveFun
2
+ class Decorators::Repeat < Decorator
3
+ attr_accessor :counter
4
+
5
+ def initialize(times: )
6
+ super
7
+ @times = times
8
+ end
9
+
10
+ def start
11
+ super
12
+ @counter = 0
13
+ end
14
+
15
+ def child_success
16
+ @counter += 1
17
+ if @counter < @times
18
+ @children[0].reset
19
+ else
20
+ success
21
+ end
22
+ end
23
+
24
+ def child_fail
25
+ child_success
26
+ end
27
+
28
+ def serializable_status_fields
29
+ [:counter]
30
+ end
31
+
32
+ add_to_task_builder
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class Decorators::UntilFail < Decorator
3
+ def child_fail
4
+ success
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class Decorators::UntilSuccess < Decorator
3
+ def child_success
4
+ success
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class LeafTasks::Failure < Task
3
+ def execute
4
+ fail
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module BehaveFun
2
+ class LeafTasks::Success < Task
3
+ def execute
4
+ success
5
+ end
6
+
7
+ add_to_task_builder
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ module BehaveFun
2
+ class LeafTasks::Wait < Task
3
+ attr_accessor :counter
4
+
5
+ def initialize(duration: )
6
+ super
7
+ @duration = duration
8
+ end
9
+
10
+ def start
11
+ super
12
+ @counter = 0
13
+ end
14
+
15
+ def execute
16
+ if @counter < @duration
17
+ @counter += 1
18
+ running
19
+ else
20
+ success
21
+ end
22
+ end
23
+
24
+ def serializable_status_fields
25
+ [:counter]
26
+ end
27
+
28
+ add_to_task_builder
29
+ end
30
+ end
@@ -0,0 +1,123 @@
1
+ module BehaveFun
2
+ class Task
3
+ include TaskSerializer
4
+
5
+ attr_accessor :guard
6
+ attr_reader :tree, :control, :children, :params, :status
7
+
8
+ def initialize(**params)
9
+ @params = params
10
+ @children = []
11
+ @status = :fresh
12
+ end
13
+
14
+ def self.task_name
15
+ name.demodulize.underscore
16
+ end
17
+
18
+ def self.add_to_task_builder(name = task_name)
19
+ BehaveFun::TaskBuilder.add_task_type(self, name: name)
20
+ end
21
+
22
+ def control=(control)
23
+ @control = control
24
+ @tree = control.tree
25
+ end
26
+
27
+ def running
28
+ @status = :running
29
+ control.child_running if control
30
+ end
31
+
32
+ def success
33
+ @status = :succeeded
34
+ control.child_success if control
35
+ end
36
+
37
+ def fail
38
+ @status = :failed
39
+ control.child_fail if control
40
+ end
41
+
42
+ def cancel
43
+ @status = :cancelled
44
+ children.each { |child| child.cancel }
45
+ end
46
+
47
+ def fresh?
48
+ @status == :fresh
49
+ end
50
+
51
+ def running?
52
+ @status == :running
53
+ end
54
+
55
+ def succeeded?
56
+ @status == :succeeded
57
+ end
58
+
59
+ def failed?
60
+ @status == :failed
61
+ end
62
+
63
+ def cancelled?
64
+ @status == :cancelled
65
+ end
66
+
67
+ def ended?
68
+ succeeded? || failed? || cancelled?
69
+ end
70
+
71
+ def guard_passed?
72
+ return true unless guard
73
+
74
+ guard.data = tree.data
75
+ guard.reset
76
+ guard.run
77
+
78
+ case guard.status
79
+ when :succeeded then true
80
+ when :failed then false
81
+ else
82
+ raise Error, 'Guard should finish in one step'
83
+ end
84
+ end
85
+
86
+ def start; end
87
+
88
+ def execute; end
89
+
90
+ def child_success; end
91
+
92
+ def child_fail; end
93
+
94
+ def child_running; end
95
+
96
+ def add_child(task)
97
+ @children << task
98
+ task.control = self
99
+ end
100
+
101
+ def run
102
+ raise Error, 'Cannot run ended task' if ended?
103
+ if fresh?
104
+ if guard_passed?
105
+ start
106
+ running
107
+ execute
108
+ else
109
+ fail
110
+ end
111
+ else
112
+ running
113
+ execute
114
+ end
115
+ end
116
+
117
+ def reset
118
+ cancel
119
+ @status = :fresh
120
+ children.each { |child| child.reset }
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,42 @@
1
+ module BehaveFun
2
+ module TaskSerializer
3
+ def name
4
+ self.class.task_name
5
+ end
6
+
7
+ def as_json
8
+ data = { type: name }
9
+ data.merge!(params: params) if params.any?
10
+ data.merge!(guard_with: guard.as_json) if guard
11
+ data.merge!(children: children.map { _1.as_json }) if children.any?
12
+ data
13
+ end
14
+
15
+ def serializable_status_fields
16
+ []
17
+ end
18
+
19
+ def dump_status
20
+ data = serializable_status_fields.inject({}) do |data, method_name|
21
+ data.merge(method_name => send(method_name))
22
+ end
23
+ data.merge!(status: status)
24
+ data.merge!(children: children.map(&:dump_status)) if children.any?
25
+ data
26
+ end
27
+
28
+ def restore_status(data)
29
+ @status = data[:status].to_sym
30
+
31
+ serializable_status_fields.each do |method_name|
32
+ send("#{method_name}=", data[method_name])
33
+ end
34
+
35
+ if data[:children]
36
+ children.zip(data[:children]).each do |child, child_data|
37
+ child.restore_status(child_data)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ module BehaveFun
2
+ class Tree < Task
3
+ attr_accessor :root, :data
4
+
5
+ def root=(root)
6
+ @root = root
7
+ @root.control = self
8
+ end
9
+
10
+ def tree
11
+ self
12
+ end
13
+
14
+ def execute
15
+ root.run
16
+ end
17
+
18
+ def child_running
19
+ running
20
+ end
21
+
22
+ def child_success
23
+ success
24
+ end
25
+
26
+ def child_fail
27
+ fail
28
+ end
29
+
30
+ # tree does not have children, it only contains a root
31
+ def add_child(child)
32
+ self.root = child
33
+ end
34
+
35
+ def reset
36
+ super
37
+ root.reset
38
+ end
39
+
40
+ def as_json
41
+ {
42
+ version: 1,
43
+ root: root.as_json
44
+ }
45
+ end
46
+
47
+ def dump_status
48
+ root.dump_status
49
+ end
50
+
51
+ def restore_status(data)
52
+ root.restore_status(data)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module BehaveFun
2
+ VERSION = '0.1.0'
3
+ end
data/lib/behave_fun.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'behave_fun/version'
2
+
3
+ require 'zeitwerk'
4
+ require 'active_support/all'
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.setup
8
+
9
+ module BehaveFun
10
+ module_function
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))
35
+ end
36
+
37
+ class Error < StandardError; end
38
+ end
39
+
40
+ loader.eager_load
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: behave_fun
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ayaya zhao
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: zeitwerk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 6.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 6.0.0
41
+ description: A behavior tree library for ruby.
42
+ email:
43
+ - ayaya.zhao@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rspec"
50
+ - ".travis.yml"
51
+ - CODE_OF_CONDUCT.md
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - behave_fun.gemspec
58
+ - bin/console
59
+ - bin/setup
60
+ - lib/behave_fun.rb
61
+ - lib/behave_fun/branch_tasks/dynamic_guard_selector.rb
62
+ - lib/behave_fun/branch_tasks/random_selector.rb
63
+ - lib/behave_fun/branch_tasks/random_sequence.rb
64
+ - lib/behave_fun/branch_tasks/selector.rb
65
+ - lib/behave_fun/branch_tasks/sequence.rb
66
+ - lib/behave_fun/decorator.rb
67
+ - lib/behave_fun/decorators/always_fail.rb
68
+ - lib/behave_fun/decorators/always_succeed.rb
69
+ - lib/behave_fun/decorators/invert.rb
70
+ - lib/behave_fun/decorators/repeat.rb
71
+ - lib/behave_fun/decorators/until_fail.rb
72
+ - lib/behave_fun/decorators/until_success.rb
73
+ - lib/behave_fun/leaf_tasks/failure.rb
74
+ - lib/behave_fun/leaf_tasks/success.rb
75
+ - lib/behave_fun/leaf_tasks/wait.rb
76
+ - lib/behave_fun/task.rb
77
+ - lib/behave_fun/task_builder.rb
78
+ - lib/behave_fun/task_serializer.rb
79
+ - lib/behave_fun/tree.rb
80
+ - lib/behave_fun/version.rb
81
+ homepage: https://github.com/ayamomiji/behave_fun
82
+ licenses:
83
+ - MIT
84
+ metadata:
85
+ homepage_uri: https://github.com/ayamomiji/behave_fun
86
+ source_code_uri: https://github.com/ayamomiji/behave_fun
87
+ changelog_uri: https://github.com/ayamomiji/behave_fun
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 2.3.0
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubygems_version: 3.1.2
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: A behavior tree library for ruby.
107
+ test_files: []