Skip to content

Commit

Permalink
Fixing double hook execution
Browse files Browse the repository at this point in the history
  • Loading branch information
gtrias committed Oct 30, 2024
1 parent e25eb12 commit 7f2ba50
Showing 1 changed file with 25 additions and 18 deletions.
43 changes: 25 additions & 18 deletions lib/captain_hook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,30 +77,37 @@ module ClassMethods
####
# Get all hooks from ancestors so you can define hooks in a parent class
def get_ancestor_hooks
# Start with empty hash for each hook type
ancestor_hooks = { before: {}, after: {}, around: {} }

ancestors.each do |ancestor|
next unless ancestor.respond_to?(:hooks)

ancestor.hooks[:before].each_value do |hook|
ancestor_hooks[:before][hook.hook.class.name] = hook
end

ancestor.hooks[:after].each_value do |hook|
ancestor_hooks[:after][hook.hook.class.name] = hook
end

ancestor.hooks[:around].each_value do |hook|
ancestor_hooks[:around][hook.hook.class.name] = hook

# Get all ancestors that have hooks, from most distant to closest
hook_ancestors = ancestors.reverse.select { |ancestor| ancestor.respond_to?(:hooks) }

# Build a hash of unique hooks, with later ancestors overriding earlier ones
hook_ancestors.each do |ancestor|
[:before, :after, :around].each do |kind|
ancestor.hooks[kind].each do |hook, config|
# Use the hook object itself as the key
ancestor_hooks[kind][hook] = config
end
end
end

ancestor_hooks
end

def get_hooks(kind)
all_hooks = (get_ancestor_hooks[kind].values + hooks[kind].values).uniq(&:hook)
all_hooks.flatten
# Only get hooks from the most specific class that defines them
return hooks[kind].values if hooks[kind].any?

# If no hooks defined in this class, look up the inheritance chain
ancestors[1..-1].each do |ancestor|
next unless ancestor.respond_to?(:hooks)
return ancestor.hooks[kind].values if ancestor.hooks[kind].any?
end

# If no hooks found anywhere in the chain, return empty array
[]
end

def hooks
Expand Down Expand Up @@ -162,12 +169,12 @@ def decorate_method!(method_name)
mark_as_overriden!(method_name)

original_method_name = :"#{method_name}__without_hooks"


# Skip if this is an inherited method that's already decorated
return if method_defined?(original_method_name)

alias_method original_method_name, method_name

# We decorate the method with the before, after and around hooks
define_method(method_name) do |*args, **kwargs|
hook_args = args
hook_kwargs = kwargs
Expand Down

0 comments on commit 7f2ba50

Please sign in to comment.