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

Combining guards #30

Closed
eregon opened this issue Jul 2, 2017 · 11 comments
Closed

Combining guards #30

eregon opened this issue Jul 2, 2017 · 11 comments

Comments

@eregon
Copy link
Member

eregon commented Jul 2, 2017

Currently, combining guards is complicated, and is often side-stepped by using shared specs which introduce an extra indirection.

Going forward I would like that guards also support being called without a block and just return true/false. Then with some generic guard/guard_not taking a lambda for the guard we could do just like if/unless, but also be able to ignore all guards (--unguarded). I am currently pondering whether --unguarded is really useful. If not, we could remove it and then just use something like:

if platform_is :linux or (platform_is :windows and ruby_version_is "2.5")
  # specs
end

which I believe is much simpler, but prevents ignoring guards globally (--unguarded).

@mjago
Copy link
Contributor

mjago commented Jul 2, 2017

Funnily enough I was looking at something like this this-morning.
What about:

platform_is :windows do
end
xyz if platform_is? :windows 

...pairs

@mjago
Copy link
Contributor

mjago commented Jul 2, 2017

Also I can't think of a useful --unguarded case myself

@eregon
Copy link
Member Author

eregon commented Jul 2, 2017

Re --unguarded, I know these usages:

  • Tag all specs of a given file with mspec --unguarded --all --dry-run --add fails SPEC, which is useful when the particular method/feature is not implemented at all but yet the implementation can load the file. This ensures it also tags on other platforms, etc, but is an over-estimation. I think it is not critical as it already works relatively well without --unguarded.
  • Being able to count how many examples exist in total. This is not very interesting.
  • It is used by mkspec to check if there is already a spec for a given method. We could replace this with a text search. It would be a bit less robust, but probably enough for this use-case.
  • It is used by mspec tag --purge which removes tags not matching any spec and therefore needs to ignore at least platforms guards (otherwise it would remove linux-specific tags on non-linux which would be wrong).

The last usage is the one that seems hard to work around without the possibility to turn off guards.
One workaround would be to delete the corresponding tag files and tag again with mspec tag --fail --add fails but that would only add failures on the current platform, lose the potential comments in the tags and the kind of the tag (it could be linux tag and not just a generic fails tag), and sometimes specs crash the interpreter so this is not practical.

@eregon
Copy link
Member Author

eregon commented Jul 2, 2017

What about:

platform_is :windows do
end
xyz if platform_is? :windows 

...pairs

I think we should avoid introducing too many extra methods at the top-level, so I think compromising and dropping the extra ? is better here. It also makes the implementation much simpler and less redundant.

@mjago
Copy link
Contributor

mjago commented Jul 4, 2017

I didn't know about mkspec - is it documented beyond the command line info?

I've always thought it would be nice if there were a dynamic list somewhere that indicated missing specs. I remember writing specs for `something' only to find they existed somewhere I hadn't looked!

@eregon
Copy link
Member Author

eregon commented Jul 4, 2017

Re mkspec, it's "documented" here: https://github.com/ruby/spec/blob/master/CONTRIBUTING.md#mkspec---a-tool-to-generate-the-spec-structure

@MSP-Greg
Copy link

@eregon

if platform_is :linux or (platform_is :windows and ruby_version_is "2.5")
  # specs
end

I like that, but as you mentioned, it causes other issues.

Maybe something like an env_is method that can take multiple platform/version constraints? Something like -

env_is [:linux], [:windows, :gte_25] do
end

Obviously, there would be need for several symbols defined for 2nd element, since people may prefer to have both a 'greater than or equal' (gte) or a 'less than' (lt) constraint.

Thinking six months from now, when 2.3, 2.4, 2.5 and 2.6 will probably all exist...

As an aside, I'll look at adding mspec to my doc site. Someday I'll write some code to allow spec style tests to be doc'd. And, sorry for the delay.

@eregon
Copy link
Member Author

eregon commented Jul 17, 2017

@MSP-Greg The problem with the env_is above is it's unclear if the guards are combined with OR or AND.

I'll try to implement:

guard -> { platform_is :linux or (platform_is :windows and ruby_version_is "2.5") } do
  ...
end

That should be relatively straightforward.
It's a bit verbose but we rarely need composed guards and I think it's good in terms of clarity.
The opposite guard could be:

guard_not -> { platform_is :linux or (platform_is :windows and ruby_version_is "2.5") } do
  ...
end
# or (but it's not trivial to invert so I prefer the one above)
guard -> { platform_is_not :linux and (platform_is_not :windows or ruby_version_is ""..."2.5") } do
  ...
end

I'm not yet convinced guard/guard_not are good names though.
Any idea for a better names for generic "guards" taking a lambda?

Maybe run_if/run_unless although run is not very descriptive.

@eregon
Copy link
Member Author

eregon commented Jul 17, 2017

About documentation, I am not sure what you want to achieve but there once was a readruby branch which allowed to document methods right next to the specs: https://github.com/ruby/spec/commits/readruby

@MSP-Greg
Copy link

I'm not yet convinced guard/guard_not are good names though.

Maybe constrain or constraint?

@eregon eregon closed this as completed in ea7600d Jul 27, 2017
@eregon
Copy link
Member Author

eregon commented Jul 27, 2017

I implemented it as guard/guard_not in ea7600d.
These names seem the clearest for now.

I applied it in a couple places in ruby/spec in ruby/spec@25d17e1 and previous commits.
Interestingly, I did not need guard_not yet, probably because I only saw rather simple combinations of 2 guards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants