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
Alias Drop#invoke_drop to Drop#[] #6338
Conversation
If a drop is mutable, #[] preferes the user-set value over the default (a Jekyll construct). This leads to scenarios where drop.value and drop["value"] return different values. By aliasing #invoke_drop to #[], both will respect mutability and return the same value.
@benbalter Great explanation, I'm a big fan of how you document issues to allow others to learn. 👏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it, and totally down to include this change in 3.6 and possibly backport. In order to ensure we don't lose this behaviour in the future, could you add a test to test/test_utils.rb
?
Whoops – |
Implemented via a948998. |
lib/jekyll/drops/drop.rb
Outdated
|
||
def fallback_data | ||
@fallback_data ||= {} | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The base drop class (in #[]
, #keys
and #key?
) assumes fallback data to exist and return a hash. Stubbed out the default value so that child classes don't each have to implement it if they don't have fallback data (including our test fixture).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intentionally left this method out so all drops had to implement this – it was part of the design of Jekyll Drops, that some fallback data had to be provided by the developer of a drop. I'm not sure I like that going away. :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was part of the design of Jekyll Drops, that some fallback data had to be provided by the developer of a drop
Admittedly out of scope, so glad to remove from this PR. Curious if that rationale still holds true when Jekyll internally often implements it as an empty hash?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed via 847ed7f
Fixing this one problem revealed another blocker to mutability taking precedence over methods. Take a look at 3776c44 (failing test) and c998c59 (fix). In short, This now PR simply changes |
Sounds like we should backport this to 3.5.x once it ships. 👍 to merge once CI is passing. |
@jekyllbot: merge +minor. |
@DirtyF discovered an interesting behavior via jekyll/github-metadata#108 (comment), which I had attempted to resolve (unsuccessfully) via jekyll/github-metadata#110.
In the particular instance,
Jekyll::Utils.deep_merge_hashes(drop, hash)
was returning a drop as expected, but without the hash values overriding the drop values. After some digging, I discovered the merge logic was correct (and calling[key]=value
, which gets stored in@mutations
), but that when a drop method was called, it was returning the drop's value, not the mutation.If a drop is mutable,
#[]
prefers the user-set value over the default (a Jekyll construct).#invoke_drop(key)
which Liquid uses, however, doesn't understand the concept of mutations as it's usingLiquid::Drop
's native implementation. This leads to scenarios wheredrop.key
,drop.invoke_drop('key')
anddrop["key"]
return different values.Normally,
Drop#[]
is aliased toDrop#invoke_drop
ensuring the values remain in sync. Since they both implement the same core logicpublic_send key if self.class.invokable? key
, by aliasing#invoke_drop
to#[]
, both will respect mutability and return the same value regardless ofdrop.invoke_drop('key')
ordrop['key]
is called (and allowingJekyll::Utils.deep_merge_hashes
to perform the expected operation).Given the following test case:
Output before change:
Output after change:
The one gotcha, is with this implementation is we lose the
liquid_method_missing
logic, which we could encorporate into#[]
if we want, but isn't strictly necessary in our implementation since we never raise for missing methods.