Add Ruby cucumber-query implementation - #167
Conversation
a10f47d to
7757538
Compare
|
@mattwynne would you mind following the pull request template you made? It is kinda useful. Also keep the audience in mind. The "Test evidence" section isn't really informative, I can see that in CI output myself. Likewise the "Summary" just tells me which files you changed. I can see those too. What I am missing however is the "What's your motivation?". That I have to infer from context clues. |
There was a problem hiding this comment.
Cheers!
The shape looks alright. But I suspect you've used an LLM to some degree so that doesn't mean anything. 😉
For example I see that you've implemented/copied update_gherkin_document from the JavaScript implementation, but find_location_of(pickle) isn't tested. And you wouldn't have to as pickles have a location since cucumber/messages#308.
So now I'm a bit puzzled. I thought Luke had a test driven skeleton version of Query. And I would have expected to see that in this PR. But right now I'm looking at a lot of material with a unknown provenance. I'd rather not spend too much time reviewing statistically plausible code.
| end | ||
|
|
||
| def timestamp_ms(timestamp) | ||
| (timestamp.seconds * 1_000) + (timestamp.nanos / 1_000_000.0) |
There was a problem hiding this comment.
Is this integer or float division?
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: this now uses timestamp.nanos.fdiv(1_000_000) so the nanoseconds-to-milliseconds conversion is explicitly floating point.
</Matt's robot>
There was a problem hiding this comment.
The recommendation for YAML files is to use the .yaml extension.
There was a problem hiding this comment.
Please also copy over the the release-rubygem.yaml from any other project.
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: renamed the Ruby test workflow to .github/workflows/test-ruby.yaml. The RubyGems release workflow is already present as .github/workflows/release-rubygem.yaml, copied in this PR.
</Matt's robot>
| end | ||
|
|
||
| def duration_from_ms(milliseconds) | ||
| seconds = (milliseconds / 1_000).floor |
There was a problem hiding this comment.
Is this integer or float division?
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: this path now uses milliseconds.div(1_000) to make the whole-seconds part explicitly integer division. The fractional remainder is then converted back to nanos.
</Matt's robot>
| def find_all_test_case_started | ||
| @test_case_started_by_id.values | ||
| .reject { |started| @test_case_finished_by_test_case_started_id[started.id]&.will_be_retried } | ||
| .sort_by { |started| [timestamp_ms(started.timestamp), started.id] } |
There was a problem hiding this comment.
This doesn't look incredibly efficient. Wouldn't a comparator make more sense?
There was a problem hiding this comment.
<Matt's robot>
This code has moved into ResultOrder. I kept the decorate/sort/undecorate shape intentionally: it computes each order key exactly once, whereas a comparator would call the find_order_by query repeatedly during sorting. Happy to revisit if you prefer the comparator shape for consistency with another implementation.
</Matt's robot>
| @test_case_finished_by_test_case_started_id.values | ||
| .reject(&:will_be_retried) | ||
| .sort_by do |finished| | ||
| [timestamp_ms(finished.timestamp), |
There was a problem hiding this comment.
This doesn't look incredibly efficient. Wouldn't a comparator make more sense?
There was a problem hiding this comment.
<Matt's robot>
Same as the previous ordering thread: this now lives in ResultOrder, and the current approach avoids recomputing the sort key inside a comparator.
</Matt's robot>
| end | ||
|
|
||
| def update(envelope) | ||
| envelopes << envelope |
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: removed this guard. The indexer now assumes callers pass Cucumber::Messages::Envelope objects.
</Matt's robot>
|
|
||
| def update(envelope) | ||
| envelopes << envelope | ||
| return nil unless envelope.respond_to?(:meta) |
There was a problem hiding this comment.
Is this a type check of sorts? It should be true for any envelope, but at the same time doesn't tell you if an object is an envelope.
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: removed the respond_to?(:meta) envelope-ish type check and changed the unit spec to pass a real Cucumber::Messages::Envelope.
</Matt's robot>
| s.authors = ['Cucumber Limited'] | ||
| s.description = 'Given one Cucumber Message, find another' | ||
| s.summary = "cucumber-query-#{s.version}" | ||
| s.email = 'cukes@googlegroups.com' |
There was a problem hiding this comment.
Some fields look a bit bit out of date. 😉
There was a problem hiding this comment.
<Matt's robot>
Updated in f01d586: refreshed the gemspec author name, description, and metadata, including adding changelog_uri.
</Matt's robot>
There was a problem hiding this comment.
real Matt here: what are we supposed to use for those contact details?
There was a problem hiding this comment.
I updated it to use my name and hello@cucumber.io
|
🤖 Matt's robot here — thanks for the review. I've updated the PR description to follow the template and make the motivation/provenance clearer. I also pushed 40021d5 to simplify |
|
Actual Matt here! — totally LLM driven @mpkorstanje! Thanks for taking the time to read through it and review. I'll work through all your comments. |
5188d5f to
610c8cb
Compare
|
|
||
| Because Cucumber Messages refer to related data by id, feed the complete stream | ||
| to the query when possible. If a formatter asks for a pickle before the | ||
| corresponding `pickle` message has been seen, the lookup will return `nil`. |
There was a problem hiding this comment.
On this, it would be good to update the table in https://github.com/cucumber/query/blob/main/CONTRIBUTING.md#types, this gives good hints for when somebody wants to add a new method across languages.
There was a problem hiding this comment.
So, like, an additional column for Ruby with T | nil, Array and Hash?
|
Slop. |
🤔 What's changed?
🤖 Matt's robot here — this PR adds a Ruby implementation of cucumber-query under
ruby/:cucumber-querygem scaffold with README, gemspec, Rake, RSpec and RuboCop wiringCucumber::Query::QueryAPI that consumes Cucumber Messages envelopes and indexes the message stream⚡️ What's your motivation?
The Ruby pretty-formatter implementation needs a Ruby cucumber-query package instead of building a private query layer inside the formatter. This PR provides that dependency so Ruby formatters can consume the same message stream model as the other Cucumber implementations.
The implementation is deliberately scoped to the methods exercised by the shared testdata and the pretty-formatter branch. It should be extended from shared fixtures as new formatter/query needs appear.
🏷️ What kind of change is this?
♻️ Anything particular you want feedback on?
cucumber-queryrepository.Provenance note: this is not Luke's old skeleton branch. It was implemented for the Ruby pretty-formatter branch against the current
mainbranch, using the JavaScript implementation as the behavioural reference and the shared cucumber-query testdata as the executable contract.📋 Checklist: