/usr/lib/ruby/vendor_ruby/sequel/plugins/hook_class_methods.rb is in ruby-sequel 4.1.1-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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | module Sequel
module Plugins
# Sequel's built-in hook class methods plugin is designed for backwards
# compatibility. Its use is not encouraged, it is recommended to use
# instance methods and super instead of this plugin. What this plugin
# allows you to do is, for example:
#
# # Block only, can cause duplicate hooks if code is reloaded
# before_save{self.created_at = Time.now}
# # Block with tag, safe for reloading
# before_save(:set_created_at){self.created_at = Time.now}
# # Tag only, safe for reloading, calls instance method
# before_save(:set_created_at)
#
# Pretty much anything you can do with a hook class method, you can also
# do with an instance method instead:
#
# def before_save
# return false if super == false
# self.created_at = Time.now
# end
#
# Note that returning false in any before hook block will skip further
# before hooks and abort the action. So if a before_save hook block returns
# false, future before_save hook blocks are not called, and the save is aborted.
#
# Usage:
#
# # Allow use of hook class methods in all model subclasses (called before loading subclasses)
# Sequel::Model.plugin :hook_class_methods
#
# # Allow the use of hook class methods in the Album class
# Album.plugin :hook_class_methods
module HookClassMethods
# Set up the hooks instance variable in the model.
def self.apply(model)
hooks = model.instance_variable_set(:@hooks, {})
Model::HOOKS.each{|h| hooks[h] = []}
end
module ClassMethods
Model::HOOKS.each{|h| class_eval("def #{h}(method = nil, &block); add_hook(:#{h}, method, &block) end", __FILE__, __LINE__)}
# This adds a new hook type. It will define both a class
# method that you can use to add hooks, as well as an instance method
# that you can use to call all hooks of that type. The class method
# can be called with a symbol or a block or both. If a block is given and
# and symbol is not, it adds the hook block to the hook type. If a block
# and symbol are both given, it replaces the hook block associated with
# that symbol for a given hook type, or adds it if there is no hook block
# with that symbol for that hook type. If no block is given, it assumes
# the symbol specifies an instance method to call and adds it to the hook
# type.
#
# If any before hook block returns false, the instance method will return false
# immediately without running the rest of the hooks of that type.
#
# It is recommended that you always provide a symbol to this method,
# for descriptive purposes. It's only necessary to do so when you
# are using a system that reloads code.
#
# Example of usage:
#
# class MyModel
# define_hook :before_move_to
# before_move_to(:check_move_allowed){|o| o.allow_move?}
# def move_to(there)
# return if before_move_to == false
# # move MyModel object to there
# end
# end
#
# Do not call this method with untrusted input, as that can result in
# arbitrary code execution.
def add_hook_type(*hooks)
Model::HOOKS.concat(hooks)
hooks.each do |hook|
@hooks[hook] = []
instance_eval("def #{hook}(method = nil, &block); add_hook(:#{hook}, method, &block) end", __FILE__, __LINE__)
class_eval("def #{hook}; model.hook_blocks(:#{hook}){|b| return false if instance_eval(&b) == false}; end", __FILE__, __LINE__)
end
end
# Returns true if there are any hook blocks for the given hook.
def has_hooks?(hook)
!@hooks[hook].empty?
end
# Yield every block related to the given hook.
def hook_blocks(hook)
@hooks[hook].each{|k,v| yield v}
end
Plugins.inherited_instance_variables(self, :@hooks=>:hash_dup)
private
# Add a hook block to the list of hook methods.
# If a non-nil tag is given and it already is in the list of hooks,
# replace it with the new block.
def add_hook(hook, tag, &block)
unless block
(raise Error, 'No hook method specified') unless tag
block = proc {send tag}
end
h = @hooks[hook]
if tag && (old = h.find{|x| x[0] == tag})
old[1] = block
else
if hook.to_s =~ /^before/
h.unshift([tag,block])
else
h << [tag, block]
end
end
end
end
module InstanceMethods
Model::BEFORE_HOOKS.each{|h| class_eval("def #{h}; model.hook_blocks(:#{h}){|b| return false if instance_eval(&b) == false}; super; end", __FILE__, __LINE__)}
Model::AFTER_HOOKS.each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
end
end
end
end
|