eventful.rb 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b9a8e5622060297424496b78fc52312d8cb0acf7d62d67571a8990c75cb8580
4
- data.tar.gz: 85aaf96637073d8e8aff7375e4977e74bd20ca9834535b7635ed936d4ae1db2a
3
+ metadata.gz: 6b1e4814ed3f3c820ac5a81d56e425b9d3f03eee9b8c819308c1bcd958ab40f8
4
+ data.tar.gz: 4de5ad6c6cf1c57147f5affa9bdf042c30eb68dadd0ef280326348de68f9f72b
5
5
  SHA512:
6
- metadata.gz: 531ffe23a894e0337cf48d29c2f96415986771cf90523f0d3d3d2e8167868443b2538fbab98e30790baeb5dc445c8ad400b3d36a0afcd18817001fe23d492fd5
7
- data.tar.gz: 6edb8b51096c9e2addc3ddbd8d6aab373d9fa4f0b4df97a28fd5d35c3878930b2351ba1f886887553717b286ea2f49f050154d4fe9141a454c7bd82adec54d41
6
+ metadata.gz: 2e80ddadfb01294f5e9bab2823d30bc43493ff76e040de7148950b5d22ea747b7345d8a9d453d441fb40e385f506af0f027a444bdd16f1f4a86e59890b24a104
7
+ data.tar.gz: a09be6861708162aa5638ad7b971aaa67bb60ae6f52cc0d816966950b1587322e87a9a0094ecb2faaa1ea2ca43f9b7ba4dd85d05cbe34d23eb135b9583c065d3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'stateful.rb'
4
+
5
+ group :development, :test do
6
+ gem 'minitest'
7
+ gem 'minitest-spec-context'
8
+ end
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # eventful.rb
2
+
3
+ Automatically change state with Stateful state machines.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'eventful.rb'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install eventful.rb
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ class Machine
29
+
30
+ include Eventful
31
+
32
+ initial_state :initial_state do
33
+ on :an_event => :next_state
34
+ on :another_event => :final_state
35
+ end
36
+
37
+ state :next_state do
38
+ on :yet_another_event => :final_state
39
+ end
40
+
41
+ final_state :final_state
42
+
43
+ # An event that produces a boolean result and which corresponds with a state trigger, which for argument sake is true.
44
+ def an_event?
45
+ true
46
+ end
47
+
48
+ # Another event that produces a boolean result and which corresponds with a state trigger, which for argument sake is false
49
+ def another_event?
50
+ false
51
+ end
52
+
53
+ # Yet another event that produces a boolean result and which corresponds with a state trigger, which for argument sake is true.
54
+ def yet_another_event?
55
+ true
56
+ end
57
+ end
58
+
59
+ machine = Machine.new
60
+ machine.current_state.name
61
+ # => :initial_state
62
+
63
+ Machine.run # Causes the state to transition from the initial_state through next_state and then to final_state.
64
+
65
+ machine.current_state.name
66
+ # => :final_state
67
+ ```
68
+
69
+ ## Contributing
70
+
71
+ 1. Fork it (https://github.com/thoran/eventful.rb/fork)
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 4. Push to the branch (`git push origin my-new-feature`)
75
+ 5. Create a new pull request
76
+
77
+ ## License
78
+
79
+ The gem is available as open source under the terms of the [Ruby License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,28 @@
1
+ require_relative './lib/Eventful/VERSION'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'eventful.rb'
5
+
6
+ spec.version = Eventful::VERSION
7
+ spec.date = '2025-07-28'
8
+
9
+ spec.summary = "Automatically change state with Stateful state machines."
10
+ spec.description = "By defining predicate methods which except for the addition of '?' matches a state machine event and then configuring an in memory or cron-based event loop, the state machine will be able to change state automatically."
11
+
12
+ spec.author = 'thoran'
13
+ spec.email = 'code@thoran.com'
14
+ spec.homepage = 'http://github.com/thoran/eventful.rb'
15
+ spec.license = 'Ruby'
16
+
17
+ spec.required_ruby_version = '>= 1.8.6'
18
+
19
+ spec.add_dependency('stateful.rb')
20
+ spec.files = [
21
+ 'eventful.rb.gemspec',
22
+ 'Gemfile',
23
+ Dir['lib/**/*.rb'],
24
+ 'README.md',
25
+ Dir['test/**/*.rb']
26
+ ].flatten
27
+ spec.require_paths = ['lib']
28
+ end
@@ -0,0 +1,6 @@
1
+ # Eventful/VERSION.rb
2
+ # Eventful::VERSION
3
+
4
+ module Eventful
5
+ VERSION = '0.8.0'
6
+ end
File without changes
@@ -0,0 +1,176 @@
1
+ # test/ActiveRecord.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', 'lib'))
10
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
11
+
12
+ require 'active_record'
13
+ require 'pg'
14
+ require 'Eventful'
15
+
16
+ class CreateTableActiveRecordMachines < ActiveRecord::Migration
17
+
18
+ def change
19
+ create_table :active_record_machines do |t|
20
+ t.string :current_state
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ class ActiveRecordMachine < ActiveRecord::Base
27
+
28
+ include Eventful
29
+
30
+ initial_state :initial_state do
31
+ on :an_event => :next_state
32
+ on :another_event => :final_state
33
+ end
34
+
35
+ state :next_state do
36
+ on :yet_another_event => :final_state
37
+ end
38
+
39
+ final_state :final_state
40
+
41
+ end
42
+
43
+ ActiveRecord::Base.establish_connection(
44
+ adapter: 'postgresql',
45
+ host: 'localhost',
46
+ database: 'test'
47
+ )
48
+ unless ActiveRecord::Base.connection.tables.include?('active_record_machines')
49
+ CreateTableActiveRecordMachines.new.change
50
+ end
51
+ if ActiveRecord::Base.connection.tables.include?('active_record_machines')
52
+ ActiveRecordMachine.delete_all
53
+ end
54
+
55
+ describe Eventful do
56
+
57
+ let(:machine){ActiveRecordMachine.create}
58
+
59
+ before do
60
+ ActiveRecordMachine.delete_all
61
+ end
62
+
63
+ it "must have successfully extended the receiver class with Stateful methods" do
64
+ machine.class.methods.include?(:stateful_states).must_equal true
65
+ end
66
+
67
+ it "must have successfully extended the receiver class with Eventful methods" do
68
+ machine.class.methods.include?(:active).must_equal true
69
+ end
70
+
71
+ context "only an_event? is true" do
72
+
73
+ before do
74
+ class ActiveRecordMachine
75
+ def an_event?
76
+ true
77
+ end
78
+
79
+ def another_event?
80
+ false
81
+ end
82
+
83
+ def yet_another_event?
84
+ false
85
+ end
86
+ end
87
+ end
88
+
89
+ it "must know which instances are active (ie. not in a final state)" do
90
+ machine.current_state
91
+ ActiveRecordMachine.active.size.must_equal 1
92
+ end
93
+
94
+ it "must know whether an event has occurred" do
95
+ machine.an_event?.must_equal true
96
+ end
97
+
98
+ it "must know whether an event has not occurred" do
99
+ machine.another_event?.must_equal false
100
+ machine.yet_another_event?.must_equal false
101
+ end
102
+
103
+ it "must automatically trigger state changes" do
104
+ machine.current_state
105
+ ActiveRecordMachine.run
106
+ machine.reload.current_state.name.must_equal :next_state
107
+ end
108
+ end
109
+
110
+ context "an_event? and yet_another_event? are true" do
111
+
112
+ before do
113
+ class ActiveRecordMachine
114
+ def an_event?
115
+ true
116
+ end
117
+
118
+ def another_event?
119
+ false
120
+ end
121
+
122
+ def yet_another_event?
123
+ true
124
+ end
125
+ end
126
+ end
127
+
128
+ it "must know which instances are active (ie. not in a final state)" do
129
+ machine.current_state
130
+ ActiveRecordMachine.active.size.must_equal 1
131
+ end
132
+
133
+ it "must know whether an event has occurred" do
134
+ machine.an_event?.must_equal true
135
+ machine.yet_another_event?.must_equal true
136
+ end
137
+
138
+ it "must know whether an event has not occurred" do
139
+ machine.another_event?.must_equal false
140
+ end
141
+
142
+ it "must automatically trigger state changes" do
143
+ machine.current_state = :next_state
144
+ ActiveRecordMachine.run
145
+ machine.reload.current_state.name.must_equal :final_state
146
+ end
147
+ end
148
+
149
+ context "frequency_in_seconds and runtime_in_seconds given" do
150
+
151
+ before do
152
+ class ActiveRecordMachine
153
+ def an_event?
154
+ true
155
+ end
156
+
157
+ def another_event?
158
+ true
159
+ end
160
+
161
+ def yet_another_event?
162
+ true
163
+ end
164
+ end
165
+ end
166
+
167
+ it "must run for no longer than the specified runtime_in_seconds" do
168
+ start_time = Time.now
169
+ ActiveRecordMachine.run(2, 10) # Run every 2 seconds for not more than 10 seconds.
170
+ finish_time = Time.now
171
+ run_time = finish_time - start_time
172
+ run_time.must_be_close_to 10, 0.1
173
+ end
174
+ end
175
+
176
+ end
@@ -0,0 +1,177 @@
1
+ # test/ActiveRecordWhenNoFinalState.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', 'lib'))
10
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
11
+
12
+ require 'active_record'
13
+ require 'pg'
14
+ require 'Eventful'
15
+
16
+ class CreateTableActiveRecordMachines2 < ActiveRecord::Migration
17
+
18
+ def change
19
+ create_table :active_record_machine2s do |t|
20
+ t.string :current_state
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ class ActiveRecordMachine2 < ActiveRecord::Base
27
+
28
+ include Eventful
29
+
30
+ initial_state :initial_state do
31
+ on :an_event => :another_state
32
+ end
33
+
34
+ state :another_state do
35
+ on :another_event => :yet_another_state
36
+ end
37
+
38
+ state :yet_another_state do
39
+ on :yet_another_event => :another_state
40
+ end
41
+
42
+ end
43
+
44
+ ActiveRecord::Base.establish_connection(
45
+ adapter: 'postgresql',
46
+ host: 'localhost',
47
+ database: 'test'
48
+ )
49
+ unless ActiveRecord::Base.connection.tables.include?('active_record_machine2s')
50
+ CreateTableActiveRecordMachines2.new.change
51
+ end
52
+ if ActiveRecord::Base.connection.tables.include?('active_record_machine2s')
53
+ ActiveRecordMachine2.delete_all
54
+ end
55
+
56
+ describe Eventful do
57
+
58
+ let(:machine2){ActiveRecordMachine2.create}
59
+
60
+ before do
61
+ ActiveRecordMachine2.delete_all
62
+ end
63
+
64
+ it "must have successfully extended the receiver class with Stateful methods" do
65
+ machine2.class.methods.include?(:stateful_states).must_equal true
66
+ end
67
+
68
+ it "must have successfully extended the receiver class with Eventful methods" do
69
+ machine2.class.methods.include?(:active).must_equal true
70
+ end
71
+
72
+ context "only an_event? is true" do
73
+
74
+ before do
75
+ class ActiveRecordMachine2
76
+ def an_event?
77
+ true
78
+ end
79
+
80
+ def another_event?
81
+ false
82
+ end
83
+
84
+ def yet_another_event?
85
+ false
86
+ end
87
+ end
88
+ end
89
+
90
+ it "must know which instances are active (ie. not in a final state)" do
91
+ machine2.current_state
92
+ ActiveRecordMachine2.active.size.must_equal 1
93
+ end
94
+
95
+ it "must know whether an event has occurred" do
96
+ machine2.an_event?.must_equal true
97
+ end
98
+
99
+ it "must know whether an event has not occurred" do
100
+ machine2.another_event?.must_equal false
101
+ machine2.yet_another_event?.must_equal false
102
+ end
103
+
104
+ it "must automatically trigger state changes" do
105
+ machine2.current_state
106
+ ActiveRecordMachine2.run
107
+ machine2.reload.current_state.name.must_equal :another_state
108
+ end
109
+ end
110
+
111
+ context "an_event? and another_event? are true" do
112
+
113
+ before do
114
+ class ActiveRecordMachine2
115
+ def an_event?
116
+ true
117
+ end
118
+
119
+ def another_event?
120
+ true
121
+ end
122
+
123
+ def yet_another_event?
124
+ false
125
+ end
126
+ end
127
+ end
128
+
129
+ it "must know which instances are active (ie. not in a final state)" do
130
+ machine2.current_state
131
+ ActiveRecordMachine2.active.size.must_equal 1
132
+ end
133
+
134
+ it "must know whether an event has occurred" do
135
+ machine2.an_event?.must_equal true
136
+ machine2.another_event?.must_equal true
137
+ end
138
+
139
+ it "must know whether an event has not occurred" do
140
+ machine2.yet_another_event?.must_equal false
141
+ end
142
+
143
+ it "must automatically trigger state changes" do
144
+ machine2.current_state
145
+ 2.times{ActiveRecordMachine2.run}
146
+ machine2.reload.current_state.name.must_equal :yet_another_state
147
+ end
148
+ end
149
+
150
+ context "frequency_in_seconds and runtime_in_seconds given" do
151
+
152
+ before do
153
+ class ActiveRecordMachine2
154
+ def an_event?
155
+ true
156
+ end
157
+
158
+ def another_event?
159
+ true
160
+ end
161
+
162
+ def yet_another_event?
163
+ true
164
+ end
165
+ end
166
+ end
167
+
168
+ it "must run for no longer than the specified runtime_in_seconds" do
169
+ start_time = Time.now
170
+ ActiveRecordMachine2.run(2, 10) # Run every 2 seconds for not more than 10 seconds.
171
+ finish_time = Time.now
172
+ run_time = finish_time - start_time
173
+ run_time.must_be_close_to 10, 0.1
174
+ end
175
+ end
176
+
177
+ end
data/test/Eventful.rb ADDED
@@ -0,0 +1,7 @@
1
+ # test/Eventful.rb
2
+
3
+ # The two ActiveRecord specs don't like being run together, so I randomly pick one of them to run...
4
+ active_record_test_file = ['ActiveRecord', 'ActiveRecordWhenNoFinalState'][rand(2)]
5
+ require_relative active_record_test_file
6
+
7
+ require_relative 'Poro'
data/test/Poro.rb ADDED
@@ -0,0 +1,145 @@
1
+ # test/Poro.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', 'lib'))
10
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
11
+
12
+ require 'Eventful'
13
+
14
+ class Machine
15
+
16
+ include Eventful
17
+
18
+ initial_state :initial_state do
19
+ on :an_event => :next_state
20
+ on :another_event => :final_state
21
+ end
22
+
23
+ state :next_state do
24
+ on :yet_another_event => :final_state
25
+ end
26
+
27
+ final_state :final_state
28
+
29
+ end
30
+
31
+ describe Eventful do
32
+
33
+ let(:machine){Machine.active.first || Machine.new}
34
+
35
+ it "must have successfully extended the receiver class with Stateful methods" do
36
+ machine.class.methods.include?(:stateful_states).must_equal true
37
+ end
38
+
39
+ it "must have successfully extended the receiver class with Eventful methods" do
40
+ machine.class.methods.include?(:active).must_equal true
41
+ end
42
+
43
+ context "only an_event? is true" do
44
+ before do
45
+ class Machine
46
+ def an_event?
47
+ true
48
+ end
49
+
50
+ def another_event?
51
+ false
52
+ end
53
+
54
+ def yet_another_event?
55
+ false
56
+ end
57
+ end
58
+ end
59
+
60
+ it "must know which instances are active (ie. not in a final state)" do
61
+ machine
62
+ Machine.active.size.must_equal 1
63
+ end
64
+
65
+ it "must know whether an event has occurred" do
66
+ machine.an_event?.must_equal true
67
+ end
68
+
69
+ it "must know whether an event has not occurred" do
70
+ machine.another_event?.must_equal false
71
+ machine.yet_another_event?.must_equal false
72
+ end
73
+
74
+ it "must automatically trigger state changes" do
75
+ machine
76
+ Machine.run
77
+ machine.current_state.name.must_equal :next_state
78
+ end
79
+ end
80
+
81
+ context "an_event? and yet_another_event? are true" do
82
+ before do
83
+ class Machine
84
+ def an_event?
85
+ true
86
+ end
87
+
88
+ def another_event?
89
+ false
90
+ end
91
+
92
+ def yet_another_event?
93
+ true
94
+ end
95
+ end
96
+ end
97
+
98
+ it "must know which instances are active (ie. not in a final state)" do
99
+ machine
100
+ Machine.active.size.must_equal 1
101
+ end
102
+
103
+ it "must know whether an event has occurred" do
104
+ machine.an_event?.must_equal true
105
+ machine.yet_another_event?.must_equal true
106
+ end
107
+
108
+ it "must know whether an event has not occurred" do
109
+ machine.another_event?.must_equal false
110
+ end
111
+
112
+ it "must automatically trigger state changes" do
113
+ machine.current_state = :next_state
114
+ Machine.run
115
+ machine.current_state.name.must_equal :final_state
116
+ end
117
+ end
118
+
119
+ context "frequency_in_seconds and runtime_in_seconds given" do
120
+ before do
121
+ class Machine
122
+ def an_event?
123
+ true
124
+ end
125
+
126
+ def another_event?
127
+ true
128
+ end
129
+
130
+ def yet_another_event?
131
+ true
132
+ end
133
+ end
134
+ end
135
+
136
+ it "must run for no longer than the specified runtime_in_seconds" do
137
+ start_time = Time.now
138
+ Machine.run(2, 10) # Run every 2 seconds for not more than 10 seconds.
139
+ finish_time = Time.now
140
+ run_time = finish_time - start_time
141
+ run_time.must_be_close_to 10, 0.1
142
+ end
143
+ end
144
+
145
+ end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventful.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2019-08-02 00:00:00.000000000 Z
12
- dependencies: []
10
+ date: 2025-07-28 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: stateful.rb
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  description: By defining predicate methods which except for the addition of '?' matches
14
27
  a state machine event and then configuring an in memory or cron-based event loop,
15
28
  the state machine will be able to change state automatically.
@@ -18,18 +31,25 @@ executables: []
18
31
  extensions: []
19
32
  extra_rdoc_files: []
20
33
  files:
34
+ - Gemfile
35
+ - README.md
36
+ - eventful.rb.gemspec
21
37
  - lib/Eventful.rb
22
38
  - lib/Eventful/ActiveRecord.rb
23
39
  - lib/Eventful/ActiveRecord/ClassMethods.rb
24
40
  - lib/Eventful/ClassMethods.rb
25
41
  - lib/Eventful/Poro.rb
26
42
  - lib/Eventful/Poro/ClassMethods.rb
43
+ - lib/Eventful/VERSION.rb
27
44
  - lib/ObjectSpace/self.select_objects.rb
28
- homepage: http://github.com/thoran/Eventful
45
+ - test/ActiveRecord.rb
46
+ - test/ActiveRecordWhenNoFinalState.rb
47
+ - test/Eventful.rb
48
+ - test/Poro.rb
49
+ homepage: http://github.com/thoran/eventful.rb
29
50
  licenses:
30
- - MIT
51
+ - Ruby
31
52
  metadata: {}
32
- post_install_message:
33
53
  rdoc_options: []
34
54
  require_paths:
35
55
  - lib
@@ -44,8 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
64
  - !ruby/object:Gem::Version
45
65
  version: '0'
46
66
  requirements: []
47
- rubygems_version: 3.0.3
48
- signing_key:
67
+ rubygems_version: 3.7.1
49
68
  specification_version: 4
50
69
  summary: Automatically change state with Stateful state machines.
51
70
  test_files: []