module Sequel::Plugins
Empty namespace that plugins should use to store themselves, so they can be loaded via Model.plugin.
Plugins
should be modules with one of the following conditions:
-
A singleton method named apply, which takes a model, additional arguments, and an optional block. This is called the first time the plugin is loaded for this model (unless it was already loaded by an ancestor class), before including/extending any modules, with the arguments and block provided to the call to Model.plugin.
-
A module inside the plugin module named ClassMethods, which will extend the model class.
-
A module inside the plugin module named InstanceMethods, which will be included in the model class.
-
A module inside the plugin module named DatasetMethods, which will extend the model's dataset.
-
A singleton method named configure, which takes a model, additional arguments, and an optional block. This is called every time the Model.plugin method is called, after including/extending any modules.
Constants
- SEQUEL_METHOD_NAME
Return a unique method name symbol for the given suffix.
Public Class Methods
Add method to mod
that overrides set_dataset to call the method afterward.
# File lib/sequel/model/plugins.rb 46 def self.after_set_dataset(mod, meth) 47 mod.send(:define_method, :set_dataset) do |*a| 48 r = super(*a) 49 # Allow calling private class methods as methods this specifies are usually private 50 send(meth) 51 r 52 end 53 end
In the given module mod
, define methods that are call the same method on the dataset. This is designed for plugins to define dataset methods inside ClassMethods that call the implementations in DatasetMethods.
This should not be called with untrusted input or method names that can't be used literally, since it uses class_eval.
# File lib/sequel/model/plugins.rb 31 def self.def_dataset_methods(mod, meths) 32 Array(meths).each do |meth| 33 mod.class_eval("def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end", __FILE__, __LINE__) 34 end 35 end
Define a private instance method using the block with the provided name and expected arity. If the name is given as a Symbol
, it is used directly. If the name is given as a String
, a unique name will be generated using that string. The expected_arity should be either 0 (no arguments) or 1 (single argument).
If a block with an arity that does not match the expected arity is used, a deprecation warning will be issued. The method defined should still work, though it will be slower than a method with the expected arity.
Sequel
only checks arity for regular blocks, not lambdas. Lambdas were already strict in regards to arity, so there is no need to try to fix arity to keep backwards compatibility for lambdas.
Blocks with required keyword arguments are not supported by this method.
# File lib/sequel/model/plugins.rb 77 def self.def_sequel_method(model, meth, expected_arity, &block) 78 if meth.is_a?(String) 79 meth = SEQUEL_METHOD_NAME.call(meth) 80 end 81 call_meth = meth 82 83 unless block.lambda? 84 required_args, optional_args, rest, keyword = _define_sequel_method_arg_numbers(block) 85 86 if keyword == :required 87 raise Error, "cannot use block with required keyword arguments when calling define_sequel_method with expected arity #{expected_arity}" 88 end 89 90 case expected_arity 91 when 0 92 unless required_args == 0 93 # SEQUEL6: remove 94 Sequel::Deprecation.deprecate("Arity mismatch in block passed to define_sequel_method. Expected Arity 0, but arguments required for #{block.inspect}. Support for this will be removed in Sequel 6.") 95 b = block 96 block = lambda{instance_exec(&b)} # Fallback 97 end 98 when 1 99 if required_args == 0 && optional_args == 0 && !rest 100 # SEQUEL6: remove 101 Sequel::Deprecation.deprecate("Arity mismatch in block passed to define_sequel_method. Expected Arity 1, but no arguments accepted for #{block.inspect}. Support for this will be removed in Sequel 6.") 102 temp_method = SEQUEL_METHOD_NAME.call("temp") 103 model.class_eval("def #{temp_method}(_) #{meth =~ /\A\w+\z/ ? "#{meth}_arity" : "send(:\"#{meth}_arity\")"} end", __FILE__, __LINE__) 104 model.send(:alias_method, meth, temp_method) 105 model.send(:undef_method, temp_method) 106 model.send(:private, meth) 107 meth = :"#{meth}_arity" 108 elsif required_args > 1 109 # SEQUEL6: remove 110 Sequel::Deprecation.deprecate("Arity mismatch in block passed to define_sequel_method. Expected Arity 1, but more arguments required for #{block.inspect}. Support for this will be removed in Sequel 6.") 111 b = block 112 block = lambda{|r| instance_exec(r, &b)} # Fallback 113 end 114 else 115 raise Error, "unexpected arity passed to define_sequel_method: #{expected_arity.inspect}" 116 end 117 end 118 119 model.send(:define_method, meth, &block) 120 model.send(:private, meth) 121 call_meth 122 end
Add method to mod
that overrides inherited_instance_variables
to include the values in this hash.
# File lib/sequel/model/plugins.rb 39 def self.inherited_instance_variables(mod, hash) 40 mod.send(:define_method, :inherited_instance_variables) do || 41 super().merge!(hash) 42 end 43 end
Private Class Methods
Return the number of required argument, optional arguments, whether the callable accepts any additional arguments, and whether the callable accepts keyword arguments (true, false or :required).
# File lib/sequel/model/plugins.rb 128 def self._define_sequel_method_arg_numbers(callable) 129 optional_args = 0 130 rest = false 131 keyword = false 132 callable.parameters.map(&:first).each do |arg_type, _| 133 case arg_type 134 when :opt 135 optional_args += 1 136 when :rest 137 rest = true 138 when :keyreq 139 keyword = :required 140 when :key, :keyrest 141 keyword ||= true 142 end 143 end 144 arity = callable.arity 145 if arity < 0 146 arity = arity.abs - 1 147 end 148 required_args = arity 149 arity -= 1 if keyword == :required 150 151 if callable.is_a?(Proc) && !callable.lambda? 152 optional_args -= arity 153 end 154 155 [required_args, optional_args, rest, keyword] 156 end