-
-
Notifications
You must be signed in to change notification settings - Fork 357
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
Support keyword arguments when checking for valid arity. #543
Conversation
else | ||
# `~` inverts the one's complement and gives us the number of | ||
# required arguments. | ||
~method.arity |
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.
Wow, it's been a long time since I've seen this operator used.
I wonder if |
min_arity <= actual && actual <= max_arity | ||
def matches?(actual_args) | ||
missing_required_keyword_args(actual_args).empty? && | ||
within_range?(actual_args.length) |
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 have any projects on ruby 2.0 yet and haven't played around with kw args so this might be totally wrong, but should we also check for invalid optional keyword args? e.g. a keyword arg that is given but that the method does not accept? Or is that not even a valid concept according to the semantics of how the ruby feature works? (You can tell I really don't know much about this language feature yet!)
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.
oh good call (I haven't used these much either)
irb(main):001:0> def x(a:1); end
=> nil
irb(main):002:0> x(b: 2)
ArgumentError: unknown keyword: b
Will tackle in a new PR, tracking here: #545
I'm excited to get support for newer ruby features like this in rspec 3 :). As you probably gathered from what I said above, I'm pretty clueless about the details of the kw args feature in ruby 2.0 and 2.1, having never used it or done more than a cursory reading about it when 2.0 came out. Do you know of a resource that goes into detail about all the different cases and how ruby handles them? I'd like to understand them better. |
I haven't seen a good document that went beyond the trivial parts of it. Playing around with them, |
@myronmarston I believe I have addressed all of your comments. I settled on I also moved the top-level ruby features method to their own module in the library itself, which improved the Don't merge this as is - when we're happy with it I want to squash down the commits. |
So I just figured something out that may be useful...if we capture the args like this: def foo(*non_kw_args, **kw_args)
end ...we explicitly get a However, once we explicitly split kw args vs non-kw args, I think it becomes much easier to model a method signature and see if a given set of args is acceptable. Specifically, we can model the following things easily:
When we capture the args, we can compare the non-kw args against just the first two attributes and compare the kw args just against the last two attributes. Then we don't even have to talk about arity, and you'd only need to use the |
I think that makes sense, particularly for when we add allowed optional args support. OK to tackle it in that PR? |
If we merge this PR and release 3.0.0.beta2 w/o the changes coming in that other PR, will that cause an inconsistent/confusing experience for users? My instinct is that supporting some aspects of kw arg method signature verification (but not all aspects) is confusing, and I think I'd rather release beta2 without any kw arg support than to have it have partial kw arg support. So if you plan to keep working on this in the short term before beta2 is released you may want to keep at it on this PR; otherwise, after beat2 is released this can probably be merged as-is (sans a rebase to deal with merge conflicts and I also want to re-review now that you've addressed my feedback -- haven't looked at your changes yet). |
This changes the error message that was included in the ArgumentError raised when arity was incorrect. It used to match the default Ruby message, it now uses our enhanced error message. While it would be technically more correct to emulate the Ruby one, ours is more useful and the logic required would now have to be more complicated to support keyword arguments. Fixes #431.
The drop is due to the addition of more implementation-specific code that has created more lines that are unable to be tested on a single Ruby.
@myronmarston I added support for allowed keywords, and refactored
|
|
||
let(:test_method) { method(:arity_kw) } | ||
|
||
it 'returns false unless all required keywords args are present' 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.
This doc string is confusing; you're not dealing with any required keyword args in this example.
Woops, looks like github was showing me an outdated view even though it showed me your most recent comment, so I left comments on old code. Ignore them -- I'll re-review what you have now. |
|
||
it 'does not require any of the arguments' do | ||
expect(within_range?(1)).to eq(true) | ||
expect(within_range?(2)).to eq(false) |
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 think within_range?
is confusing when used with a method that has kw args. It may or may not accept 2 args depending on what they are:
irb(main):001:0> def arity_kw(x, y:1, z:2); end
=> nil
irb(main):002:0> arity_kw(nil, nil)
ArgumentError: wrong number of arguments (2 for 1)
from (irb):1:in `arity_kw'
from (irb):2
from /Users/myron/.rubies/ruby-2.0.0-p247/bin/irb:12:in `<main>'
irb(main):003:0> arity_kw(nil, {})
=> nil
I think we're better of testing these methods with an actual list of args rather than using a helper where you pass a number since the values are important.
@xaviershay -- I've got some seeds of ideas for further improvement but it's the kind of thing I need to play with a bit to really flesh out. I don't think it'll change any external behavior but it should make it easier to maintain and reason about. So maybe we should merge this and then I can do a PR on top of this? |
BTW, this addresses #545 now, right? |
After sleeping on it I figured out how to do this, will submit further improvement today. Yes, it addresses #545. |
@myronmarston latest commit isn't a great diff, but I think is a better way of doing this. I had to noun a verb, but everything else became clearer. |
I love the metaness of this, since it uses "noun" as a verb and "verb" as a noun :). |
This looks great, @xaviershay. Merging. |
Support keyword arguments when checking for valid arity.
Dammit you didn't let me rebase+squash :( |
Didn't realize you wanted to, sorry. |
s'ok we're still friends |
This changes the error message that was included in the
ArgumentError
raised when arity was incorrect. It used to match the default Ruby
message, it now uses our enhanced error message. While it would be
technically more correct to emulate the Ruby one, ours is more useful and the
logic required would now have to be more complicated to support keyword
arguments.
Fixes #431.
R @alindeman @myronmarston