Skip to content
Browse files

Simplify availability / class matching implementation for integrations

  • Loading branch information...
1 parent 25f6431 commit f95d15f64af57cf5904bf8da291e94cb682e052d @obrie obrie committed Feb 15, 2012
View
14 lib/state_machine/integrations.rb
@@ -73,7 +73,19 @@ module Integrations
# StateMachine::Integrations.match(MongoMapperVehicle) # => StateMachine::Integrations::MongoMapper
# StateMachine::Integrations.match(SequelVehicle) # => StateMachine::Integrations::Sequel
def self.match(klass)
- all.detect {|integration| integration.available? && integration.matches?(klass)}
+ all.detect {|integration| integration.matches?(klass)}
+ end
+
+ # Attempts to find an integration that matches the given list of ancestors.
+ # This will look through all of the built-in integrations under the StateMachine::Integrations
+ # namespace and find one that successfully matches one of the ancestors.
+ #
+ # == Examples
+ #
+ # StateMachine::Integrations.match([]) # => nil
+ # StateMachine::Integrations.match(['ActiveRecord::Base') # => StateMachine::Integrations::ActiveModel
+ def self.match_ancestors(ancestors)
+ all.detect {|integration| integration.matches_ancestors?(ancestors)}
end
# Finds an integration with the given name. If the integration cannot be
View
11 lib/state_machine/integrations/active_model.rb
@@ -366,17 +366,10 @@ def self.included(base) #:nodoc:
@defaults = {}
- # Whether this integration is available. Only true if ActiveModel is
- # defined.
- def self.available?
- defined?(::ActiveModel)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that include ActiveModel::Observing or ActiveModel::Validations
# will automatically use the ActiveModel integration.
- def self.matches?(klass)
- %w(Observing Validations).any? {|feature| ::ActiveModel.const_defined?(feature) && klass <= ::ActiveModel.const_get(feature)}
+ def self.matching_ancestors
+ %w(ActiveModel ActiveModel::Observing ActiveModel::Validations)
end
# Adds a validation error to the given object
View
11 lib/state_machine/integrations/active_record.rb
@@ -407,17 +407,10 @@ module ActiveRecord
# The default options to use for state machines using this integration
@defaults = {:action => :save}
- # Whether this integration is available. Only true if ActiveRecord::Base
- # is defined.
- def self.available?
- defined?(::ActiveRecord::Base)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that inherit from ActiveRecord::Base will automatically use
# the ActiveRecord integration.
- def self.matches?(klass)
- klass <= ::ActiveRecord::Base
+ def self.matching_ancestors
+ %w(ActiveRecord::Base)
end
def self.extended(base) #:nodoc:
View
21 lib/state_machine/integrations/base.rb
@@ -18,16 +18,25 @@ def integration_name
end
# Whether this integration is available for the current library. This
- # is usually only true if the ORM that the integration is for is
- # currently defined. Default is false.
+ # is only true if the ORM that the integration is for is currently
+ # defined.
def available?
- false
+ matching_ancestors.any? && Object.const_defined?(matching_ancestors[0].split('::')[0])
end
- # Whether the integration should be used for the given class. Default
- # is false.
+ # The list of ancestor names that cause this integration to matched.
+ def matching_ancestors
+ []
+ end
+
+ # Whether the integration should be used for the given class.
def matches?(klass)
- false
+ matches_ancestors?(klass.ancestors.map(&:name))
+ end
+
+ # Whether the integration should be used for the given list of ancestors.
+ def matches_ancestors?(ancestors)
+ (ancestors & matching_ancestors).any?
end
# Tracks the various version overrides for an integration
View
12 lib/state_machine/integrations/data_mapper.rb
@@ -308,20 +308,12 @@ module DataMapper
require 'state_machine/integrations/data_mapper/versions'
# The default options to use for state machines using this integration
- class << self; attr_reader :defaults; end
@defaults = {:action => :save, :use_transactions => false}
- # Whether this integration is available. Only true if DataMapper::Resource
- # is defined.
- def self.available?
- defined?(::DataMapper::Resource)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that include DataMapper::Resource will automatically use the
# DataMapper integration.
- def self.matches?(klass)
- klass <= ::DataMapper::Resource
+ def self.matching_ancestors
+ %w(DataMapper::Resource)
end
# Loads additional files specific to DataMapper
View
11 lib/state_machine/integrations/mongo_mapper.rb
@@ -291,17 +291,10 @@ module MongoMapper
# The default options to use for state machines using this integration
@defaults = {:action => :save}
- # Whether this integration is available. Only true if MongoMapper::Document
- # is defined.
- def self.available?
- defined?(::MongoMapper::Document)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that include MongoMapper::Document will automatically use the
# MongoMapper integration.
- def self.matches?(klass)
- klass <= ::MongoMapper::Document
+ def self.matching_ancestors
+ %w(MongoMapper::Document)
end
protected
View
11 lib/state_machine/integrations/mongoid.rb
@@ -341,17 +341,10 @@ module Mongoid
# The default options to use for state machines using this integration
@defaults = {:action => :save}
- # Whether this integration is available. Only true if Mongoid::Document
- # is defined.
- def self.available?
- defined?(::Mongoid::Document)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that include Mongoid::Document will automatically use the
# Mongoid integration.
- def self.matches?(klass)
- klass <= ::Mongoid::Document
+ def self.matching_ancestors
+ %w(Mongoid::Document)
end
def self.extended(base) #:nodoc:
View
12 lib/state_machine/integrations/sequel.rb
@@ -271,20 +271,12 @@ module Sequel
require 'state_machine/integrations/sequel/versions'
# The default options to use for state machines using this integration
- class << self; attr_reader :defaults; end
@defaults = {:action => :save}
- # Whether this integration is available. Only true if Sequel::Model is
- # defined.
- def self.available?
- defined?(::Sequel::Model)
- end
-
- # Should this integration be used for state machines in the given class?
# Classes that include Sequel::Model will automatically use the Sequel
# integration.
- def self.matches?(klass)
- klass <= ::Sequel::Model
+ def self.matching_ancestors
+ %w(Sequel::Model)
end
# Forces the change in state to be recognized regardless of whether the
View
4 test/unit/integrations/base_test.rb
@@ -13,6 +13,10 @@ def test_should_not_be_available
assert !StateMachine::Integrations::Base.available?
end
+ def test_should_not_have_any_matching_ancestors
+ assert_equal [], StateMachine::Integrations::Base.matching_ancestors
+ end
+
def test_should_not_match_any_classes
assert !StateMachine::Integrations::Base.matches?(Class.new)
end
View
34 test/unit/integrations_test.rb
@@ -2,7 +2,10 @@
class IntegrationMatcherTest < Test::Unit::TestCase
def setup
- @klass = Class.new
+ superclass = Class.new
+ self.class.const_set('Vehicle', superclass)
+
+ @klass = Class.new(superclass)
end
def test_should_return_nil_if_no_match_found
@@ -13,20 +16,39 @@ def test_should_return_integration_class_if_match_found
integration = Module.new do
include StateMachine::Integrations::Base
- def self.available?
- true
+ def self.matching_ancestors
+ ['IntegrationMatcherTest::Vehicle']
end
+ end
+ StateMachine::Integrations.const_set('Custom', integration)
+
+ assert_equal integration, StateMachine::Integrations.match(@klass)
+ ensure
+ StateMachine::Integrations.send(:remove_const, 'Custom')
+ end
+
+ def test_should_return_nil_if_no_match_found_with_ancestors
+ assert_nil StateMachine::Integrations.match_ancestors(['IntegrationMatcherTest::Fake'])
+ end
+
+ def test_should_return_integration_class_if_match_found_with_ancestors
+ integration = Module.new do
+ include StateMachine::Integrations::Base
- def self.matches?(klass)
- true
+ def self.matching_ancestors
+ ['IntegrationMatcherTest::Vehicle']
end
end
StateMachine::Integrations.const_set('Custom', integration)
- assert_equal integration, StateMachine::Integrations.match(@klass)
+ assert_equal integration, StateMachine::Integrations.match_ancestors(['IntegrationMatcherTest::Fake', 'IntegrationMatcherTest::Vehicle'])
ensure
StateMachine::Integrations.send(:remove_const, 'Custom')
end
+
+ def teardown
+ self.class.send(:remove_const, 'Vehicle')
+ end
end
class IntegrationFinderTest < Test::Unit::TestCase
View
34 test/unit/machine_test.rb
@@ -511,61 +511,63 @@ def setup
integration = Module.new do
include StateMachine::Integrations::Base
- def self.available?
- true
- end
-
- def self.matches?(klass)
- true
+ def self.matching_ancestors
+ ['MachineWithCustomIntegrationTest::Vehicle']
end
end
StateMachine::Integrations.const_set('Custom', integration)
+
+ superclass = Class.new
+ self.class.const_set('Vehicle', superclass)
+
+ @klass = Class.new(superclass)
end
def test_should_be_extended_by_the_integration_if_explicit
- machine = StateMachine::Machine.new(Class.new, :integration => :custom)
+ machine = StateMachine::Machine.new(@klass, :integration => :custom)
assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def test_should_not_be_extended_by_the_integration_if_implicit_but_not_available
StateMachine::Integrations::Custom.class_eval do
- def self.available?
- false
+ def self.matching_ancestors
+ []
end
end
- machine = StateMachine::Machine.new(Class.new)
+ machine = StateMachine::Machine.new(@klass)
assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def test_should_not_be_extended_by_the_integration_if_implicit_but_not_matched
StateMachine::Integrations::Custom.class_eval do
- def self.matches?(klass)
- false
+ def self.matching_ancestors
+ []
end
end
- machine = StateMachine::Machine.new(Class.new)
+ machine = StateMachine::Machine.new(@klass)
assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def test_should_be_extended_by_the_integration_if_implicit_and_available_and_matches
- machine = StateMachine::Machine.new(Class.new)
+ machine = StateMachine::Machine.new(@klass)
assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def test_should_not_be_extended_by_the_integration_if_nil
- machine = StateMachine::Machine.new(Class.new, :integration => nil)
+ machine = StateMachine::Machine.new(@klass, :integration => nil)
assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def test_should_not_be_extended_by_the_integration_if_false
- machine = StateMachine::Machine.new(Class.new, :integration => false)
+ machine = StateMachine::Machine.new(@klass, :integration => false)
assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
end
def teardown
+ self.class.send(:remove_const, 'Vehicle')
StateMachine::Integrations.send(:remove_const, 'Custom')
end
end

0 comments on commit f95d15f

Please sign in to comment.
Something went wrong with that request. Please try again.