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 48 def self.after_set_dataset(mod, meth) 49 mod.send(:define_method, :set_dataset) do |*a| 50 r = super(*a) 51 # Allow calling private class methods as methods this specifies are usually private 52 send(meth) 53 r 54 end 55 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 mod.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true) 35 end 36 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 79 def self.def_sequel_method(model, meth, expected_arity, &block) 80 if meth.is_a?(String) 81 meth = SEQUEL_METHOD_NAME.call(meth) 82 end 83 call_meth = meth 84 85 unless block.lambda? 86 required_args, optional_args, rest, keyword = _define_sequel_method_arg_numbers(block) 87 88 if keyword == :required 89 raise Error, "cannot use block with required keyword arguments when calling define_sequel_method with expected arity #{expected_arity}" 90 end 91 92 case expected_arity 93 when 0 94 unless required_args == 0 95 # SEQUEL6: remove 96 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.") 97 b = block 98 block = lambda{instance_exec(&b)} # Fallback 99 end 100 when 1 101 if required_args == 0 && optional_args == 0 && !rest 102 # SEQUEL6: remove 103 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.") 104 temp_method = SEQUEL_METHOD_NAME.call("temp") 105 model.class_eval("def #{temp_method}(_) #{meth =~ /\A\w+\z/ ? "#{meth}_arity" : "send(:\"#{meth}_arity\")"} end", __FILE__, __LINE__) 106 model.send(:alias_method, meth, temp_method) 107 model.send(:undef_method, temp_method) 108 model.send(:private, meth) 109 meth = :"#{meth}_arity" 110 elsif required_args > 1 111 # SEQUEL6: remove 112 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.") 113 b = block 114 block = lambda{|r| instance_exec(r, &b)} # Fallback 115 end 116 else 117 raise Error, "unexpected arity passed to define_sequel_method: #{expected_arity.inspect}" 118 end 119 end 120 121 model.send(:define_method, meth, &block) 122 model.send(:private, meth) 123 call_meth 124 end
Add method to mod
that overrides inherited_instance_variables
to include the values in this hash.
# File lib/sequel/model/plugins.rb 40 def self.inherited_instance_variables(mod, hash) 41 mod.send(:define_method, :inherited_instance_variables) do || 42 super().merge!(hash) 43 end 44 mod.send(:private, :inherited_instance_variables) 45 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 130 def self._define_sequel_method_arg_numbers(callable) 131 optional_args = 0 132 rest = false 133 keyword = false 134 callable.parameters.map(&:first).each do |arg_type, _| 135 case arg_type 136 when :opt 137 optional_args += 1 138 when :rest 139 rest = true 140 when :keyreq 141 keyword = :required 142 when :key, :keyrest 143 keyword ||= true 144 end 145 end 146 arity = callable.arity 147 if arity < 0 148 arity = arity.abs - 1 149 end 150 required_args = arity 151 arity -= 1 if keyword == :required 152 153 # callable currently is always a non-lambda Proc 154 optional_args -= arity 155 156 [required_args, optional_args, rest, keyword] 157 end