-
-
Notifications
You must be signed in to change notification settings - Fork 106
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
Dry::Types::Constructor(URI) triggers :uri? predicate with bad arity #335
Comments
Thanks again for such a detailed report. I'll get to it eventually unless somebody beats me to it first. |
What kind of solution are you aiming for?
Can you tell me where I can add a dummy |
@solnic @doriantaylor IMO the correct solution would be removing this fallback from dry-types https://github.com/dry-rb/dry-types/blob/3fac200005fccc546386281af27dff11de45bdb1/lib/dry/types/predicate_inferrer.rb#L49 |
I mean I doubt anyone uses this intentionally |
Yeah, hey, if it's not intentional then I doubt anybody will miss it… Question: would it make sense to be able to do something like: Foo = Types.Constructor(::Foo) do |input|
Foo.new(coerce_foo input)
end.predicate do |raw|
validate_foo raw
end …and then have the validation predicate attached to the type itself? |
@flash-gordon @doriantaylor the intention was to support arbitrary types with a primitive that has a corresponding predicate type-check, it's obviously buggy and naive so it should be fixed, rather than removed (especially that removing it would break people's code). I believe a simple check if there's a valid corresponding predicate will be enough. |
@doriantaylor btw for the time being you can pin dry-logic to the version that doesn't have |
Fixed via dry-rb/dry-types#414 Filled
Bool
Number
Empty
Odd
Even
True
False
UUID_V1
UUID_V2
UUID_V3
UUID_V4
UUID_V5 I don't think it has a lot of usage :) |
@flash-gordon we probably want to make this fix in dry-schema 1.6.0 because it should depend on latest dry-types that may require some people to turn on the old behavior. WDYT? (assuming I understand dry-rb/dry-types#414 correctly 🙂) |
@solnic like cut a release with a bumped dependency and add an entry to the changelog? |
@flash-gordon yes because if somebody pulls in latest dry-types w/o us bumping dry-schema, it could be a nasty surprise. If we make it more explicit through dep update + new release of dry-schema, things will be more obvious for the users. |
So, the final solution will be:
|
@flash-gordon sounds like a really good plan! |
when are you going to release this? |
I mean it's basically ready. I'll deploy it to production today and release gems tomorrow (if nothing comes up). |
The recent addition of the
uri?
predicate toDry::Logic::Predicates
has the unfortunate side effect of crashing when aDry::Types::Constructor
is based off ofURI
(or presumably/(?:.*::)?URI$/
; as will be explained momentarily):The following code will reproduce the error given
dry-schema
1.5.6 anddry-logic
1.0.8:Diagnosis
It appears that what is happening is the
Types::URI
object is being handed off to an instance ofDry::Types::PredicateInferrer
like so:…which it appears to do via
Dry::Schema::Macros::DSL#extract_type_spec
. The:uri?
predicate is picked because of line 49 indry-types/predicate_inferrer.rb
, which looks like:…which if I understand correctly will turn the class name
URI
into the symbol:uri?
given that it is not found in the hash. Since this predicate takes two arguments,Dry::Schema::Predicate#ensure_valid
raises an exception because this invocation of:uri?
has been queued without its other argument (an array of URI schemes), and to my knowledge there is no (documented) way to get additional arguments into predicates that have been queued through the inferrer mechanism.Remedies
I see a number of possible remedies for this situation; the simplest perhaps being to overwrite the
uri?
predicate in the application with a method of arity 1. My only problem with this is it is not clear via the documentation where the predicate is actually being invoked and thus where it must be overridden.Another solution would be to modify
Dry::Types::PredicateInferrer#infer_predicate
to ignore matches on predicates with arities greater than 1. Ostensibly the most involved solution would be to change (or document?) the interface so the additional arguments can be passed into multi-argument predicates when those predicates have been inferred.Remarks
This bug was particularly difficult to track down. The behaviour spans three modules (
dry-schema
,dry-types
,dry-logic
), which is fine—it is DRY after all—but perhaps some additional signposts or an architectural overview would be helpful. The ultimateraise
inensure_valid
was particularly ambiguous, down to the choice ofArgumentError
: in addition to the terse error message, it wasn't clear initially where this error was coming from. My inclination here would be to create a subclass ofArgumentError
(say,PredicateParamError
) to signal the peculiar case that a given predicate—which has yet to be invoked—has not been bundled with its requisite parameters. Saying something explicit in the error message likepredicate :foo? takes parameters; see docs at …
would also be helpful.The overarching approach to mapping class names to predicates, moreover, has the potential to produce fragile and surprising results. Consider:
…sure enough:
This is because of line 95 in
trace.rb
, looking for the derivation of the class name:key?
which has been listed as invalid. As with the introduction of the:uri?
predicate did with my code, there is potential for future predicates colliding with class names given toDry::Types::Constructor
. As such I apologize if I have potentially burdened you with an architectural rethink, and that my ignorance of the inner workings ofdry-rb
precludes me of being much more help than this. Nevertheless if pointed in the right direction I can hopefully do more.The text was updated successfully, but these errors were encountered: