machina 0.0.1

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: d67cfd0648b85a02e58ce0f287c24a5f2a2424ff50ac949b1272f44885cb3f77
4
+ data.tar.gz: 341433286e327508944bd8fac79640b0be466288629fe02f4c296ba3f3ea01cd
5
+ SHA512:
6
+ metadata.gz: 8e34227ae96d02e0682e7c3a489d318baffcb95b91d6068b740010e4640f1f3bad6da62e03683ce259bfd8db02032aae4a23392d54c951140ee6fd185b2e24d3
7
+ data.tar.gz: edefe97cd25753f5d7458502cc625817b3204c0957e5351eb3a2ef9889dea8e72f22b0ac315ef521ccc8ba94b52aff0c7f28b2c3693a7ea0d428cc1c4ec3c371
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ machina (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ machina!
15
+
16
+ BUNDLED WITH
17
+ 1.17.2
data/Makefile ADDED
@@ -0,0 +1,13 @@
1
+ .PHONY: *
2
+
3
+ default: test
4
+
5
+ build:
6
+ rm *.gem
7
+ gem build machina.gemspec
8
+
9
+ publish: build
10
+ gem push *.gem
11
+
12
+ test:
13
+ ruby -Ilib:spec spec/*_spec.rb
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # Machina
2
+
3
+ _a god introduced by means of a crane in ancient Greek and Roman drama to decide the final outcome_
4
+
5
+ ![](https://theatricaleffectsandstaging.files.wordpress.com/2016/05/untitled1.png?w=390&h=326)
6
+
7
+ ```ruby
8
+ fsm = Machina.new(:unconfirmed)
9
+
10
+ fsm.when[:welcome_email] = -> { send_welcome_email }
11
+ fsm.when[:enable_account] = -> (user) { user.enabled! }
12
+
13
+ fsm[:confirm] = {
14
+ :unconfirmed => [:welcome_email, :enable_account, :confirmed],
15
+ }
16
+
17
+ fsm.on[:confirm] = -> (user) { puts "Starting confirmation process for #{user.id}." }
18
+
19
+ fsm.state # => :unconfirmed
20
+ fsm.trigger!(:confirm, user)
21
+ fsm.state # => :confirmed
22
+ ```
data/lib/machina.rb ADDED
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Machina
4
+ InvalidEventError = Class.new(StandardError)
5
+ InvalidStateChangeError = Class.new(StandardError)
6
+
7
+ EVENT = -> (h, k) { h[k] = ->(*args) {} }
8
+
9
+ attr_reader :state, :events
10
+
11
+ # Initializes Machina
12
+ #
13
+ # @param initial_state [Symbol] the initial state of the state machine
14
+ # @return [Machina] the initialized Machina
15
+ #
16
+ def initialize(initial_state)
17
+ @state = initial_state
18
+ @events = Hash.new { |h, k| h[k] = [] }
19
+ end
20
+
21
+ # Triggers an event.
22
+ #
23
+ # @param event [Symbol] the event to trigger
24
+ # @param args [Array<Object>] the objects that the callback will receive
25
+ # @return [void]
26
+ #
27
+ def trigger(event, *args)
28
+ return unless trigger?(event)
29
+
30
+ Array(events[event][state]).each do |candidate_state|
31
+ begin
32
+ self.when[candidate_state].call(*args)
33
+ rescue StandardError
34
+ break
35
+ end
36
+
37
+ @state = candidate_state
38
+ end
39
+
40
+ on[event].call(*args)
41
+ end
42
+
43
+ # Triggers an event and raises on error.
44
+ #
45
+ # @param event [Symbol] the event to trigger
46
+ # @param args [Array<Object>] the objects that the callback will receive
47
+ # @return [void]
48
+ #
49
+ def trigger!(event, *args)
50
+ raise InvalidStateChangeError, "Event #{event} missing #{state} step" unless trigger?(event)
51
+
52
+ trigger(event, *args)
53
+ end
54
+
55
+ # Checks if an event can be triggered
56
+ #
57
+ # @param event [Symbol] the event to trigger
58
+ # @return [Boolean] the chance posibility
59
+ #
60
+ def trigger?(event)
61
+ raise InvalidEventError, "Event #{event} not found." unless events.key?(event)
62
+
63
+ events[event].key?(state)
64
+ end
65
+
66
+ # Defines the list of possible callbacks when an event is triggered
67
+ #
68
+ # @return [Hash]
69
+ #
70
+ def on
71
+ @on ||= Hash.new(&EVENT)
72
+ end
73
+
74
+ # Defines the list of possible callbacks when a state is reached
75
+ #
76
+ # @return [Hash]
77
+ #
78
+ def when
79
+ @when ||= Hash.new(&EVENT)
80
+ end
81
+
82
+ # Defines the list of possible events and their transitions
83
+ #
84
+ # @param key [Symbol] the event name
85
+ # @param states [Hash] the event transitions
86
+ # @return [void]
87
+ #
88
+ def []=(key, states)
89
+ events[key] = states
90
+ end
91
+ end
data/machina.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "machina"
5
+ s.version = "0.0.1"
6
+ s.summary = "Simple state machine"
7
+ s.description = "Really really simple state machine"
8
+ s.authors = ["elcuervo"]
9
+ s.licenses = %w[MIT HUGWARE]
10
+ s.email = ["elcuervo@elcuervo.net"]
11
+ s.homepage = "http://github.com/elcuervo/machina"
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files test`.split("\n")
14
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+
4
+ Post = Struct.new(:title, :notified, :published)
5
+
6
+ describe Machina do
7
+ attr_reader :fsm
8
+
9
+ before { @fsm = Machina.new(:start) }
10
+
11
+ it "basic" do
12
+ fsm[:begin] = { :start => :step1 }
13
+
14
+ assert_equal :start, fsm.state
15
+
16
+ fsm.trigger(:begin)
17
+
18
+ assert_equal :step1, fsm.state
19
+ end
20
+
21
+ it "complex" do
22
+ post = Post.new("Something HN worthy", false, false)
23
+ completed = false
24
+
25
+ fsm.when[:send_notification] = -> (post) { post.notified = true }
26
+ fsm.when[:published] = -> (post) { post.published = true }
27
+
28
+ fsm[:complete] = {
29
+ :start => [:review, :send_notification, :published],
30
+ :review => [:send_notification, :published],
31
+ :reset => :start
32
+ }
33
+
34
+ fsm.on[:complete] = -> (_post) { completed = true }
35
+
36
+ assert_equal :start, fsm.state
37
+ assert_equal false, completed
38
+ assert_equal false, post.notified
39
+ assert_equal false, post.published
40
+
41
+ fsm.trigger(:complete, post)
42
+
43
+ assert_equal :published, fsm.state
44
+ assert_equal true, completed
45
+ assert_equal true, post.notified
46
+ assert_equal true, post.published
47
+ end
48
+
49
+ it "stops on error" do
50
+ fsm.when[:stop] = -> { raise }
51
+
52
+ fsm[:act] = {
53
+ :start => [:a, :b, :stop, :final]
54
+ }
55
+
56
+ fsm.trigger(:act)
57
+
58
+ assert_equal :b, fsm.state
59
+ end
60
+
61
+ it "trigger!" do
62
+ fsm[:one] = {
63
+ :not_start => :reset
64
+ }
65
+
66
+ assert_raises(Machina::InvalidStateChangeError) { fsm.trigger!(:one) }
67
+ assert_raises(Machina::InvalidEventError) { fsm.trigger!(:two) }
68
+
69
+ assert_equal :start, fsm.state
70
+ end
71
+ end
@@ -0,0 +1,2 @@
1
+ require "minitest/autorun"
2
+ require "machina"
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: machina
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - elcuervo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Really really simple state machine
14
+ email:
15
+ - elcuervo@elcuervo.net
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - Makefile
24
+ - README.md
25
+ - lib/machina.rb
26
+ - machina.gemspec
27
+ - spec/machina_spec.rb
28
+ - spec/spec_helper.rb
29
+ homepage: http://github.com/elcuervo/machina
30
+ licenses:
31
+ - MIT
32
+ - HUGWARE
33
+ metadata: {}
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.0.3
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Simple state machine
53
+ test_files: []