stateful 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 85ae4d99568569f667a41d4b1959cc511f300dea
4
+ data.tar.gz: af2c257fdfcedf21ea5b760537c9d32c004ac74e
5
+ SHA512:
6
+ metadata.gz: 8b714fc19974ee231d8baf208c655f835a6c002fa12c984740f0a14a29449a8b3595b7e7297ecf203dc318f077ec49f7ad8c0be396b818d3b915502f5db59255
7
+ data.tar.gz: 1b6d4c06b40dad7123e6a6f6c946596ca0f1a1665cff1b0e4fd9f7e68012703def03a97c36417584ccfb8e1ac221f48a84233809907e146a6b49dd966bb1d801
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stateful.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 jake hoffner
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,115 @@
1
+ # Stateful
2
+
3
+ A simple state machine gem. Works with plain ruby objects and Mongoid. This gem aims
4
+ to keep things simple. It supports the following:
5
+
6
+ - Single state attribute/field per object
7
+ - Simple event model, just use plain ruby methods as your events and use the change_state helper to change the state.
8
+ - Supports virtual/grouped states that can be used to break down top level states into more granular sub-states.
9
+ - Utilizes ActiveSupport::Callbacks
10
+ - Simple hash structure for defining states and their possible transitions. No complicated DSL to learn.
11
+ - ActiveSupport is the only dependency.
12
+ - Very small code footprint.
13
+ - Mongoid support, automatically creates field, validations and scopes for you.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'stateful'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install stateful
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ class Project
33
+ include Stateful
34
+
35
+ attr_reader :published_at
36
+
37
+ stateful default: :new,
38
+ events: [:publish, :unpublish, :approve, :close, :mark_as_duplicate],
39
+ states: {
40
+ active: {
41
+ new: :published,
42
+ published: {
43
+ needs_approval: [:approved, :duplicate],
44
+ approved: :closed
45
+ }
46
+ },
47
+ inactive: {
48
+ closed: nil,
49
+ duplicate: nil
50
+ }
51
+ }
52
+
53
+ def publish
54
+ # change the state to needs_approval and fire publish events. The block will only be
55
+ # called if the state can successfully be changed.
56
+ change_state(:needs_approval, :publish) do
57
+ @published_at = Time.now
58
+ end
59
+ end
60
+
61
+ # use callbacks if you want
62
+ after_publish do |project|
63
+ NotificationService.notify_project_published(project)
64
+ end
65
+
66
+ # define other event methods ...
67
+ end
68
+
69
+ project = Project.new
70
+ project.active? # => true
71
+ project.new? # => true
72
+ project.published? # => false
73
+ ```
74
+
75
+ If you are using with Mongoid a field called state will automatically be created for you.
76
+
77
+ ```ruby
78
+ class Project
79
+ include Mongoid::Document # must be included first
80
+ include Stateful
81
+
82
+ field :published_at, type: Time
83
+
84
+ stateful default: :new,
85
+ events: [:publish, :unpublish, :approve, :close, :mark_as_duplicate],
86
+ states: {
87
+ active: {
88
+ new: :published,
89
+ published: {
90
+ needs_approval: [:approved, :duplicate],
91
+ approved: :closed
92
+ }
93
+ },
94
+ inactive: {
95
+ closed: nil,
96
+ duplicate: nil
97
+ }
98
+ }
99
+
100
+
101
+ # ...
102
+ end
103
+
104
+ # scopes are automatically created for you
105
+ Project.active.count
106
+ Project.published.count
107
+ ```
108
+
109
+ ## Contributing
110
+
111
+ 1. Fork it
112
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
113
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
114
+ 4. Push to the branch (`git push origin my-new-feature`)
115
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ module Stateful
2
+ module Mongoid
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ protected
7
+
8
+ def define_state_attribute(options)
9
+ field :state, type: Symbol, default: options[:default]
10
+ validates_inclusion_of :state,
11
+ in: state_infos.keys,
12
+ message: options.has_key?(:message) ? options[:message] : 'invalid state value',
13
+ allow_nil: !!options[:allow_nil]
14
+
15
+ # configure scopes to query the attribute value
16
+ state_infos.values.each do |info|
17
+ states = info.collect_child_states
18
+ if states.length == 1
19
+ scope info.name, where(state: states.first)
20
+ else
21
+ scope info.name, where(:state.in => states)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ module Stateful
2
+ class StateInfo
3
+ attr_reader :parent, :children, :name, :to_transitions
4
+ def initialize(state_class, parent, name, config)
5
+ @state_class = state_class
6
+ if parent
7
+ @parent = parent
8
+ parent.children << self
9
+ end
10
+
11
+ @name = name
12
+ @to_transitions = []
13
+
14
+ if config.is_a?(Hash)
15
+ @groupConfig = config
16
+ @children = []
17
+ else
18
+ @to_transitions = config ? (config.is_a?(Array) ? config : [config]) : []
19
+ end
20
+ end
21
+
22
+ def is?(state)
23
+ (@name == state or (parent and parent.is?(state)))
24
+ end
25
+
26
+ def is_group?
27
+ !!@groupConfig
28
+ end
29
+
30
+ def can_transition_to?(state)
31
+ state_info = @state_class.state_infos[state]
32
+ if is_group? or state_info.nil? or state_info.is_group?
33
+ false
34
+ else
35
+ to_transitions.include?(state)
36
+ end
37
+ end
38
+
39
+ def collect_child_states
40
+ is_group? ? children.flat_map(&:collect_child_states) : [name]
41
+ end
42
+
43
+ def expand_to_transitions
44
+ if to_transitions.any?
45
+ @to_transitions = to_transitions.flat_map do |to|
46
+ info = @state_class.state_infos[to]
47
+
48
+ if info.is_group?
49
+ info.collect_child_states
50
+ else
51
+ [info.name]
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module Stateful
2
+ VERSION = "0.0.1"
3
+ end
data/lib/stateful.rb ADDED
@@ -0,0 +1,142 @@
1
+ require "stateful/version"
2
+ require "stateful/state_info"
3
+
4
+ module Stateful
5
+ extend ActiveSupport::Concern
6
+ include ActiveSupport::Callbacks
7
+
8
+ included do
9
+ if defined?(Mongoid)
10
+ require 'mongoid/document'
11
+ include Stateful::Mongoid if included_modules.include?(::Mongoid::Document)
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ def state_infos
17
+ @state_infos ||= {}
18
+ end
19
+
20
+ def stateful(options)
21
+ options[:events] ||= []
22
+
23
+ define_method 'state_events' do
24
+ options[:events]
25
+ end
26
+
27
+ define_method 'state_info' do
28
+ self.class.state_infos[self.state]
29
+ end
30
+
31
+ define_method 'state_valid?' do
32
+ self.class.state_infos.keys.include?(state)
33
+ end
34
+
35
+ define_method 'change_state' do |new_state, options = {}, &block|
36
+ return false if new_state == state
37
+ return false unless state_info.can_transition_to?(new_state)
38
+
39
+ # convert shortcut event name to options hash
40
+ options = {event: options} if options.is_a? Symbol
41
+ options[:persist_methods] = [:persist_state, :save]
42
+
43
+ _change_state(new_state, options, &block)
44
+ end
45
+
46
+ define_method 'change_state!' do |new_state, options = {}, &block|
47
+ return false if new_state == state
48
+ raise "transition from #{state} to #{new_state} not allowed" unless state_info.can_transition_to?(new_state)
49
+
50
+ # convert shortcut event name to options hash
51
+ options = {event: options} if options.is_a? Symbol
52
+ options[:persist_methods] = [:persist_state!, :save!]
53
+ _change_state(new_state, options, &block)
54
+ end
55
+
56
+ define_method '_change_state' do |new_state, options, &block|
57
+ # do a little magic and infer the event name from the method name used to call change_state
58
+ # TODO: decide if this is too magical, for now it has been commented out.
59
+ #unless options[:event]
60
+ # calling_method = caller[1][/`.*'/][1..-2].gsub('!', '').to_sym
61
+ # options[:event] = calling_method if state_events.include? calling_method
62
+ #end
63
+
64
+ if block and block.call == false
65
+ false
66
+ else
67
+ callbacks = [:state_change]
68
+ callbacks << options[:event] if options[:event]
69
+ run_callbacks *callbacks do
70
+ self.state = new_state
71
+ if options[:persist_methods]
72
+ method = options[:persist_methods].find {|m| respond_to?(m)}
73
+ __send__(method) if method
74
+ end
75
+ if respond_to?(:persist_state)
76
+ persist_state
77
+ elsif respond_to?(:save!)
78
+ save!
79
+ end
80
+ end
81
+ true
82
+ end
83
+ end
84
+
85
+ private :_change_state
86
+
87
+ define_method 'can_transition_to?' do |new_state|
88
+ state_info.can_transition_to?(new_state)
89
+ end
90
+
91
+ # init and configure state info
92
+ init_state_info(options[:states])
93
+ state_infos.values.each do |info|
94
+ info.expand_to_transitions
95
+
96
+ define_method "#{info.name}?" do
97
+ info.is?(self.state)
98
+ end
99
+ end
100
+
101
+
102
+ define_state_attribute(options)
103
+
104
+ # define the event callbacks
105
+ events = ([:state_change] + options[:events])
106
+ define_callbacks *events
107
+
108
+ # define callback helpers
109
+ events.each do |event|
110
+ define_singleton_method "before_#{event}" do |method = nil, &block|
111
+ set_callback(event, :before, method ? method : block)
112
+ end
113
+
114
+ define_singleton_method "after_#{event}" do |method = nil, &block|
115
+ set_callback(event, :after, method ? method : block)
116
+ end
117
+ end
118
+ end
119
+
120
+ protected
121
+ def define_state_attribute(options)
122
+ define_method 'state' do
123
+ instance_variable_get(:@state) || options[:default]
124
+ end
125
+
126
+ define_method 'state=' do |val|
127
+ instance_variable_set(:@state, val)
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ def init_state_info(values, parent = nil)
134
+ values.each do |name, config|
135
+ info = state_infos[name] = Stateful::StateInfo.new(self, parent, name, config)
136
+ init_state_info(config, info) if info.is_group?
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ require 'stateful/mongoid' if defined?(Mongoid)
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require './lib/stateful'
3
+ require 'mongoid'
4
+
5
+
6
+ class Kata
7
+ include Mongoid::Document
8
+ include Stateful
9
+
10
+ stateful default: :draft, events: [:publish, :approve, :retire], states: {
11
+ :draft => :beta,
12
+ beta: {
13
+ :needs_testing => :needs_approval,
14
+ :needs_approval => :approved
15
+ },
16
+ :approved => :retired,
17
+ :retired => nil
18
+ }
19
+ end
20
+
21
+ describe Stateful::Mongoid do
22
+ let(:kata) {Kata.new}
23
+
24
+ it 'should support creating a state field' do
25
+ Kata.fields.keys.include?('state').should be_true
26
+ end
27
+
28
+ it 'should support validating state values' do
29
+ kata.state.should == :draft
30
+ kata.valid?.should be_true
31
+ kata.state = :invalid
32
+ kata.valid?.should be_false
33
+ end
34
+
35
+ it 'should support can_transition_to?' do
36
+ kata.can_transition_to?(:beta).should be_true
37
+ kata.can_transition_to?(:retired).should be_false
38
+ end
39
+
40
+ it 'should create scopes for each state and virtual state' do
41
+ Kata.beta.selector.should == {"state" => {"$in" => [:needs_testing, :needs_approval]}}
42
+ Kata.draft.selector.should == {"state" => :draft}
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ require 'mongoid'
6
+ require 'mongoid/document'
7
+
8
+ #
9
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+
21
+ end
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+ require './lib/stateful'
3
+
4
+ class Kata
5
+ include Stateful
6
+
7
+ attr_accessor :approved_by, :ready_score, :published_at, :state_changes
8
+
9
+ def initialize
10
+ @ready_score = 0
11
+ @state_changes = 0
12
+ end
13
+
14
+ stateful default: :draft,
15
+ events: [:publish, :unpublish, :approve, :retire],
16
+ states: {
17
+ :draft => :beta,
18
+ published: {
19
+ beta: {
20
+ :needs_feedback => [:draft, :needs_approval],
21
+ :needs_approval => [:draft, :approved]
22
+ },
23
+ :approved => :retired
24
+ },
25
+ :retired => nil
26
+ }
27
+
28
+
29
+ after_state_change do |doc|
30
+ doc.state_changes += 1
31
+ end
32
+
33
+ def vote(ready)
34
+ @ready_score += ready ? 1 : -1
35
+
36
+ # votes only affect state when in beta
37
+ if beta?
38
+ if enough_votes_for_approval? and needs_feedback?
39
+ change_state(:needs_approval)
40
+ elsif not enough_votes_for_approval? and needs_approval?
41
+ change_state(:needs_feedback)
42
+ end
43
+ end
44
+ end
45
+
46
+ def publish
47
+ change_state(enough_votes_for_approval? ? :needs_approval : :needs_feedback) do
48
+ @published_at = Time.now
49
+ end
50
+ end
51
+
52
+ def unpublish
53
+ change_state(:draft)
54
+ end
55
+
56
+ def approve(approved_by)
57
+ change_state(:approved) do
58
+ @approved_by = approved_by
59
+ end
60
+ end
61
+
62
+ def retire
63
+ change_state(:retire)
64
+ end
65
+
66
+ def enough_votes_for_approval?
67
+ ready_score >= 10
68
+ end
69
+ end
70
+
71
+ describe Kata do
72
+ let(:kata) {Kata.new}
73
+
74
+ it 'should support state_infos' do
75
+ Kata.state_infos.should_not be_nil
76
+ end
77
+
78
+ it 'should support default state' do
79
+ kata.state.should == :draft
80
+ end
81
+
82
+ it 'should support state_info' do
83
+ kata.state_info.should_not be_nil
84
+ kata.state_info.name.should == :draft
85
+ end
86
+
87
+ it 'should support simple boolean helper methods' do
88
+ kata.draft?.should be_true
89
+ kata.published?.should be_false
90
+ end
91
+
92
+ context 'change_state' do
93
+ it 'should raise error when an invalid transition state is provided' do
94
+ expect{kata.change_state(:retired)}.to raise_error
95
+ end
96
+
97
+ it 'should raise error when a group state is provided' do
98
+ expect{kata.change_state(:beta)}.to raise_error
99
+ end
100
+
101
+ it 'should return false when state is the same' do
102
+ kata.change_state(:draft).should be_false
103
+ end
104
+
105
+ it 'should support state_valid?' do
106
+ kata.state_valid?.should be_true
107
+ end
108
+
109
+ it 'should change the state when a proper state is provided' do
110
+ kata.change_state(:needs_feedback).should be_true
111
+ kata.state.should == :needs_feedback
112
+ kata.change_state(:needs_approval).should be_true
113
+ kata.state.should == :needs_approval
114
+ kata.change_state(:draft).should be_true
115
+ kata.state.should == :draft
116
+ kata.change_state(:needs_approval).should be_true
117
+ kata.change_state(:approved).should be_true
118
+ kata.state.should == :approved
119
+ end
120
+
121
+ it 'should support calling passed blocks when state is valid' do
122
+ kata.published_at.should be_nil
123
+ kata.publish
124
+ kata.published_at.should_not be_nil
125
+ end
126
+
127
+ it 'should support ingoring passed blocked when state is not valid' do
128
+ kata.approve('test')
129
+ kata.approved?.should be_false
130
+ kata.approved_by.should be_nil
131
+ end
132
+
133
+ it 'should support after callbacks methods' do
134
+ kata.publish
135
+ kata.state_changes.should == 1
136
+ end
137
+ end
138
+
139
+ describe Stateful::StateInfo do
140
+ it 'should support is?' do
141
+ Kata.state_infos[:draft].is?(:draft).should be_true
142
+ Kata.state_infos[:needs_feedback].is?(:published).should be_true
143
+ Kata.state_infos[:needs_feedback].is?(:beta).should be_true
144
+ Kata.state_infos[:approved].is?(:published).should be_true
145
+ Kata.state_infos[:approved].is?(:beta).should be_false
146
+ Kata.state_infos[:retired].is?(:beta).should be_false
147
+ end
148
+
149
+ it 'should support expanded to transitions' do
150
+ Kata.state_infos[:draft].to_transitions.should == [:needs_feedback, :needs_approval]
151
+ Kata.state_infos[:needs_approval].to_transitions.should == [:draft, :approved]
152
+
153
+ Kata.state_infos[:retired].to_transitions.should be_empty
154
+
155
+ p Kata.instance_methods
156
+ end
157
+ end
158
+ end
data/stateful.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stateful/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "stateful"
8
+ spec.version = Stateful::VERSION
9
+ spec.authors = ["jake hoffner"]
10
+ spec.email = ["jake@codewars.com"]
11
+ spec.description = %q{A simple state machine gem}
12
+ spec.summary = %q{A simple state machine gem. Works with plain ruby objects and Mongoid. This gem aims
13
+ to keep things simple.}
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'activesupport'
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "mongoid", "~> 3.0"
27
+
28
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stateful
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - jake hoffner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mongoid
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: A simple state machine gem
84
+ email:
85
+ - jake@codewars.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - lib/stateful.rb
96
+ - lib/stateful/mongoid.rb
97
+ - lib/stateful/state_info.rb
98
+ - lib/stateful/version.rb
99
+ - spec/mongoid_spec.rb
100
+ - spec/spec_helper.rb
101
+ - spec/stateful_spec.rb
102
+ - stateful.gemspec
103
+ homepage: ''
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.0.3
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: A simple state machine gem. Works with plain ruby objects and Mongoid. This
127
+ gem aims to keep things simple.
128
+ test_files:
129
+ - spec/mongoid_spec.rb
130
+ - spec/spec_helper.rb
131
+ - spec/stateful_spec.rb