minimal_state_machine 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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in minimal_state_machine.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Matteo Depalo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # MinimalStateMachine
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'minimal_state_machine'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install minimal_state_machine
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
Binary file
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ class MinimalStateMachineGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ desc "Creates migration files required by reputation system gem."
9
+
10
+ self.source_paths << File.join(File.dirname(__FILE__), 'templates')
11
+
12
+ def self.next_migration_number(path)
13
+ ActiveRecord::Generators::Base.next_migration_number(path)
14
+ end
15
+
16
+ def create_migration_files
17
+ create_migration_file_if_not_exist 'create_states'
18
+ end
19
+
20
+ private
21
+
22
+ def create_migration_file_if_not_exist(file_name)
23
+ unless self.class.migration_exists?(File.dirname(File.expand_path("db/migrate/#{file_name}")), file_name)
24
+ migration_template "#{file_name}.rb", "db/migrate/#{file_name}.rb"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ class CreateStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :msm_states do |t|
4
+ t.string :type
5
+ t.references :state_machine, :polymorphic => true
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ require 'minimal_state_machine/version'
2
+ require 'minimal_state_machine/state'
3
+ require 'active_support'
4
+
5
+ module MinimalStateMachine
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_one :state, :as => :state_machine, :class_name => 'MinimalStateMachine::State'
10
+
11
+ after_initialize :set_initial_state, :if => proc { state.nil? }
12
+
13
+ def self.states
14
+ {}
15
+ end
16
+
17
+ class InvalidStateError < StandardError; end
18
+
19
+ def state_name=(state_name)
20
+ raise InvalidStateError unless self.class.states.keys.map(&:to_s).include?(state_name)
21
+
22
+ if state.nil? || state.new_record?
23
+ self.state = self.class.states[state_name.to_sym].new
24
+ else
25
+ transition_to state_name
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ class InvalidTransitionError < StandardError; end
32
+
33
+ def transition_to(state_name)
34
+ if state.class.valid_transition_states.include?(state_name)
35
+ state.destroy
36
+ self.state = self.class.states[state_name.to_sym].new
37
+ save
38
+ else
39
+ raise InvalidTransitionError
40
+ end
41
+ end
42
+
43
+ def set_initial_state
44
+ if self.class.respond_to?(:initial_state) && self.class.initial_state
45
+ self.state_name = self.class.initial_state
46
+ else
47
+ self.state_name = self.class.states.keys.map(&:to_s).first
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_record'
2
+
3
+ module MinimalStateMachine
4
+ class State < ActiveRecord::Base
5
+ self.table_name = 'msm_states'
6
+
7
+ def self.valid_transition_states
8
+ []
9
+ end
10
+
11
+ belongs_to :state_machine, :polymorphic => true
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module MinimalStateMachine
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'minimal_state_machine/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "minimal_state_machine"
8
+ gem.version = MinimalStateMachine::VERSION
9
+ gem.authors = ["Matteo Depalo"]
10
+ gem.email = ["matteodepalo@gmail.com"]
11
+ gem.description = %q{A state machine for activerecord implemented with the state pattern}
12
+ gem.summary = %q{A state machine implemented with the state pattern}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'activerecord'
21
+ gem.add_dependency 'activesupport'
22
+
23
+ gem.add_development_dependency 'rspec'
24
+ gem.add_development_dependency 'debugger'
25
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'msm_states'")
4
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'state_machines'")
5
+ ActiveRecord::Base.connection.create_table(:msm_states) do |t|
6
+ t.string :type
7
+ t.references :state_machine, :polymorphic => true
8
+ t.timestamps
9
+ end
10
+
11
+ ActiveRecord::Base.connection.create_table(:state_machines)
12
+
13
+ class StateMachine < ActiveRecord::Base
14
+ include MinimalStateMachine
15
+
16
+ def self.states
17
+ { :open => StateMachineOpen, :closed => StateMachineClosed, :solved => StateMachineSolved }
18
+ end
19
+
20
+ def self.initial_state
21
+ 'open'
22
+ end
23
+ end
24
+
25
+ class StateMachineOpen < MinimalStateMachine::State
26
+ def self.valid_transition_states
27
+ %w(closed)
28
+ end
29
+ end
30
+
31
+ class StateMachineClosed < MinimalStateMachine::State
32
+ def self.valid_transition_states
33
+ %w(solved open)
34
+ end
35
+ end
36
+
37
+ class StateMachineSolved < MinimalStateMachine::State; end
38
+
39
+ describe StateMachine do
40
+ before(:each) do
41
+ @state_machine = StateMachine.create
42
+ end
43
+
44
+ it 'sets the initial state' do
45
+ @state_machine.state.should be_a(StateMachineOpen)
46
+ end
47
+
48
+ it 'changes state' do
49
+ @state_machine.state_name = 'closed'
50
+
51
+ @state_machine.state.should be_a(StateMachineClosed)
52
+ end
53
+
54
+ it 'raises an invalid transition error if the new state is not among the allowed transition states' do
55
+ expect { @state_machine.state_name = 'solved' }.to raise_error('MinimalStateMachine::InvalidTransitionError')
56
+ end
57
+
58
+ it 'raises an invalid state error if the state assigned in not among the allowed states' do
59
+ expect { @state_machine.state_name = 'invalid_state' }.to raise_error('MinimalStateMachine::InvalidStateError')
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ require 'minimal_state_machine'
2
+ require 'debugger'
3
+
4
+ root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
5
+ ActiveRecord::Base.establish_connection(
6
+ :adapter => "sqlite3",
7
+ :database => "#{root}/db/minimal_state_machine.sqlite3"
8
+ )
9
+
10
+ RSpec.configure do |config|
11
+ config.before(:each) do
12
+ ActiveRecord::Base.connection.increment_open_transactions
13
+ ActiveRecord::Base.connection.begin_db_transaction
14
+ end
15
+
16
+ config.after(:each) do
17
+ ActiveRecord::Base.connection.rollback_db_transaction
18
+ ActiveRecord::Base.connection.decrement_open_transactions
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minimal_state_machine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matteo Depalo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: debugger
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: A state machine for activerecord implemented with the state pattern
79
+ email:
80
+ - matteodepalo@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - db/minimal_state_machine.sqlite3
92
+ - lib/generators/minimal_state_machine/minimal_state_machine_generator.rb
93
+ - lib/generators/minimal_state_machine/templates/create_states.rb
94
+ - lib/minimal_state_machine.rb
95
+ - lib/minimal_state_machine/state.rb
96
+ - lib/minimal_state_machine/version.rb
97
+ - minimal_state_machine.gemspec
98
+ - spec/minimal_state_machine_spec.rb
99
+ - spec/spec_helper.rb
100
+ homepage: ''
101
+ licenses: []
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 1.8.24
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: A state machine implemented with the state pattern
124
+ test_files:
125
+ - spec/minimal_state_machine_spec.rb
126
+ - spec/spec_helper.rb