mouse_organ 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 641094f0c65c8fbee427c96d520549086475873b
4
+ data.tar.gz: b22183796cb160f016e6d215c5a0ea98d2cc846b
5
+ SHA512:
6
+ metadata.gz: 49314c17a6e28eea2e114bfeb68dae62185180bbf68a0bb79d04e960eb848e4e537abd02cfe00f0492008658271f8e12ae4a7f8a4f7249576ffaa9c1c6532079
7
+ data.tar.gz: b4f2da325915322c469846f81a95375b9395b874efa28bc6f25dc5515a5866ef68de2fbb52fa6f05ba30a4ce453cc4e2aec1550f6ff0499dc5c7de93e35e77c0
@@ -0,0 +1,15 @@
1
+ syntax: regexp
2
+
3
+ ^\.bundle/
4
+ ^Gemfile.lock
5
+ ^doc/
6
+ ^pkg/
7
+ ^spec/reports/
8
+ ^tmp/
9
+
10
+ syntax: glob
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ -I .
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+
7
+ gem "rspec", "~> 3.8"
8
+ gem "pry"
9
+ gem "rdoc"
10
+
11
+ end
12
+
13
+
14
+
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Andrew Jones
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,70 @@
1
+ Mouse Organ
2
+ ===========
3
+
4
+ Ladies and gentlemen, the Marvelous -- Mechanical -- Mouse Organ!
5
+
6
+ This is a _very_ small mixin that turns a class into a basic state machine.
7
+
8
+
9
+ Installation
10
+ ------------
11
+
12
+ Just download lib/mouse_organ.rb into your code. Or you could just use it as a pattern of sorts,
13
+ and roll your own in the same vein.
14
+
15
+ I mean, sure, you can also `gem install mouse_organ`. But honestly, it might be better to have the
16
+ class where you can see it, for documentation purposes? Your call.
17
+
18
+
19
+
20
+ Example
21
+ -------
22
+
23
+ ```{.ruby}
24
+ class Foo
25
+ include MouseOrgan
26
+
27
+ def initialize
28
+ machine_start(:one)
29
+ end
30
+
31
+ def state_one
32
+ transition_to :two
33
+ sleep 1
34
+ end
35
+
36
+ def state_two
37
+ transition_to :three
38
+ sleep 1
39
+ end
40
+
41
+ def state_three
42
+ throw :machine_stop
43
+ end
44
+
45
+ def transition_to(state)
46
+ puts state
47
+ super
48
+ end
49
+
50
+ end
51
+ ```
52
+
53
+
54
+ What You Get
55
+ ------------
56
+
57
+ Each of your methods that start `state_` define a state of the state machine. To start the machine,
58
+ pass `#machine_start` the initial state name (e.g., `:two` for the state defined by `#state_two`).
59
+
60
+ Inside a state method, you can change to a new state using `transition_to(:statename)`. You can
61
+ stop the machine using `throw :machine_stop`, or you can override `#machine_stop?` to return true
62
+ if the machine should stop.
63
+
64
+ Passing an invalid state to `#machine_start` or `#transition_to` raises ArgumentError.
65
+
66
+ The attribute @state holds the current state.
67
+
68
+ It might be useful to override `#transition_to` as I have above -- for example, in order to log
69
+ every change of state.
70
+
@@ -0,0 +1,70 @@
1
+ ##
2
+ # A tiny mixin to turn a class into a state machine.
3
+ # Example:
4
+ #
5
+ # class Foo
6
+ # include MouseOrgan
7
+ #
8
+ # def initialize
9
+ # machine_start(:one)
10
+ # end
11
+ #
12
+ # def state_one
13
+ # transition_to :two
14
+ # sleep 1
15
+ # end
16
+ #
17
+ # def state_two
18
+ # transition_to :three
19
+ # sleep 1
20
+ # end
21
+ #
22
+ # def state_three
23
+ # throw :machine_stop
24
+ # end
25
+ #
26
+ # def transition_to(state)
27
+ # puts state
28
+ # super
29
+ # end
30
+ #
31
+ # end
32
+ #
33
+ module MouseOrgan
34
+ VERSION = "0.1.0"
35
+
36
+ def machine_start(initial)
37
+ transition_to initial
38
+
39
+ catch :machine_stop do
40
+ loop do
41
+ send state_method(@state)
42
+ throw :machine_stop if machine_stop?
43
+ end
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ def transition_to(state)
50
+ if self.respond_to? state_method(state)
51
+ @state = state
52
+ else
53
+ fail ArgumentError, "Unknown state '#{state}'"
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ def machine_stop?
60
+ false
61
+ end
62
+
63
+ private
64
+
65
+ def state_method(state)
66
+ "state_#{state}".to_sym
67
+ end
68
+
69
+ end # of MouseOrgan
70
+
@@ -0,0 +1,28 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'mouse_organ'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "mouse_organ"
7
+ spec.version = MouseOrgan::VERSION
8
+ spec.authors = ["Andy Jones"]
9
+ spec.email = ["andy.jones@twosticksconsulting.co.uk"]
10
+ spec.summary = %q|Tiny state machine|
11
+ spec.description = <<-DESC.gsub(/^\s+/, "")
12
+ A tiny mixin to turn a class into a state machine.
13
+ DESC
14
+
15
+ spec.homepage = "https://bitbucket.org/andy-twosticks/mouse_organ"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `hg status -macn0`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.extra_rdoc_files = spec.files.grep(%r{^md/})
24
+
25
+ #spec.add_runtime_dependency "devnull", '~>0.1'
26
+ #spec.add_runtime_dependency "octothorpe", '~>0.4'
27
+
28
+ end
@@ -0,0 +1,124 @@
1
+ require "mouse_organ"
2
+
3
+
4
+ RSpec.describe "MouseOrgan" do
5
+
6
+ let(:class_organ1) do
7
+ Class.new do
8
+ include MouseOrgan
9
+ end
10
+ end
11
+
12
+ let(:class_organ2) do
13
+ Class.new do
14
+ include MouseOrgan
15
+ attr_reader :state
16
+
17
+ def go; machine_start(:one); end
18
+
19
+ def state_one; throw :machine_stop; end
20
+ end
21
+ end
22
+
23
+ let(:class_organ3) do
24
+ Class.new do
25
+ include MouseOrgan
26
+
27
+ def go; machine_start(:one); end
28
+
29
+ def state_one; transition_to :two; end
30
+ def state_two; transition_to :three; end
31
+ def state_three; throw :machine_stop; end
32
+ end
33
+ end
34
+
35
+ let(:class_organ4) do
36
+ Class.new do
37
+ include MouseOrgan
38
+
39
+ def go; machine_start(:one); end
40
+
41
+ def state_one; transition_to :two; end
42
+ def state_two; transition_to :three; end
43
+ def state_three; transition_to :one; end
44
+
45
+ def machine_stop?; @state == :three; end
46
+ end
47
+ end
48
+
49
+ let(:class_organ5) do
50
+ Class.new do
51
+ include MouseOrgan
52
+ attr_reader :state_history
53
+
54
+ def initialize; @state_history = []; end
55
+
56
+ def go; machine_start(:one); end
57
+
58
+ def state_one; transition_to :two; end
59
+ def state_two; transition_to :three; end
60
+ def state_three; throw :machine_stop; end
61
+
62
+ def transition_to(state)
63
+ @state_history << state
64
+ super
65
+ end
66
+ end
67
+ end
68
+
69
+ let(:organ1) { class_organ1.new }
70
+ let(:organ2) { class_organ2.new }
71
+ let(:organ3) { class_organ3.new }
72
+ let(:organ4) { class_organ4.new }
73
+ let(:organ5) { class_organ5.new }
74
+
75
+
76
+ describe "#machine_start" do
77
+
78
+ it "raises ArgumentError if given an invalid state" do
79
+ expect{ organ1.machine_start(:wrong) }.to raise_error ArgumentError
80
+ end
81
+
82
+ it "transitions to the initial state" do
83
+ expect( organ2 ).to receive(:transition_to).with(:one).and_call_original
84
+ organ2.go
85
+ end
86
+
87
+ it "transits through the given states and stops when :machine_stop is thrown" do
88
+ expect( organ3 ).to receive(:transition_to).with(:one).and_call_original.ordered
89
+ expect( organ3 ).to receive(:transition_to).with(:two).and_call_original.ordered
90
+ expect( organ3 ).to receive(:transition_to).with(:three).and_call_original.ordered
91
+ organ3.go
92
+ end
93
+
94
+ it "transits through the given states and stops when #machine_stop? is true" do
95
+ expect( organ4 ).to receive(:transition_to).with(:one).and_call_original.ordered
96
+ expect( organ4 ).to receive(:transition_to).with(:two).and_call_original.ordered
97
+ expect( organ4 ).to receive(:transition_to).with(:three).and_call_original.ordered
98
+ organ4.go
99
+ end
100
+
101
+ end # of #machine_start
102
+
103
+
104
+ describe "#transition_to" do
105
+
106
+ it "raises ArgumentError if given an invalid state" do
107
+ expect{ organ2.transition_to(:two) }.to raise_error ArgumentError
108
+ end
109
+
110
+ it "sets @state to the new state" do
111
+ organ2.transition_to(:one)
112
+ expect( organ2.state ).to eq :one
113
+ end
114
+
115
+ it "will allow overriding" do
116
+ organ5.go
117
+ expect( organ5.state_history ).to eq(%i|one two three|)
118
+ end
119
+
120
+ end # of #transition_to
121
+
122
+
123
+ end
124
+
@@ -0,0 +1,25 @@
1
+ require 'pry' #always useful when debugging
2
+
3
+ RSpec.configure do |config|
4
+
5
+ config.expect_with :rspec do |expectations|
6
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
7
+ end
8
+
9
+ config.mock_with :rspec do |mocks|
10
+ mocks.verify_partial_doubles = true
11
+ end
12
+
13
+ config.shared_context_metadata_behavior = :apply_to_host_groups
14
+ config.filter_run_when_matching :focus
15
+ config.disable_monkey_patching!
16
+ config.warnings = true
17
+ config.order = :random
18
+
19
+ if config.files_to_run.one?
20
+ config.default_formatter = 'doc'
21
+ end
22
+
23
+ Kernel.srand config.seed
24
+ end
25
+
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mouse_organ
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andy Jones
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'A tiny mixin to turn a class into a state machine.
14
+
15
+ '
16
+ email:
17
+ - andy.jones@twosticksconsulting.co.uk
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".hgignore"
23
+ - ".rspec"
24
+ - Gemfile
25
+ - LICENSE.md
26
+ - README.md
27
+ - lib/mouse_organ.rb
28
+ - mouse_organ.gemspec
29
+ - spec/mouse_organ_spec.rb
30
+ - spec/spec_helper.rb
31
+ homepage: https://bitbucket.org/andy-twosticks/mouse_organ
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.5.2
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Tiny state machine
55
+ test_files:
56
+ - spec/mouse_organ_spec.rb
57
+ - spec/spec_helper.rb