switcher 0.0.1.beta → 0.1.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.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .rvmrc
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in switcher.gemspec
4
4
  gemspec
5
+
6
+ gem "guard-rspec"
7
+
8
+ group "activerecord" do
9
+ gem "activerecord", "~> 3.0.0"
10
+ gem "sqlite3"
11
+ end
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec', :version => 2, :all_after_pass => true, :all_on_start => true,
2
+ :cli => "--colour --format documentation --profile" do
3
+ watch(%r{^lib/(.+)\.rb$})
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ end
data/README.md CHANGED
@@ -1,3 +1,17 @@
1
- TODO - write README
1
+ Not for production use
2
2
 
3
- See specs
3
+ Docs: See specs
4
+
5
+ ## TODO:
6
+
7
+ * 1.8 compat
8
+ * Write README
9
+ * Refactoring
10
+ * Events without state
11
+ * Ability to define validations, associations etc. in state (ability to call static methods from object)
12
+
13
+ ## Adapters TODO:
14
+
15
+ * ActiveModel
16
+ * Virtus
17
+ * Mongoid
@@ -0,0 +1,78 @@
1
+ module Switcher
2
+ module ActiveRecord
3
+
4
+ module Initializer
5
+ end
6
+
7
+ module ClassMethods
8
+ def switcher_pre_initialize(inst, spec)
9
+ inst.class_eval do
10
+ spec_name = spec.name
11
+
12
+ define_method(:"#{spec_name}_spec") { spec }
13
+ define_method(:"#{spec_name}_prev") { self.instance_variable_get(:"@#{spec_name}_statement").state_prev }
14
+
15
+ define_method(:"#{spec_name}") { self.instance_variable_get(:"@#{spec_name}_statement").state_current }
16
+
17
+ events = []
18
+
19
+ spec.states.each_pair do |state_name, state|
20
+ define_method(:"#{spec_name}_#{state_name}?") do
21
+ state_name == self.send(:"#{spec_name}")
22
+ end
23
+
24
+ events << state.event_names
25
+ end
26
+
27
+ events.flatten.each do |event_name|
28
+ define_method(:"can_#{event_name}?") do
29
+ self.class.class_variable_get(:@@__specs__).map { |spc|
30
+ spc.states[self.send(:"#{spc.name}")].event_names.include?(event_name)
31
+ }.include?(true)
32
+ end
33
+
34
+ define_method(:"#{event_name}!") do |*args|
35
+ switch_from(nil, event_name, *args)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.included(base)
44
+ base.extend Switcher::ClassMethods
45
+ base.extend Switcher::ActiveRecord::ClassMethods
46
+
47
+ base.class_eval do
48
+ after_initialize do
49
+ self.class.class_variable_get(:@@__specs__).each do |spec|
50
+ spec_name = spec.name
51
+ state_current = read_attribute(spec_name)
52
+ state_prev = (has_attribute?("#{spec_name}_prev") ? read_attribute("#{spec_name}_prev") : nil)
53
+
54
+ self.instance_variable_set(:"@#{spec_name}_statement", Statement.new(self, spec, state_current, state_prev))
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def switch(event, *args)
61
+ switch_from(self.class, event, *args)
62
+ end
63
+
64
+ def switch_from(orig, event, *args)
65
+ self.class.class_variable_get(:@@__specs__).each do |spc|
66
+ spc_name = spc.name
67
+
68
+ self.instance_variable_get(:"@#{spc_name}_statement").publish(event, orig, args)
69
+
70
+ write_attribute(spc_name, self.send(:"#{spc_name}"))
71
+ if has_attribute?("#{spc_name}_prev")
72
+ write_attribute("#{spc_name}_prev", self.send(:"#{spc_name}_prev"))
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,65 @@
1
+ module Switcher
2
+ module Object
3
+ module Initializer
4
+ def new(*args, &block)
5
+ instance = allocate
6
+ instance.instance_eval { initialize(*args, &block) }
7
+ instance.class.class_variable_get(:@@__specs__).each do |spc| # TODO - move to something like Switcher.initial_statement(instance)
8
+ instance.instance_variable_set(:"@#{spc.name}_statement", Statement.new(instance, spc))
9
+ end
10
+ instance
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def switcher_pre_initialize(inst, spec)
16
+ inst.class_eval do
17
+ spec_name = spec.name
18
+
19
+ define_method(:"#{spec_name}_spec") { spec }
20
+ define_method(:"#{spec_name}_prev") { self.instance_variable_get(:"@#{spec_name}_statement").state_prev }
21
+
22
+ define_method(:"#{spec_name}") { self.instance_variable_get(:"@#{spec_name}_statement").state_current }
23
+
24
+ events = []
25
+
26
+ spec.states.each_pair do |state_name, state|
27
+ define_method(:"#{spec_name}_#{state_name}?") do
28
+ state_name == self.send(:"#{spec_name}")
29
+ end
30
+
31
+ events << state.event_names
32
+ end
33
+
34
+ events.flatten.each do |event_name|
35
+ define_method(:"can_#{event_name}?") do
36
+ self.class.class_variable_get(:@@__specs__).map { |spc|
37
+ spc.states[self.send(:"#{spc.name}")].event_names.include?(event_name)
38
+ }.include?(true)
39
+ end
40
+
41
+ define_method(:"#{event_name}!") do |*args|
42
+ switch(event_name, *args)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.included(base)
50
+ base.extend Switcher::ClassMethods
51
+ base.extend Switcher::Object::Initializer
52
+ base.extend Switcher::Object::ClassMethods
53
+ end
54
+
55
+ def switch(event, *args)
56
+ switch_from(self.class, event, *args)
57
+ end
58
+
59
+ def switch_from(orig, event, *args)
60
+ self.class.class_variable_get(:@@__specs__).each do |spc|
61
+ self.instance_variable_get(:"@#{spc.name}_statement").publish(event, orig, args)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,15 +1,18 @@
1
1
  module Switcher
2
2
  class Facade
3
- def initialize(data, target_state=nil)
3
+ def initialize(target, data)
4
4
  @args = data
5
5
  @stopped = false
6
- @target_state = target_state
6
+ @bubble_cancelled = false
7
+ @target_state = nil
8
+ @target = target
7
9
  end
8
10
 
9
- attr_reader :args, :stopped, :target_state
11
+ attr_reader :args, :stopped, :target, :target_state, :bubble_cancelled
10
12
 
11
13
  def stop
12
14
  @stopped = true
15
+ @bubble_cancelled = true
13
16
  end
14
17
 
15
18
  alias :restrict :stop
@@ -17,5 +20,9 @@ module Switcher
17
20
  def switch_to(state)
18
21
  @target_state = state.to_sym
19
22
  end
23
+
24
+ def cancel_bubble
25
+ @bubble_cancelled = true
26
+ end
20
27
  end
21
28
  end
data/lib/switcher/spec.rb CHANGED
@@ -7,10 +7,10 @@ module Switcher
7
7
  @name = name.to_sym
8
8
  @states = {}
9
9
  @states_list = []
10
- @state_prev = nil
10
+ @targets = []
11
11
  end
12
12
 
13
- attr_reader :name, :states, :state_prev
13
+ attr_reader :name, :states, :states_list, :targets
14
14
 
15
15
  def state(name, &block)
16
16
  listener = Listener.new(name)
@@ -20,26 +20,9 @@ module Switcher
20
20
  @states[name.to_sym] = listener
21
21
  end
22
22
 
23
- def current_state
24
- @current_state || @states_list.first
23
+ def notify(*list)
24
+ @targets = list
25
25
  end
26
26
 
27
- def publish(current_state, event, instance, args)
28
- facade = Facade.new(args)
29
- ["before_#{event}", event.to_s].each do |ev|
30
- @states[current_state.to_sym].trigger(ev, facade, instance, args)
31
- end
32
- set_state(facade)
33
- @states[current_state.to_sym].trigger("after_#{event}", facade, instance, args)
34
- end
35
-
36
- private
37
-
38
- def set_state(facade)
39
- unless facade.stopped && facade.target_state.nil?
40
- @state_prev = @current_state
41
- @current_state = facade.target_state.to_sym
42
- end
43
- end
44
27
  end
45
28
  end
@@ -0,0 +1,64 @@
1
+ module Switcher
2
+ class Statement
3
+ def initialize(instance, spec, state_current=nil, state_prev=nil)
4
+ @instance = instance
5
+
6
+ @spec = spec
7
+
8
+ @state_prev = state_prev
9
+ @state_current = state_current
10
+ end
11
+
12
+ attr_reader :name, :states
13
+
14
+ def state_current
15
+ (@state_current || @spec.states_list.first).to_sym
16
+ end
17
+
18
+ def state_prev
19
+ @state_prev ? @state_prev.to_sym : nil
20
+ end
21
+
22
+ def publish(event, original, args)
23
+ states = @spec.states
24
+ state = state_current
25
+
26
+ return unless states.has_key?(state)
27
+
28
+ facade = Facade.new(original, args)
29
+
30
+ ["before_#{event}", event.to_s].each do |ev|
31
+ states[state].trigger(ev, facade, @instance, args)
32
+ end
33
+
34
+ set_state(facade)
35
+
36
+ states[state].trigger("after_#{event}", facade, @instance, args)
37
+
38
+ return if facade.bubble_cancelled
39
+
40
+ if @spec.targets.length > 0
41
+ @spec.targets.each do |target|
42
+ target_instance = @instance.send(target.to_sym)
43
+ if target_instance.respond_to?(:each)
44
+ target_instance.each do |ti|
45
+ ti.switch_from(original, event, args) if ti.respond_to?(:switch_from)
46
+ end
47
+ else
48
+ target_instance.switch_from(original, event, args) if target_instance.respond_to?(:switch_from)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def set_state(facade)
57
+ unless facade.stopped || facade.target_state.nil?
58
+ @state_prev = state_current
59
+ @state_current = facade.target_state.to_sym
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module Switcher
2
- VERSION = "0.0.1.beta"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/switcher.rb CHANGED
@@ -1,7 +1,20 @@
1
1
  require "switcher/version"
2
+ require 'switcher/spec'
3
+ require 'switcher/statement'
4
+ require 'switcher/adapters/object'
5
+ require 'switcher/adapters/active_record'
2
6
 
3
7
  module Switcher
4
- # Your code goes here...
5
- end
8
+ module ClassMethods
9
+ def switcher(name, options={}, &block)
10
+ self.class_variable_defined?(:@@__specs__) or self.class_variable_set(:@@__specs__, [])
6
11
 
7
- require 'switcher/machine'
12
+ spec = Spec.new(name, options)
13
+ spec.instance_eval(&block)
14
+
15
+ self.class_variable_get(:@@__specs__) << spec
16
+
17
+ switcher_pre_initialize(self, spec)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ class Airbag
2
+ include Switcher::Object
3
+
4
+ def initialize
5
+ @crashed_from = nil
6
+ end
7
+
8
+ attr_reader :crashed_from
9
+
10
+ switcher :state do
11
+ state :idle do
12
+ on :crash, switch_to: :deployed do |ev|
13
+ @crashed_from = ev.target
14
+ end
15
+ end
16
+
17
+ state :deployed
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_record'
2
+
3
+ class Box < ActiveRecord::Base
4
+ include Switcher::ActiveRecord
5
+
6
+ switcher :state do
7
+ state :requested do
8
+ on :produce, switch_to: :produced
9
+ end
10
+
11
+ state :produced do
12
+ on :break, switch_to: :broken
13
+ end
14
+
15
+ state :broken
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ class Car
2
+ include Switcher::Object
3
+
4
+ attr_accessor :airbag, :airbags
5
+
6
+ switcher :state do
7
+ notify :airbag, :airbags
8
+
9
+ state :new do
10
+ on :buy, switch_to: :buyed
11
+ end
12
+
13
+ state :buyed do
14
+ on :start, switch_to: :used
15
+ end
16
+
17
+ state :used do
18
+ on :crash, switch_to: :damaged do |ev, fast=true|
19
+ ev.cancel_bubble unless fast
20
+ end
21
+ end
22
+
23
+ state :damaged do
24
+ on :repair, switch_to: :used
25
+ end
26
+ end
27
+
28
+ switcher :movement do
29
+ state :stands do
30
+ on :start, switch_to: :moves
31
+ end
32
+
33
+ state :moves do
34
+ on :stop, switch_to: :stands
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  class Human
2
- include Switcher::Machine
2
+ include Switcher::Object
3
3
 
4
4
  def initialize
5
5
  @easy_to_fight = false
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+ require 'fixtures/box'
4
+ require 'fileutils'
5
+
6
+ describe Switcher::ActiveRecord do
7
+ before :all do
8
+ FileUtils.rm("test.sqlite3") if File.exists?("test.sqlite3")
9
+
10
+ ActiveRecord::Migration.verbose = false
11
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "test.sqlite3")
12
+
13
+ ActiveRecord::Schema.define do
14
+ create_table :boxes do |t|
15
+ t.string :type
16
+ t.string :state
17
+ t.string :state_prev
18
+ end
19
+ end
20
+ end
21
+
22
+ after :all do
23
+ FileUtils.rm("test.sqlite3")
24
+ end
25
+
26
+ let(:box) do
27
+ Box.new
28
+ end
29
+
30
+ it "should have initial state" do
31
+ box.state.should eq(:requested)
32
+ end
33
+
34
+ it "should switch states" do
35
+ box.produce!
36
+
37
+ box.state.should eq(:produced)
38
+ end
39
+
40
+ it "should save states" do
41
+ box.produce!
42
+ box.save
43
+
44
+ box.reload
45
+
46
+ box.state.should eq(:produced)
47
+ end
48
+
49
+ it "should save previous states if possible" do
50
+ box.produce!
51
+ box.save
52
+
53
+ box.reload
54
+
55
+ box.state_prev.should eq(:requested)
56
+ end
57
+
58
+ it "should save last defined state" do
59
+ box.produce!
60
+ box.break!
61
+ box.save
62
+
63
+ box.reload
64
+
65
+ box.state.should eq(:broken)
66
+ end
67
+
68
+ it "can detect possibility to switch" do
69
+ box.can_produce?.should be_true
70
+ box.can_break?.should be_false
71
+ end
72
+
73
+ it "should have state predicate" do
74
+ box.state_requested?.should be_true
75
+ box.state_produced?.should be_false
76
+ end
77
+ end
@@ -1,54 +1,158 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  require 'fixtures/human'
4
+ require 'fixtures/car'
5
+ require 'fixtures/airbag'
4
6
 
5
7
  describe Switcher do
6
8
 
7
9
  describe "Basic functionality" do
8
- people = Human.new
10
+ person = Human.new
11
+
12
+ it "should have initial state" do
13
+ person.state.should eq(:newborn)
14
+ end
9
15
 
10
16
  it "should switch to state with option" do
11
- people.go_to_school!
12
- people.state.should eq(:scholar)
17
+ person.go_to_school!
18
+
19
+ person.state.should eq(:scholar)
13
20
  end
14
21
 
15
22
  it "should switch to state by internal condition" do
16
- people.finish_school!(2)
17
- people.state.should eq(:worker)
23
+ person.finish_school!(2)
24
+
25
+ person.state.should eq(:worker)
18
26
  end
19
27
 
20
28
  it "should have before and after callbacks" do
21
- people.full_age!(100)
22
- people.fight!(true)
29
+ person.full_age!(100)
30
+ person.fight!(true)
23
31
 
24
- people.state.should eq(:civil)
25
- people.easy_to_fight.should be_true
26
- people.honor.should eq(100)
32
+ person.state.should eq(:civil)
33
+ person.easy_to_fight.should be_true
34
+ person.honor.should eq(100)
27
35
  end
28
36
 
29
37
  it "can prevent switch" do
30
- people.find_job!(false)
31
- people.state.should eq(:civil)
38
+ person.find_job!(false)
39
+
40
+ person.state.should eq(:civil)
32
41
  end
33
42
 
34
43
  it "and can not" do
35
- people.find_job!(true)
36
- people.state.should eq(:manager)
44
+ person.switch("find_job", true)
45
+
46
+ person.state.should eq(:manager)
37
47
  end
38
48
 
39
49
  it "can detect possibility to switch" do
40
- people.can_fight?.should be_false
41
- people.can_die?.should be_true
50
+ person.can_fight?.should be_false
51
+ person.can_die?.should be_true
42
52
  end
43
53
 
44
54
  it "should remember previous state" do
45
- people.state_prev.should eq(:civil)
55
+ person.state_prev.should eq(:civil)
46
56
  end
47
57
 
48
58
  it "should have state predicate" do
49
- people.manager?.should be_true
50
- people.civil?.should be_false
59
+ person.state_manager?.should be_true
60
+ person.state_civil?.should be_false
61
+ end
62
+ end
63
+
64
+ describe "Multiple states" do
65
+ car = Car.new
66
+
67
+ it "should have different states" do
68
+ car.state.should eq(:new)
69
+ car.movement.should eq(:stands)
70
+ end
71
+
72
+ it "should switch states" do
73
+ car.buy!
74
+
75
+ car.state.should eq(:buyed)
76
+ car.movement.should eq(:stands)
77
+ end
78
+
79
+ it "should have cross-stated events" do
80
+ car.start!
81
+
82
+ car.state.should eq(:used)
83
+ car.movement.should eq(:moves)
84
+ end
85
+
86
+ it "should remember previous states" do
87
+ car.state_prev.should eq(:buyed)
88
+ car.movement_prev.should eq(:stands)
89
+ end
90
+
91
+ it "should have state predicates" do
92
+ car.state_used?.should be_true
93
+ car.state_new?.should be_false
94
+
95
+ car.movement_moves?.should be_true
96
+ car.movement_stands?.should be_false
51
97
  end
52
98
  end
53
99
 
100
+ describe "Multiple instances" do
101
+ car_one = Car.new
102
+ car_two = Car.new
103
+
104
+ it "should work independent" do
105
+ car_one.buy!
106
+
107
+ car_two.state.should eq(:new)
108
+ end
109
+ end
110
+
111
+ describe "Event bubbling" do
112
+ it "should bubble event" do
113
+ car = Car.new
114
+ car.airbag = Airbag.new
115
+
116
+ car.buy!
117
+ car.start!
118
+ car.crash!
119
+
120
+ car.airbag.state.should eq(:deployed)
121
+ end
122
+
123
+ it "should bubble event to collections" do
124
+ car = Car.new
125
+ car.airbags = [Airbag.new, Airbag.new]
126
+
127
+ car.buy!
128
+ car.start!
129
+ car.crash!
130
+
131
+ car.airbags.each do |ab|
132
+ ab.state.should eq(:deployed)
133
+ end
134
+ end
135
+
136
+ it "should define original target" do
137
+ car = Car.new
138
+ car.airbag = Airbag.new
139
+
140
+ car.buy!
141
+ car.start!
142
+ car.crash!
143
+
144
+ car.airbag.crashed_from.to_s.should eq("Car")
145
+ end
146
+
147
+ it "should cancel bubble" do
148
+ car = Car.new
149
+ car.airbag = Airbag.new
150
+
151
+ car.buy!
152
+ car.start!
153
+ car.crash!(false)
154
+
155
+ car.airbag.state.should eq(:idle)
156
+ end
157
+ end
54
158
  end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta
5
- prerelease: 6
4
+ version: 0.1.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andrey Savchenko
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-28 00:00:00.000000000Z
12
+ date: 2012-03-04 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70269386935900 !ruby/object:Gem::Requirement
16
+ requirement: &70251275731280 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70269386935900
24
+ version_requirements: *70251275731280
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70269386935320 !ruby/object:Gem::Requirement
27
+ requirement: &70251275730860 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70269386935320
35
+ version_requirements: *70251275730860
36
36
  description: Switcher is simple, event-driven state machine
37
37
  email:
38
38
  - andrey@aejis.eu
@@ -42,16 +42,23 @@ extra_rdoc_files: []
42
42
  files:
43
43
  - .gitignore
44
44
  - Gemfile
45
+ - Guardfile
45
46
  - README.md
46
47
  - Rakefile
47
48
  - lib/switcher.rb
49
+ - lib/switcher/adapters/active_record.rb
50
+ - lib/switcher/adapters/object.rb
48
51
  - lib/switcher/facade.rb
49
52
  - lib/switcher/listener.rb
50
- - lib/switcher/machine.rb
51
53
  - lib/switcher/spec.rb
54
+ - lib/switcher/statement.rb
52
55
  - lib/switcher/version.rb
56
+ - spec/fixtures/airbag.rb
57
+ - spec/fixtures/box.rb
58
+ - spec/fixtures/car.rb
53
59
  - spec/fixtures/human.rb
54
60
  - spec/spec_helper.rb
61
+ - spec/switcher_active_record_spec.rb
55
62
  - spec/switcher_spec.rb
56
63
  - switcher.gemspec
57
64
  homepage: https://github.com/Ptico/switcher
@@ -69,9 +76,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
76
  required_rubygems_version: !ruby/object:Gem::Requirement
70
77
  none: false
71
78
  requirements:
72
- - - ! '>'
79
+ - - ! '>='
73
80
  - !ruby/object:Gem::Version
74
- version: 1.3.1
81
+ version: '0'
75
82
  requirements: []
76
83
  rubyforge_project: switcher
77
84
  rubygems_version: 1.8.6
@@ -79,6 +86,10 @@ signing_key:
79
86
  specification_version: 3
80
87
  summary: Switcher is simple, event-driven state machine
81
88
  test_files:
89
+ - spec/fixtures/airbag.rb
90
+ - spec/fixtures/box.rb
91
+ - spec/fixtures/car.rb
82
92
  - spec/fixtures/human.rb
83
93
  - spec/spec_helper.rb
94
+ - spec/switcher_active_record_spec.rb
84
95
  - spec/switcher_spec.rb
@@ -1,43 +0,0 @@
1
- require 'switcher/spec'
2
-
3
- module Switcher
4
- module Machine
5
-
6
- module ClassMethods
7
- def switcher(name, options={}, &block)
8
- self.class_variable_defined?(:@@__specs__) or self.class_variable_set(:@@__specs__, [])
9
-
10
- spec = Spec.new(name, options)
11
- spec.instance_eval(&block)
12
-
13
- self.class_variable_get(:@@__specs__) << spec # dup and destroy?
14
-
15
- self.class_eval do
16
- define_method(:"#{spec.name}_spec") { spec }
17
- define_method(:"#{spec.name}_prev") { spec.state_prev }
18
-
19
- define_method(:"#{spec.name}") { spec.current_state }
20
-
21
- events = []
22
-
23
- spec.states.each_pair do |state_name, state|
24
- define_method(:"#{state_name}?") { state_name == self.send(:"#{spec.name}") }
25
-
26
- events << state.event_names
27
- end
28
-
29
- events.flatten.each do |event_name|
30
- define_method(:"can_#{event_name}?") { spec.states[self.send(:"#{spec.name}")].event_names.include?(event_name) }
31
- define_method(:"#{event_name}!") do |*args|
32
- spec.publish(self.send(:"#{spec.name}"), event_name, self, args)
33
- end
34
- end
35
- end
36
- end
37
- end
38
-
39
- def self.included(base)
40
- base.extend ClassMethods
41
- end
42
- end
43
- end