Skip to content

Commit

Permalink
Sequel::Model.plugin can now be overridden just like the other Model …
Browse files Browse the repository at this point in the history
…methods

Before Model.plugin was special, since it was defined directly on
the class.  Now, it is defined in ClassMethods instead.  This will
allow plugins to alter the plugin method itself.  For example, you
could now have a plugin that changes the behavior of future
plugins.
  • Loading branch information
jeremyevans committed Feb 14, 2011
1 parent 1ca08b5 commit b143db8
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 55 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== HEAD

* Sequel::Model.plugin can now be overridden just like the other Model methods (jeremyevans)

* Add tinytds adapter, the best way to connect to MSSQL from a C based ruby running on *nix (jeremyevans)

* Recognize bigint unsigned as a Bignum type in the schema dumper (gamespy-tech) (#327)
Expand Down
50 changes: 50 additions & 0 deletions lib/sequel/model/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ module ClassMethods
# stored so when the dataset changes, methods defined with def_dataset_method
# will be applied to the new dataset.
attr_reader :dataset_methods
#
# Array of plugin modules loaded by this class
#
# Sequel::Model.plugins
# # => [Sequel::Model, Sequel::Model::Associations]
attr_reader :plugins

# The primary key for the class. Sequel can determine this automatically for
# many databases, but not all, so you may need to set it manually. If not
Expand Down Expand Up @@ -308,6 +314,28 @@ def no_primary_key
clear_setter_methods_cache
@simple_pk = @primary_key = nil
end

# Loads a plugin for use with the model class, passing optional arguments
# to the plugin. If the plugin is a module, load it directly. Otherwise,
# require the plugin from either sequel/plugins/#{plugin} or
# sequel_#{plugin}, and then attempt to load the module using a
# the camelized plugin name under Sequel::Plugins.
def plugin(plugin, *args, &blk)
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
unless @plugins.include?(m)
@plugins << m
m.apply(self, *args, &blk) if m.respond_to?(:apply)
include(m::InstanceMethods) if m.const_defined?("InstanceMethods")
extend(m::ClassMethods)if m.const_defined?("ClassMethods")
if m.const_defined?("DatasetMethods")
dataset.extend(m::DatasetMethods) if @dataset
dataset_method_modules << m::DatasetMethods
meths = m::DatasetMethods.public_instance_methods.reject{|x| NORMAL_METHOD_NAME_REGEXP !~ x.to_s}
def_dataset_method(*meths) unless meths.empty?
end
end
m.configure(self, *args, &blk) if m.respond_to?(:configure)
end

# Returns primary key attribute hash. If using a composite primary key
# value such be an array with values for each primary key in the correct
Expand Down Expand Up @@ -608,6 +636,27 @@ def overridable_methods_module
@overridable_methods_module
end

# Returns the module for the specified plugin. If the module is not
# defined, the corresponding plugin required.
def plugin_module(plugin)
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
if !Sequel::Plugins.const_defined?(module_name) ||
(Sequel.const_defined?(module_name) &&
Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
begin
Sequel.tsk_require "sequel/plugins/#{plugin}"
rescue LoadError => e
begin
Sequel.tsk_require "sequel_#{plugin}"
rescue LoadError => e2
e.message << "; #{e2.message}"
raise e
end
end
end
Sequel::Plugins.const_get(module_name)
end

# Find the row in the dataset that matches the primary key. Uses
# a static SQL optimization if the table and primary key are simple.
def primary_key_lookup(pk)
Expand Down Expand Up @@ -1444,6 +1493,7 @@ def to_hash(key_column=nil, value_column=nil)
end
end

extend ClassMethods
plugin self
end
end
55 changes: 0 additions & 55 deletions lib/sequel/model/plugins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,59 +21,4 @@ module Sequel
# any modules.
module Plugins
end

class Model
# Loads a plugin for use with the model class, passing optional arguments
# to the plugin. If the plugin is a module, load it directly. Otherwise,
# require the plugin from either sequel/plugins/#{plugin} or
# sequel_#{plugin}, and then attempt to load the module using a
# the camelized plugin name under Sequel::Plugins.
def self.plugin(plugin, *args, &blk)
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
unless @plugins.include?(m)
@plugins << m
m.apply(self, *args, &blk) if m.respond_to?(:apply)
include(m::InstanceMethods) if m.const_defined?("InstanceMethods")
extend(m::ClassMethods)if m.const_defined?("ClassMethods")
if m.const_defined?("DatasetMethods")
dataset.extend(m::DatasetMethods) if @dataset
dataset_method_modules << m::DatasetMethods
meths = m::DatasetMethods.public_instance_methods.reject{|x| NORMAL_METHOD_NAME_REGEXP !~ x.to_s}
def_dataset_method(*meths) unless meths.empty?
end
end
m.configure(self, *args, &blk) if m.respond_to?(:configure)
end

module ClassMethods
# Array of plugin modules loaded by this class
#
# Sequel::Model.plugins
# # => [Sequel::Model, Sequel::Model::Associations]
attr_reader :plugins

private

# Returns the module for the specified plugin. If the module is not
# defined, the corresponding plugin required.
def plugin_module(plugin)
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
if !Sequel::Plugins.const_defined?(module_name) ||
(Sequel.const_defined?(module_name) &&
Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
begin
Sequel.tsk_require "sequel/plugins/#{plugin}"
rescue LoadError => e
begin
Sequel.tsk_require "sequel_#{plugin}"
rescue LoadError => e2
e.message << "; #{e2.message}"
raise e
end
end
end
Sequel::Plugins.const_get(module_name)
end
end
end
end

0 comments on commit b143db8

Please sign in to comment.