omg-statelogic 1.0.2 → 1.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/CHANGELOG CHANGED
@@ -1,2 +1,8 @@
1
- 0.1.2 - 2008-01-10
1
+ 1.1 - 2009-08-11
2
+ - adds finder methods in the form of find_all_#{state}(*args)
3
+ - adds named scope named after corresponding state
4
+ - no longer redefines existing methods with the same names, issues warnings instead
5
+ - forces state names to underscore notation when used as part of method/scope names
6
+
7
+ 0.1.2 - 2009-01-10
2
8
  - Support scoping arbitrary callbacks beyond ActiveRecord's
data/README.rdoc CHANGED
@@ -12,6 +12,13 @@ consistency over merely formal... whatever...
12
12
  - ???????
13
13
  - PROFIT!!!11
14
14
 
15
+ === Changes in v1.1
16
+ _Please review these carefully as they may be incompatible with your existing code._
17
+ - adds finder methods in the form of +find_all_#{state}(*args)+ (Order.find_all_ready) sugg. by ares
18
+ - adds named scope named after corresponding state (Order.paid) sugg. by ares
19
+ - no longer redefines existing methods with the same names, issues warnings instead
20
+ - forces state names to underscore notation when used as part of method names
21
+
15
22
  === Installation
16
23
  gem install omg-statelogic --source http://gems.github.com
17
24
 
@@ -32,7 +39,7 @@ Please report via Github issue tracking.
32
39
  initial_state 'unpaid' do
33
40
  transitions_to 'ready', 'suspended' # won't let you change to wrong states
34
41
  end
35
- state 'ready' do # you get +ready?+, +was_ready?+
42
+ state 'ready' do # you get +ready?+, +was_ready?+, +Order.ready+ named scope and +Order.find_all_ready+ finder
36
43
  transitions_to 'redeemed', 'suspended'
37
44
  validates_presence_of :txref # scoped validations
38
45
  before_save :prepare_for_plucking # scoped callbacks
@@ -1,6 +1,27 @@
1
- require 'statelogic/callbacks_ext'
1
+ require 'statelogic/callbacks_ext' unless ([ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR] <=> [2, 3]) >= 0
2
2
 
3
3
  module Statelogic
4
+ module Util
5
+ def self.debug(msg = nil, &block)
6
+ ::ActiveRecord::Base.logger.debug(msg, &block) if ::ActiveRecord::Base.logger
7
+ end
8
+
9
+ def self.warn(msg = nil, &block)
10
+ ::ActiveRecord::Base.logger.warn(msg, &block) if ::ActiveRecord::Base.logger
11
+ end
12
+
13
+ def self.defmethod(cls, name, meta = false, &block)
14
+ c = meta ? cls.metaclass : cls
15
+ unless c.method_defined?(name)
16
+ c.send(:define_method, name, &block)
17
+ Util.debug { "Statelogic created #{meta ? 'class' : 'instance'} method #{name} on #{cls.name}." }
18
+ else
19
+ warn { "Statelogic won't override #{meta ? 'class' : 'instance'} method #{name} already defined on #{cls.name}." }
20
+ nil
21
+ end
22
+ end
23
+ end
24
+
4
25
  module ActiveRecord
5
26
  def self.included(other)
6
27
  other.extend(ClassMethods)
@@ -51,14 +72,25 @@ module Statelogic
51
72
  alias initial initial_state
52
73
 
53
74
  def state(name, options = {}, &block)
75
+ name = name.to_s
76
+ uname = name.underscore
54
77
  attr = @config[:attribute]
55
78
  attr_was = :"#{attr}_was"
56
- @class.class_eval do
57
- define_method("#{name}?") { send(attr) == name }
58
- define_method("was_#{name}?") { send(attr_was) == name }
79
+ find_all_by_attr = "find_all_by_#{attr}"
80
+
81
+ Util.defmethod(@class, "#{uname}?") { send(attr) == name }
82
+ Util.defmethod(@class, "was_#{uname}?") { send(attr_was) == name }
83
+
84
+ unless @class.respond_to?(name)
85
+ @class.send(:named_scope, uname, :conditions => {attr.to_sym => name })
86
+ Util.debug { "Statelogic has defined named scope #{uname} on #{@class.name}." }
87
+ else
88
+ Util.warn { "Statelogic won't override class method #{uname} already defined on #{@class.name}." }
59
89
  end
60
90
 
61
- StateScopeHelper.new(@class, name, @config).instance_eval(&block)
91
+ Util.defmethod(@class, "find_all_#{uname}", true) {|*args| send(find_all_by_attr, name, *args) }
92
+
93
+ StateScopeHelper.new(@class, name, @config).instance_eval(&block) if block_given?
62
94
 
63
95
  @config[:states] << name
64
96
  @config[:initial] << name if options[:initial]
@@ -73,7 +105,7 @@ module Statelogic
73
105
 
74
106
  ConfigHelper.new(self, options).instance_eval(&block)
75
107
 
76
- initial = [options[:initial], options[:states]].find {|x| !x.blank? }
108
+ initial = [options[:initial], options[:states]].find(&:present?)
77
109
  validates_inclusion_of attr, :in => initial, :on => :create if initial
78
110
 
79
111
  const = attr.to_s.pluralize.upcase
@@ -83,7 +115,5 @@ module Statelogic
83
115
  end
84
116
  end
85
117
 
86
- # :stopdoc:
87
- class ActiveRecord::Base
88
- include Statelogic::ActiveRecord
89
- end
118
+ ActiveRecord::Base.send :include, Statelogic::ActiveRecord
119
+
@@ -1,7 +1,7 @@
1
1
  class Test::Unit::TestCase
2
2
  def self.should_not_require_attributes(*attributes)
3
3
  get_options!(attributes)
4
- klass = model_class
4
+ klass = described_type
5
5
 
6
6
  attributes.each do |attribute|
7
7
  should "not require #{attribute} to be set" do
@@ -9,4 +9,5 @@ class Test::Unit::TestCase
9
9
  end
10
10
  end
11
11
  end
12
- end
12
+ end
13
+
@@ -1,39 +1,32 @@
1
1
  require 'test_helper'
2
2
 
3
- class Order < ActiveRecord::Base
4
- statelogic do
5
- initial_state 'unpaid' do
6
- transitions_to 'ready', 'suspended'
7
- end
8
- state 'ready' do
9
- transitions_to 'redeemed', 'suspended'
10
- validates_presence_of :txref
11
- end
12
- state 'redeemed' do
13
- transitions_to 'suspended'
14
- validates_presence_of :txref, :redeemed_at, :facility_id
15
- end
16
- state 'suspended' do
17
- transitions_to 'unpaid', 'ready', 'redeemed'
18
- validate do |order|
19
- order.errors.add(:txref, :invalid) if order.txref && order.txref !~ /\AREF/
20
- end
21
- end
22
- end
23
- end
3
+ #ActiveRecord::Base.logger = Logger.new(STDERR)
24
4
 
25
5
  class OrderTest < ActiveSupport::TestCase
26
6
  include ActiveRecord::TestFixtures
27
7
  self.fixture_path = 'test/fixtures'
28
8
 
29
9
  fixtures :orders
10
+
11
+ should_have_class_methods :unpaid, :ready, :redeemed, :suspended
12
+ should_have_class_methods :find_all_unpaid, :find_all_ready, :find_all_redeemed, :find_all_suspended
30
13
 
14
+ should_have_instance_methods :unpaid?, :ready?, :redeemed?, :suspended?
15
+ should_have_instance_methods :was_unpaid?, :was_ready?, :was_redeemed?, :was_suspended?
16
+
17
+ context 'Finders and scopes' do
18
+ should 'return adequate shit' do
19
+ for st in %w(unpaid ready redeemed suspended)
20
+ assert_same_elements Order.find_all_by_state(st), Order.send(st)
21
+ assert_same_elements Order.find_all_by_state(st), Order.send("find_all_#{st}")
22
+ end
23
+ end
24
+ end
25
+
31
26
  should_validate_presence_of :state, :message => default_error_message(:inclusion)
32
27
 
33
28
  context 'A fresh order' do
34
- setup do
35
- @order = Order.new
36
- end
29
+ subject { Order.new }
37
30
 
38
31
  should_allow_values_for :state, 'unpaid'
39
32
  should_not_allow_values_for :state, 'ready', 'redeemed', 'suspended', 'screwed_up',
@@ -42,9 +35,7 @@ class OrderTest < ActiveSupport::TestCase
42
35
  end
43
36
 
44
37
  context 'An unpaid order' do
45
- setup do
46
- @order = orders(:unpaid)
47
- end
38
+ subject { orders(:unpaid) }
48
39
 
49
40
  should_allow_values_for :state, 'unpaid', 'ready', 'suspended'
50
41
  should_not_allow_values_for :state, 'redeemed', 'screwed_up',
@@ -53,9 +44,7 @@ class OrderTest < ActiveSupport::TestCase
53
44
  end
54
45
 
55
46
  context 'A ready order' do
56
- setup do
57
- @order = orders(:ready)
58
- end
47
+ subject { orders(:ready) }
59
48
 
60
49
  should_allow_values_for :state, 'ready', 'redeemed', 'suspended'
61
50
  should_not_allow_values_for :state, 'unpaid', 'screwed_up',
@@ -65,9 +54,7 @@ class OrderTest < ActiveSupport::TestCase
65
54
  end
66
55
 
67
56
  context 'A redeemed order' do
68
- setup do
69
- @order = orders(:redeemed)
70
- end
57
+ subject { orders(:redeemed) }
71
58
 
72
59
  should_allow_values_for :state, 'redeemed', 'suspended'
73
60
  should_not_allow_values_for :state, 'unpaid', 'ready', 'screwed_up',
@@ -76,9 +63,7 @@ class OrderTest < ActiveSupport::TestCase
76
63
  end
77
64
 
78
65
  context 'A suspended order' do
79
- setup do
80
- @order = orders(:suspended)
81
- end
66
+ subject { orders(:suspended) }
82
67
 
83
68
  should_allow_values_for :state, 'suspended', 'redeemed', 'ready', 'unpaid'
84
69
  should_not_allow_values_for :state, 'screwed_up', :message => default_error_message(:inclusion)
@@ -87,3 +72,4 @@ class OrderTest < ActiveSupport::TestCase
87
72
  should_not_require_attributes :txref, :redeemed_at, :facility_id
88
73
  end
89
74
  end
75
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omg-statelogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: "1.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Gunko
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-23 00:00:00 -07:00
12
+ date: 2009-08-11 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -64,7 +64,8 @@ files:
64
64
  - rails/init.rb
65
65
  has_rdoc: true
66
66
  homepage: http://github.com/omg/statelogic
67
- post_install_message:
67
+ licenses:
68
+ post_install_message: v1.1 introduces changes that may (or may not) be incompatible for you. Please review them at http://github.com/omg/statelogic
68
69
  rdoc_options:
69
70
  - --line-numbers
70
71
  - --main
@@ -86,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
87
  requirements: []
87
88
 
88
89
  rubyforge_project:
89
- rubygems_version: 1.2.0
90
+ rubygems_version: 1.3.5
90
91
  signing_key:
91
92
  specification_version: 2
92
93
  summary: Another state machine for ActiveRecord