Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to override parents defined hooks #12

Merged
merged 3 commits into from
Nov 29, 2024
Merged

Conversation

josemoyab
Copy link
Contributor

@josemoyab josemoyab commented Nov 26, 2024

Overriding a hook in a child class currently overrides all the hooks defined by its parents. This PR aims to allow overriding only the desired hooks based on the hook class. However, it doesn’t permit adding the same hook twice on the same kind.

This PR also consider around hooks while checking if all hooks excluded a method

@gtrias
Copy link
Member

gtrias commented Nov 28, 2024

Overriding a hook in a child class currently overrides all the parents’ defined hooks. This PR helps to override the desired ones based on the hook class.

@josemoyab can you try if the configuration works with this changes made by @atd ?

#10

@josemoyab josemoyab force-pushed the allow-overriding-hooks branch from c6ecc23 to 794891a Compare November 28, 2024 11:01
@josemoyab
Copy link
Contributor Author

Overriding a hook in a child class currently overrides all the parents’ defined hooks. This PR helps to override the desired ones based on the hook class.

@josemoyab can you try if the configuration works with this changes made by @atd ?

#10

I tested the configuration with the changes made by @atd, and everything worked as expected.

@josemoyab josemoyab marked this pull request as ready for review November 28, 2024 11:03
@josemoyab josemoyab requested a review from gtrias November 28, 2024 11:08
@@ -44,17 +44,19 @@ def hook(
# Hooks logic part
####
def get_hooks(kind)
# Only get hooks from the most specific class that defines them
return hooks[kind].values if hooks[kind].any?
hook_list = Hash.new { |h, k| h[k] = [] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this? why it needs to be initialized in this way?

Copy link
Contributor Author

@josemoyab josemoyab Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hash where we’ll store and organize the hooks defined by a class and its ancestors. The key is the hook class name, and the value is an array containing all the occurrences of that hook.

It can be initialized that way to directly store hook occurrences using the “<<“ operator on the loop

# If no hooks found anywhere in the chain, return empty array
[]
# Return an array containing the first element of each key in hook_list
hook_list.values.map(&:first)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why &:first? how this hook_list.values looks like?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On each iteration of the loop, we stored all the occurrences of hooks from a class and its ancestors in the hook_list. Since the array is sorted, selecting the first element means that we retrieve the hook definition closer to the child class.

Considering the following class definitions::

class Child
   hook :before, hook: Hook1.new, ...
end

class Parent < Child
   hook :before, hook: Hook1.new, ...
   hook :before, hook: Hook2.new, ...
end

Calling get_hooks(:before) will set the value of hook_list to this:

{
  "Hook1": [Hook1 (from Child), Hook1 (from Parent),
  "Hook2": [Hook2 (from Parent)]
}

and hook_list.values will looks like:

[
[Hook1 (from Child), Hook1 (from Parent)],
[Hook2 (from Parent)]
]

So mapping the values using first will produce an array like:

[Hook1 (from Child), Hook2 (from Parent)]

Copy link
Member

@gtrias gtrias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand the fix. What essentially changed?

@gtrias
Copy link
Member

gtrias commented Nov 28, 2024

Overriding a hook in a child class currently overrides all the parents’ defined hooks. This PR helps to override the desired ones based on the hook class.

@josemoyab can you try if the configuration works with this changes made by @atd ?
#10

I tested the configuration with the changes made by @atd, and everything worked as expected.

You mean that merging @atd changes this PR is not needed anymore?

@josemoyab
Copy link
Contributor Author

I tested the configuration with the changes made by @atd, and everything worked as expected.

You mean that merging @atd changes this PR is not needed anymore?

It means I merge his branch and mine and everything worked as expected

@josemoyab
Copy link
Contributor Author

josemoyab commented Nov 28, 2024

I don't fully understand the fix. What essentially changed?

I added a comment with an example, but TL;DR I changed get_hooks method so if a class defines some hooks instead of returning only the hooks defined by itself, it also include hooks defined by its parents. And also included around hooks on method_excluded_by_all_hooks? method so we prevent excluding all hooks defined for a method when some hook on around excluded that method

@atd
Copy link
Contributor

atd commented Nov 29, 2024

@josemoyab please be aware that my branch is failing in Factorial

@josemoyab josemoyab requested a review from gtrias November 29, 2024 10:35
@josemoyab
Copy link
Contributor Author

@josemoyab please be aware that my branch is failing in Factorial

No worries, I've tested this branch in factorial and everything looks good

@gtrias I've simplified the get_hooks method as we discussed

@@ -44,17 +44,13 @@ def hook(
# Hooks logic part
####
def get_hooks(kind)
# Only get hooks from the most specific class that defines them
return hooks[kind].values if hooks[kind].any?
ancestors.each_with_object({}) do |klass, hook_list|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much better!

Copy link
Member

@gtrias gtrias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@josemoyab josemoyab merged commit 549f1ce into main Nov 29, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants