-
-
Notifications
You must be signed in to change notification settings - Fork 759
Conversation
I think I'd rather see the hook registration delayed until they are actually needed, as I suggested in the rspec-rails issue:
Any reason that won't work? Seems far less complex, and would perform better. |
It completely buggers the ordering, this is actually a far simpler change. |
Can you expand on that a bit? I'm not following... |
Moving the call to So I attempted to solve this by changing how the hooks are added to the array but then local hooks are just intermingled with the configuration hooks, so I moved the registration call to the hook methods so it's a "JIT" registration of hooks, however this messes with the ordering of hooks in nested contexts. |
So at this point the best place to load the configuration hooks is actually in the existing place, and then load in any extra hooks on metadata changes, or rewrite the hook system so we have more control over the ordering. The later is more complexity and more overhead. |
def []=(key, value) | ||
super | ||
@callback.call if defined?(@callback) | ||
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.
There are other ways to change an metadata hash, right? Such as store
, or any of the xyz!
methods. Should the on_change
hook be triggered for them?
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.
This is the only one we use AFAIK but yes they should all follow this pattern, I'll go over the enum spec and add them all.
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've updated this for the ones that set metadata, this doesn't deregister hooks at the moment (that would require more changes, do we want to support that?)
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 don't think we need to deregister hooks. on_change
is private, anyway.
I've updated this for the ones that set metadata,
What about delete
, delete_if
, select!
and reject!
?
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.
They don't set metadata, but remove it, hence my comment
this doesn't deregister hooks at the moment (that would require more changes, do we want to support that?
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'm ok with that too, or even just publicly stating we only support adding to metadata. If we stopped inheriting from hash and delegating to an internal hash we could control the api and reject those methods totally.
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'd be good to merge this PR soon, but I'd still like others to weight in (I'm still very much on the fence). @xaviershay? @samphippen? @soulcutter?
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.
Ping?
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'm OK stating that it's not intended to be a public API but is just intended for use by rspec-rails and is subject to change in a minor release.
This. We should collect stronger use-cases before exposing this publicly.
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.
Reading this more, seems like we're between a rock and a hard place. We've exposed a full Hash
as our interface, so are at the mercy of future versions of ruby to keep the method signatures that we're overriding for dirty tracking the same.
Seems like since we already have an iteration over methods in the latest version, it would be straight forward to just add the extra methods there.
Thanks, @JonRowe, after hearing you explain that this definitely seems like the right direction. Left a few comments. |
@myronmarston I've addressed the issues commented about |
Looks good...seems like you are missing a few mutation methods, though (see above). |
|
||
[:[]=, :store, :merge!].each do |name| | ||
define_method(name) do |*args| | ||
super(*args) |
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.
merge!
accepts a block:
http://www.ruby-doc.org/core-2.0.0/Hash.html#method-i-merge-21
I think that it gets forwarded automatically via super
, but it would be good to spec that.
The other mutation methods only remove things from the hash, there's currently nothing to remove hooks when you remove metadata anyway. I left off the other mutation methods to make this more apparent. (See above) |
@@ -156,6 +156,19 @@ def ascending_numbers | |||
expect(examples_run.count).to eq(1) | |||
end | |||
|
|||
it "still runs matching config hooks when metadta is added later" do |
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.
s/metadta/metadata/
Rebased and added extra mutation methods. Note that overriding |
oop, forgot about compat for old versions again :/ |
Given that this is not a new feature, and that Jon is away all weekend, I'm going to argue that this should not be a blocker for 3.0.0 pre. Any objections? |
Thanks for adding the extra mutation methods @xaviershay, any ideas on how to actually make this work in those situations? (e.g. actually remove now unnecessary hooks?) |
Only need to guard the spec, real code will be harmless.
Ah I see, I didn't understand the problem. Going to think about this after 3-pre. If you wanted to mark as private and merge without the extra mutation methods I'd be ok with that. |
WDYT @myronmarston? Merge without the mutation methods? Or at least with the mutation methods marked as private...? |
IIRC, this is fixing a bug in rspec-rails 2.14, right? Let's merge this in some form ASAP. I'm not sure what "with the mutation methods marks as private" means -- the metadata object is a hash, and the mutation methods are part of a hash's public interface. What do you mean by that? |
Following on from @xaviershay's suggestion, they're public for |
Hmmm...I don't think we can do that in RSpec 2.x -- it would violate semver. We can do it in RSpec 3, but I'm wondering if there's a better approach we can do in 3.0? Can we change how rspec-rails does it's inclusion (maybe along the lines of rspec/rspec-rails#662) so that this is unnecessary? |
@myronmarston However we solve rspec-rails (I still think this is the easiest way) we should either fix this or make metadata immutable. As it stands it's confusing IMO. |
@JonRowe -- clearly this solution isn't going to work with the metadata hash just being a raw hash...we should figure out an alternate solution. Keeping open for now until we figure that out. |
I think we need an api to mutate the hash, that triggers the hook inclusion et al, then |
What kind of API do you have in mind? I'm having trouble coming up with a non-clunky API for that. Here's an alternate idea I presented in #1231: RSpec.configure do |rspec|
rspec.define_inferred_metadata do |metadata|
metadata[:type] = type_for(metadata[:file_path])
end
end Basically, rather than officially supporting all metadata features when you mutate metadata after the fact, provide an API to allow inferred metadata entries (which rspec-rails currently mutates the metadata to achieve), and rspec-core will ensure the inferred entries are set before it does anything with the metadata. |
👍 |
Closing in favor of #1496 |
Fully supporting metadata mutation is fraught with difficulties see (rspec/rspec-rails#829 and the attempted fix in #1089). For RSpec 3, we decided to expose `define_derived_metadata` as an officially supported way to accomplish the sorts of things metadata mutation was used for in RSpec 2. This spec got left behind (since it was passing at the time, it wasn't noticed) but isn’t something we want to support going forward since module inclusion shouldn't mutate metadata. It’s also getting in the way of a perf optimization I'm implementing.
Fully supporting metadata mutation is fraught with difficulties see (rspec/rspec-rails#829 and the attempted fix in #1089). For RSpec 3, we decided to expose `define_derived_metadata` as an officially supported way to accomplish the sorts of things metadata mutation was used for in RSpec 2. This spec got left behind (since it was passing at the time, it wasn't noticed) but isn’t something we want to support going forward since module inclusion shouldn't mutate metadata. It’s also getting in the way of a perf optimization I'm implementing.
Fully supporting metadata mutation is fraught with difficulties see (rspec/rspec-rails#829 and the attempted fix in #1089). For RSpec 3, we decided to expose `define_derived_metadata` as an officially supported way to accomplish the sorts of things metadata mutation was used for in RSpec 2. This spec got left behind (since it was passing at the time, it wasn't noticed) but isn’t something we want to support going forward since module inclusion shouldn't mutate metadata. It’s also getting in the way of a perf optimization I'm implementing.
Fully supporting metadata mutation is fraught with difficulties see (rspec/rspec-rails#829 and the attempted fix in rspec#1089). For RSpec 3, we decided to expose `define_derived_metadata` as an officially supported way to accomplish the sorts of things metadata mutation was used for in RSpec 2. This spec got left behind (since it was passing at the time, it wasn't noticed) but isn’t something we want to support going forward since module inclusion shouldn't mutate metadata. It’s also getting in the way of a perf optimization I'm implementing.
This is a trivial take at solving rspec/rspec-rails#829 but simply watching for metadata changes
and then applying hooks again when they change. Hooks shouldn't be included twice due to the
checks in the existing call.
Simply moving the call to register the hooks didn't work due to ordering on the hooks.
Thoughts? /cc @myronmarston