mutator 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 266ddb73a57d444d63b9f9460df79a5eb8d19089
4
- data.tar.gz: 8597a08ee353f97a42a3d7469bf187c494ce1723
3
+ metadata.gz: d69e47c148240cf6a7f6000f259980b0ef39caa6
4
+ data.tar.gz: b1aa0ed144d14bd76ab91a1884f7d005519afbb3
5
5
  SHA512:
6
- metadata.gz: 0f84541de39489ad4dab75b699e895b9f552cf86b0302cc02c93865d64001f43a646d7726515432bb29656df2a6987546122c7906c79047606a1ee0f8f73fb8e
7
- data.tar.gz: 0e640ac518c45bf09731a77201096c1d57d860fc34ca8e7c90dc85f58e93222fee50d1c9fd9e4b355bf7adc38705f0d274ab2eebd86b3f4779817a813d1d398b
6
+ metadata.gz: ae7fdbe701040f8116984b8ed5222231f97333dfa1b62068eec392b3aa9ea5f05cf40ed60d3a33b5ab3616f1175ef910e5b9d6ddeeb268b22806f4d7f2865fc5
7
+ data.tar.gz: 94afab94f0b66e4b76d1c6f5086fb5080db2040eab6215dc55254ee0b365932a133f0fcdc7597497ba659eead9d185c19d6591e6c39ca117498a2028cc3572c9
data/.hound.yml ADDED
@@ -0,0 +1,5 @@
1
+ StringLiterals:
2
+ Enabled: false
3
+
4
+ AccessModifierIndentation:
5
+ EnforcedStyle: outdent
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ [![Gem Version](https://badge.fury.io/rb/mutator.png)](http://badge.fury.io/rb/mutator)
2
+ [![Build Status](https://travis-ci.org/ericroberts/mutator.png?branch=master)](https://travis-ci.org/ericroberts/mutator)
3
+ [![Code Climate](https://codeclimate.com/github/ericroberts/mutator.png)](https://codeclimate.com/github/ericroberts/mutator)
4
+ [![Coverage Status](https://coveralls.io/repos/ericroberts/mutator/badge.png?branch=master)](https://coveralls.io/r/ericroberts/mutator?branch=master)
5
+
1
6
  # Mutator
2
7
 
3
8
  Yes, this is another state machine gem. Why? Well, among the major state machine gems I found, they didn't quite do what I was looking for. So I wrote my own. Plus, reinventing the wheel is fun!
@@ -46,7 +51,7 @@ end
46
51
 
47
52
  ### So how do I use it?
48
53
 
49
- Transition looks like this:
54
+ Transitions look like this:
50
55
 
51
56
  ``` ruby
52
57
  wonder = Wonder.new
@@ -5,7 +5,7 @@ module Mutator
5
5
  end
6
6
 
7
7
  def self.included(base)
8
- "Mutator::#{base.name}".constantize.states.each do |state|
8
+ Mutator.const_get(base.name, false).states.each do |state|
9
9
  base.send(:define_singleton_method, state) do
10
10
  self.where(state: state)
11
11
  end
@@ -15,7 +15,7 @@ module Mutator
15
15
  protected
16
16
 
17
17
  def machine_class
18
- "Mutator::#{self.class.name}".constantize
18
+ Mutator.const_get(self.class.name, false)
19
19
  end
20
20
  end
21
21
  end
@@ -14,11 +14,11 @@ module Mutator
14
14
  stateholder.state
15
15
  end
16
16
 
17
- def transition(to:, success: lambda { |_transition| }, failure: lambda { |_transition| })
18
- transition = Transition.new(to: to, from: current_state, machine: self)
17
+ def transition(options)
18
+ options = extract(options)
19
+ success, failure, transition = options.values
19
20
 
20
- if transition.valid?
21
- stateholder.state = to
21
+ if transition.call
22
22
  success.call(transition)
23
23
  true
24
24
  else
@@ -28,8 +28,9 @@ module Mutator
28
28
  end
29
29
 
30
30
  def self.states
31
- self.transitions.map do |t|
32
- [t[:to], t[:from]]
31
+ self.transitions.map do |transition|
32
+ to, from = transition[:to], transition[:from]
33
+ [to, from]
33
34
  end.flatten.uniq
34
35
  end
35
36
 
@@ -40,5 +41,22 @@ module Mutator
40
41
  def transitions
41
42
  self.class.transitions
42
43
  end
44
+
45
+ protected
46
+
47
+ def extract(options)
48
+ to = options[:to]
49
+ fail ArgumentError, 'must provide state to transition to' unless to
50
+
51
+ {
52
+ success: lambda { |_| },
53
+ failure: lambda { |_| },
54
+ transition: Transition.new(
55
+ to: to,
56
+ from: current_state,
57
+ machine: self
58
+ )
59
+ }.merge(options)
60
+ end
43
61
  end
44
62
  end
@@ -2,23 +2,42 @@ module Mutator
2
2
  class Transition
3
3
  attr_reader :to, :from, :machine
4
4
 
5
- def initialize(to:, from:, machine:)
6
- @to, @from, @machine = to, from, machine
5
+ def initialize(opts)
6
+ require_parameters!(opts)
7
+ @to, @from, @machine = opts[:to], opts[:from], opts[:machine]
8
+ end
9
+
10
+ def call
11
+ stateholder.state = to if valid?
7
12
  end
8
13
 
9
14
  def valid?
10
- transitions.present?
15
+ transitions.length > 0
11
16
  end
12
17
 
13
18
  def stateholder
14
19
  machine.stateholder
15
20
  end
16
21
 
22
+ def ==(other)
23
+ to == other.to && from == other.from && machine == other.machine
24
+ end
25
+
26
+ def eql?(other)
27
+ public_send(:==, other)
28
+ end
29
+
17
30
  protected
18
31
 
19
32
  def transitions
20
- machine.transitions.select do |t|
21
- t[:to] == to && t[:from].include?(from)
33
+ machine.transitions.select do |transition|
34
+ transition[:to] == to && transition[:from].include?(from)
35
+ end
36
+ end
37
+
38
+ def require_parameters!(opts)
39
+ [:to, :from, :machine].each do |attr|
40
+ fail ArgumentError, "must provide #{attr}" unless opts[attr]
22
41
  end
23
42
  end
24
43
  end
@@ -1,3 +1,3 @@
1
1
  module Mutator
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/mutator.gemspec CHANGED
@@ -22,4 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "rspec", "~> 3.0"
24
24
  spec.add_development_dependency "coveralls"
25
+ spec.add_development_dependency "awesome_print"
26
+ spec.add_development_dependency "pry"
25
27
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'support/test_classes'
3
+
4
+ describe Mutator::Helpers do
5
+ subject { Mutator::Helpers }
6
+
7
+ describe '.included' do
8
+ let(:base) { Stateholder }
9
+
10
+ it 'should not error' do
11
+ expect { subject.included(base) }.to_not raise_error
12
+ end
13
+ end
14
+
15
+ context 'when included' do
16
+ subject { Stateholder.new }
17
+
18
+ describe '#machine' do
19
+ it 'should respond to it' do
20
+ expect(subject).to respond_to :machine
21
+ end
22
+
23
+ it 'should return a Mutator::Stateholder object' do
24
+ expect(subject.machine).to be_a Mutator::Stateholder
25
+ end
26
+ end
27
+
28
+ [:initial_state, :second_state, :third_state].each do |state|
29
+ describe ".#{state}" do
30
+ it 'should respond to the method' do
31
+ expect(subject.class).to respond_to state
32
+ end
33
+
34
+ it 'should call where on the stateholder' do
35
+ expect(subject.class).to receive(:where).
36
+ with(state: state).
37
+ and_return(Stateholder.new)
38
+ subject.class.public_send(state)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+ require 'support/test_classes'
3
+
4
+ describe Mutator::Stateholder do
5
+ subject { Mutator::Stateholder.new(stateholder) }
6
+ let(:stateholder) { Stateholder.new }
7
+
8
+ describe '#initialize' do
9
+ it 'should not error' do
10
+ expect { subject }.to_not raise_error
11
+ end
12
+ end
13
+
14
+ describe '#stateholder' do
15
+ it 'should return the stateholder it was passed' do
16
+ expect(subject.stateholder).to eq stateholder
17
+ end
18
+ end
19
+
20
+ describe '#valid?' do
21
+ it 'should be valid if the state exists in states list' do
22
+ subject.stateholder.state = :initial_state
23
+ expect(subject).to be_valid
24
+ end
25
+
26
+ it 'should not be valid for a state not in states list' do
27
+ subject.stateholder.state = :foobar
28
+ expect(subject).to_not be_valid
29
+ end
30
+ end
31
+
32
+ describe '#current_state' do
33
+ it 'should return the stateholder state' do
34
+ expect(subject.current_state).to eq stateholder.state
35
+ end
36
+ end
37
+
38
+ describe '#transition' do
39
+ let(:transition) do
40
+ Mutator::Transition.new(to: to, from: from, machine: subject)
41
+ end
42
+
43
+ context 'arguments' do
44
+ it 'should raise an exception if you do not provide to' do
45
+ expect { subject.transition }.to raise_error ArgumentError
46
+ end
47
+
48
+ it 'should not raise if to is provided' do
49
+ expect { subject.transition to: :any_state }.to_not raise_error
50
+ end
51
+ end
52
+
53
+ context 'valid transition' do
54
+ let(:from) { :initial_state }
55
+ let(:to) { :second_state }
56
+
57
+ before { subject.stateholder.state = from }
58
+
59
+ it 'should update state' do
60
+ expect(subject.stateholder.state).to eq from
61
+ subject.transition(to: to)
62
+ expect(subject.stateholder.state).to eq to
63
+ end
64
+
65
+ it 'should return true' do
66
+ expect(subject.transition(to: to)).to be true
67
+ end
68
+
69
+ context 'with success policy' do
70
+ let(:success) { double }
71
+
72
+ before { allow(success).to receive(:call).and_return(true) }
73
+
74
+ it 'should still update state' do
75
+ expect(subject.stateholder.state).to eq from
76
+ subject.transition(to: to, success: success)
77
+ expect(subject.stateholder.state).to eq to
78
+ end
79
+
80
+ it 'should still return true' do
81
+ expect(subject.transition(to: to, success: success)).to be true
82
+ end
83
+
84
+ it 'should call the success policy' do
85
+ expect(success).to receive(:call).and_return(true)
86
+ subject.transition(to: to, success: success)
87
+ end
88
+
89
+ it 'should call the success policy with transition' do
90
+ expect(success).to receive(:call).with(transition).and_return(true)
91
+ subject.transition(to: to, success: success)
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'invalid transition' do
97
+ let(:from) { :initial_state }
98
+ let(:to) { :third_state }
99
+
100
+ before { subject.stateholder.state = from }
101
+
102
+ it 'should not update state' do
103
+ expect(subject.stateholder.state).to eq from
104
+ subject.transition(to: to)
105
+ expect(subject.stateholder.state).to eq from
106
+ end
107
+
108
+ it 'should return false' do
109
+ expect(subject.transition(to: to)).to be false
110
+ end
111
+
112
+ context 'with failure policy' do
113
+ let(:failure) { double }
114
+
115
+ before { allow(failure).to receive(:call).and_return(true) }
116
+
117
+ it 'should still not update state' do
118
+ expect(subject.stateholder.state).to eq from
119
+ subject.transition(to: to, failure: failure)
120
+ expect(subject.stateholder.state).to eq from
121
+ end
122
+
123
+ it 'should still return false' do
124
+ expect(subject.transition(to: to, failure: failure)).to be false
125
+ end
126
+
127
+ it 'should call the failure policy' do
128
+ expect(failure).to receive(:call).and_return(true)
129
+ subject.transition(to: to, failure: failure)
130
+ end
131
+
132
+ it 'should call the failure policy with transition' do
133
+ expect(failure).to receive(:call).with(transition).and_return(true)
134
+ subject.transition(to: to, failure: failure)
135
+ end
136
+
137
+ context 'when policy is to raise an exception' do
138
+ before { expect(failure).to receive(:call).and_raise(Exception) }
139
+
140
+ it 'should raise an exception' do
141
+ expect { subject.transition(to: to, failure: failure) }.to raise_error Exception
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '#states' do
149
+ it 'should respond to states' do
150
+ expect(subject).to respond_to :states
151
+ end
152
+
153
+ it 'should extract states from transitions' do
154
+ expect(subject.states.sort).to eq [
155
+ :initial_state,
156
+ :second_state,
157
+ :third_state
158
+ ].sort
159
+ end
160
+ end
161
+
162
+ describe '#transitions' do
163
+ it 'should respond to' do
164
+ expect(subject).to respond_to :transitions
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+ require 'support/test_classes'
3
+
4
+ describe Mutator::Transition do
5
+ subject { Mutator::Transition.new(to: to, from: from, machine: machine) }
6
+ let(:to) { :initial_state }
7
+ let(:from) { :second_state }
8
+ let(:machine) { Mutator::Stateholder.new(stateholder) }
9
+ let(:stateholder) { Stateholder.new }
10
+
11
+ describe '#initialize' do
12
+ it 'should not error' do
13
+ expect { subject }.to_not raise_error
14
+ end
15
+
16
+ context 'arguments' do
17
+ [:to, :from, :machine].each do |attr|
18
+ it "should require you to pass #{attr}" do
19
+ args = { to: :something, from: :something, machine: :something }
20
+ args.delete attr
21
+ expect { subject.class.new(args) }.to raise_error ArgumentError, "must provide #{attr}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ [:to, :from, :machine].each do |attr|
28
+ describe "##{attr}" do
29
+ it 'should be set to what it was passed' do
30
+ expect(subject.public_send(attr)).to eq public_send(attr)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#call' do
36
+ context 'transition is valid' do
37
+ let(:to) { :second_state }
38
+ let(:from) { :initial_state }
39
+
40
+ it 'should return the new state' do
41
+ expect(subject.call).to eq :second_state
42
+ end
43
+ end
44
+
45
+ context 'transition is invalid' do
46
+ let(:to) { :third_state }
47
+ let(:from) { :initial_state }
48
+
49
+ it 'should return the new state' do
50
+ expect(subject.call).to be nil
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#valid?' do
56
+ context 'valid transition' do
57
+ let(:to) { :second_state }
58
+ let(:from) { :initial_state }
59
+
60
+ it 'should be true' do
61
+ expect(subject).to be_valid
62
+ end
63
+ end
64
+
65
+ context 'invalid transition' do
66
+ let(:to) { :third_state }
67
+ let(:from) { :initial_state }
68
+
69
+ it 'should be false' do
70
+ expect(subject).to_not be_valid
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#stateholder' do
76
+ it 'should return the machine stateholder' do
77
+ expect(subject.stateholder).to eq machine.stateholder
78
+ end
79
+ end
80
+
81
+ shared_examples 'equal' do |method|
82
+ it 'should consider itself equal to another transition that is the same' do
83
+ transition1 = subject.class.new(to: to, from: from, machine: machine)
84
+ transition2 = subject.class.new(to: to, from: from, machine: machine)
85
+
86
+ expect(transition1.public_send(method, transition2)).to be true
87
+ end
88
+ end
89
+
90
+ describe '#==' do
91
+ it_should_behave_like 'equal', :==
92
+ end
93
+
94
+ describe '#eql?' do
95
+ it_should_behave_like 'equal', :eql?
96
+ end
97
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require 'coveralls'
2
2
  Coveralls.wear!
3
+
4
+ require 'mutator'
@@ -0,0 +1,23 @@
1
+ module Mutator
2
+ class Stateholder < Machine
3
+ def self.transitions
4
+ [
5
+ { from: [:initial_state], to: :second_state },
6
+ { from: [:second_state], to: :third_state }
7
+ ]
8
+ end
9
+ end
10
+ end
11
+
12
+ class Stateholder
13
+ include Mutator::Helpers
14
+
15
+ attr_writer :state
16
+
17
+ def state
18
+ @state ||= :initial_state
19
+ end
20
+
21
+ def self.where(*)
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-11 00:00:00.000000000 Z
11
+ date: 2014-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: awesome_print
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  description: Yet another state machine gem. I didn't find one I liked, so I made one.
70
98
  I probably didn't look hard enough.
71
99
  email:
@@ -75,6 +103,7 @@ extensions: []
75
103
  extra_rdoc_files: []
76
104
  files:
77
105
  - ".gitignore"
106
+ - ".hound.yml"
78
107
  - ".rspec"
79
108
  - ".travis.yml"
80
109
  - Gemfile
@@ -87,7 +116,11 @@ files:
87
116
  - lib/mutator/transition.rb
88
117
  - lib/mutator/version.rb
89
118
  - mutator.gemspec
119
+ - spec/lib/mutator/helpers_spec.rb
120
+ - spec/lib/mutator/machine_spec.rb
121
+ - spec/lib/mutator/transition_spec.rb
90
122
  - spec/spec_helper.rb
123
+ - spec/support/test_classes.rb
91
124
  homepage: https://github.com/ericroberts/mutator
92
125
  licenses:
93
126
  - MIT
@@ -113,4 +146,8 @@ signing_key:
113
146
  specification_version: 4
114
147
  summary: Mutator is just another state machine gem.
115
148
  test_files:
149
+ - spec/lib/mutator/helpers_spec.rb
150
+ - spec/lib/mutator/machine_spec.rb
151
+ - spec/lib/mutator/transition_spec.rb
116
152
  - spec/spec_helper.rb
153
+ - spec/support/test_classes.rb