/usr/lib/ruby/vendor_ruby/sequel/plugins/association_proxies.rb is in ruby-sequel 4.15.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | module Sequel
module Plugins
# Sequel by default does not use proxies for associations. The association
# method for *_to_many associations returns an array, and the association_dataset
# method returns a dataset. This plugin makes the association method return a proxy
# that will load the association and call a method on the association array if sent
# an array method, and otherwise send the method to the association's dataset.
#
# You can override which methods to forward to the dataset by passing a block to the plugin:
#
# plugin :association_proxies do |opts|
# [:find, :where, :create].include?(opts[:method])
# end
#
# If the block returns false or nil, the method is sent to the array of associated
# objects. Otherwise, the method is sent to the association dataset. Here are the entries
# in the hash passed to the block:
#
# :method :: The name of the method
# :arguments :: The arguments to the method
# :block :: The block given to the method
# :instance :: The model instance related to the call
# :reflection :: The reflection for the association related to the call
# :proxy_argument :: The argument given to the association method call
# :proxy_block :: The block given to the association method call
#
# For example, in a call like:
#
# artist.albums(1){|ds| ds}.foo(2){|x| 3}
#
# The opts passed to the block would be:
#
# {
# :method => :foo,
# :arguments => [2],
# :block => {|x| 3},
# :instance => artist,
# :reflection => {:name=>:albums} # AssociationReflection instance
# :proxy_argument => 1,
# :proxy_block => {|ds| ds}
# }
#
# Usage:
#
# # Use association proxies in all model subclasses (called before loading subclasses)
# Sequel::Model.plugin :association_proxies
#
# # Use association proxies in a specific model subclass
# Album.plugin :association_proxies
module AssociationProxies
def self.configure(model, &block)
model.instance_eval do
@association_proxy_to_dataset = block if block
@association_proxy_to_dataset ||= AssociationProxy::DEFAULT_PROXY_TO_DATASET
end
end
# A proxy for the association. Calling an array method will load the
# associated objects and call the method on the associated object array.
# Calling any other method will call that method on the association's dataset.
class AssociationProxy < BasicObject
array = []
# Default proc used to determine whether to sent the method to the dataset.
# If the array would respond to it, sends it to the array instead of the dataset.
DEFAULT_PROXY_TO_DATASET = proc{|opts| !array.respond_to?(opts[:method])}
# Set the association reflection to use, and whether the association should be
# reloaded if an array method is called.
def initialize(instance, reflection, proxy_argument, &proxy_block)
@instance = instance
@reflection = reflection
@proxy_argument = proxy_argument
@proxy_block = proxy_block
end
# Call the method given on the array of associated objects if the method
# is an array method, otherwise call the method on the association's dataset.
def method_missing(meth, *args, &block)
v = if @instance.model.association_proxy_to_dataset.call(:method=>meth, :arguments=>args, :block=>block, :instance=>@instance, :reflection=>@reflection, :proxy_argument=>@proxy_argument, :proxy_block=>@proxy_block)
@instance.send(@reflection.dataset_method)
else
@instance.send(:load_associated_objects, @reflection, @proxy_argument, &@proxy_block)
end
v.send(meth, *args, &block)
end
end
module ClassMethods
# Proc that accepts a method name, array of arguments, and block and
# should return a truthy value to send the method to the dataset instead of the
# array of associated objects.
attr_reader :association_proxy_to_dataset
Plugins.inherited_instance_variables(self, :@association_proxy_to_dataset=>nil)
# Changes the association method to return a proxy instead of the associated objects
# directly.
def def_association_method(opts)
opts.returns_array? ? association_module_def(opts.association_method, opts){|*r, &block| AssociationProxy.new(self, opts, r[0], &block)} : super
end
end
end
end
end
|