Skip to content

Commit

Permalink
[Ruby] Split messages files per message type (#225)
Browse files Browse the repository at this point in the history
* Set minimum ruby to 2.7 and minimum rubygems to 3.2.3

* Remove ruby 2.6 and 2.7 from workflows - Add in ruby 3.3

* Update target rubocop version

* Update misc files

* Update to use latest CCK in testing

* Remove some gitignore files

* Spike of non-working code

* Spike of using both private and public methods

* Compare / contrast the two ways of performing the new cck path reference

* Working example for iterative checks on each item

* Use file exist to simplify code - Remove wildcards

* Update minimum deps for rake / rspec

* Fix up all gemspec cops

* Move towards a spec support structure to remove any oddities flagged by rubocop

* Remove duplicate dummy messages

* Split up composiite dummy message class into individual items

* Remove top level leaked fake class for utils testing

* Fix up some minor simple offenses for utils spec

* Slight update to check rubocop works and then regenerate autogenconfig

* Bump rubocop performance and rubocop rake to latest. Slight bump to rubocop / rubocop-rspec

* Fix up issue whereby error was being rescued incorrectly and was being stored without requirement

* Tidy up serialization formatting

* Ignore line length cop as it's un-enforceable

* Attempt to distinguish what are the actual objects in the acceptance tests

* Re-gen the autogen config using bundler to ensure correct version (For now)

* Set minimum ruby to 3.0

* Reduce line count of spec for acceptance as we just want a wrap/unwrap call

* Fix up typos and named subject issue in serialization spec

* Fix up a couple of spec support Lint/MissingSuper calls

* Simplify deserialization protocol into just a single class method which is extended

* underscore as a method isn't used in the utils implementation

* Remove underscore tests

* Simplify Utils to just be extended as class methods

* Utils aren't used in the deserialization protocol

* Move all serialization into the message proper as it's just a single module with 1 method used in 1 location

* Move the deserialization spec tests into message proper

Fix describe block as they're class methods not instance methods

* Remove utils class and place camelize inside the message proper

* Don't create an extra object

* Split id generator into individual class files

* AF: Style/SpecialGlobalVars

* Simplify serialization spec by not creating 10 different subjects

* AF: Gemspec/OrderedDependencies

* AF: Layout/EmptyLineAfterMagicComment

* Partial fix for the Layout/FirstArrayElementIndentation cop offenses

* AF: Layout/LeadingEmptyLines

* Re-generate todo file with May's marker - 50 offenses cleared with the gem upgrade and rubocop bump

* Fix rubocop error

* Alter UUID test to just check for a securerandom uuid and simplify the code

* Alter incrementing spec to only have 1 assertion line

* Move serialization into message model proper

* Fix up Layout cops after copying over serialization messages

* AF: Lint/ToJSON should allow optional discarded args

* In ruby 2.6+ #to_h permits a block assign so we can refine this code better

* Refine the compacting of the resultant hash in the message adhering to the Style/CollectionCompact rule

* AF: Style/SlicingWithRange

* Update tests to remove redundant failing ones and fix up some legacy named subject offenses

* Re-order and tidy up messages class

* Add super() call to each message generation - Should remedy Lint/MissingSuper cop offense

* Re-generate config

* Fix up args to JSONSchema generation to use Ruby 3.0+ idioms

* Fix up the Trailing Whitespace cop by fixing a generation bug

* AF: Lint/AmbiguousOperatorPrecedence

* Fix up RSpec/DescribedClass issue with ndjson spec

* Partial fix of RSpec/ExampleLength

* Alter the Enum generator enabling us to autofix Style/ClassAndModuleChildren

* AF: FrozenStringLiteral

* Remove redundant spec

* Configure and permit AllowedNames to also include  as a name and Exclusion lists to be merged

* Disable Style/AccessorGrouping

* Fix up namespacing issues when migrating tests

* Move some logic out into let/subject blocks

* Fix up auto-fix offenses in rubocop

* Remove frozen string literal pragma's whilst we haven't fixed up autogen

* Add new requirements pending migration to one class per file logic like in java/cpp

* Fix up line spacing in generic ruby file and begin to split file into constituent ones

* Move all helpers to helpers namespace

* Fix up tests and require path

* Rename confusingly named make targets

* Generate files in new way

* Leave leakage item on dtos file for now as it will serve well when we come to fix filename

* Add new generation logic to .generate-messages

* add new clean command

* Add new filename checking for template
Fix clean process not to remove helpers

* Alter generation to use snake cased names

* Re-generate files

* Remove extra line that's not needed

* Make inheritance from message simpler

* Alter enum generation to also make new unique files

* Add .from_h method to ruby.rb.erb template to begin process of removing redundant template

* Add enum generation to the generator script
Clean up all redundant strings

* Remove all trace to referencing the .dtos.rb file including using the now un-needed jsonschema template for the deserializers

* Remove all trace to referencing the .deserializers.rb file

* Fix up namespace for UUID

* Require all new messages when requiring one message

* Only add comma after properties that aren't final

* Remove un-required requirement now we are recursively loading items in

* Re-generate messages using new templates

* Remove duplicate comma on the if/elsif/else statement

* Add comma into correct spot in template

* Fixed mismatched comment style from template

* Fix frozen string literal pragmas in templates

* Enum template was assigning an un-needed index during iteration

* Re-generated messages

* Re-generate TODO file after minor fixes in templates

* AF: Style/StringConcatenation

* Manual fix for RSpec/ExampleLength

* AF: RSpec/DescribedClass£

* AF: Layout/SpaceInsideBlockBraces

* Remove duplicate files missed by bad merge conflict

* Re-generate TODO file owing to conflict clash

* Fix up RSpec/MultipleExpectations

* Disable ParameterLists cop as most messages will have 5+ properties

* Fix up RSpec/NestedGroups

* Ignore method length for same reason as parameter lists

* AF: Layout/EmptyLineAfterGuardClause

* Remove TODO file as we have < 10 offenses to fix now

* Ignore all generated files

* Switch from metric blanket overrides to generated code overrides

* Only ignore Metrics and Layout/LineLength for generated messages

* Fix up line length offenses in message class proper

* Fix up all remaining line length issues in the specs

* Fix up LineLength offenses by moving extraction of message out to a private sub method

* Update changelogs

* Slight update to some rubocop gems that don't affect signoff of rubocop conformance

* Accessor grouping should only be unenforceable in generated messages

* Update docs
  • Loading branch information
luke-hill authored Jun 13, 2024
1 parent 4a2c5fe commit 556259d
Show file tree
Hide file tree
Showing 91 changed files with 3,501 additions and 3,413 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Changed
- [Ruby] **Breaking change** Messages are now altered to be 1 message class per file ([#225](https://github.com/cucumber/messages/pull/225) [luke-hill](https://github.com/luke-hill))
- [Ruby] Updated minimum Ruby version to 3.0 ([#216](https://github.com/cucumber/messages/pull/216) [luke-hill](https://github.com/luke-hill))
- [Ruby] Use latest CCK conformance for signing off message releases ([#216](https://github.com/cucumber/messages/pull/216) [luke-hill](https://github.com/luke-hill))
- [Ruby] Tidied up around 80% of all of the rubocop `Layout` offenses (This included 2 minor alterations to the generator code) ([#217](https://github.com/cucumber/messages/pull/217) [luke-hill](https://github.com/luke-hill))
- [Ruby] Tidied up all remaining rubocop offenses (This included 2 minor alterations to the generator code) ([#217](https://github.com/cucumber/messages/pull/217) [#225](https://github.com/cucumber/messages/pull/225) [luke-hill](https://github.com/luke-hill))
- [Php] Permit both PHPUnit 10 and PHPUnit 11 ([#200](https://github.com/cucumber/messages/pull/200) [ciaranmcnulty](https://github.com/ciaranmcnulty))

### Fixed
Expand Down
23 changes: 11 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Some guidelines for making schema changes:
- Use the most appropriate data type
- Follow existing naming conventions (camelCase)
- Add new fields last to minimise impact on consuming code
- Probably don't add a new field as `required` - this will make the new code unable to read existing messages
- Don't add a new field as `required` - this will make the new code unable to read existing messages
- Ideally add a description to any new fields

If you need some advice, drop into the `#committers` channel on the [Cucumber Slack](https://cucumber.io/community#slack) and ask.
Expand All @@ -20,24 +20,23 @@ The code for various languages is generated from the JSON files. You can clean a
make clean-all generate-all
```

This requires various tooling to be installed on your computer, including Ruby and Node.js. If you're missing some of it, you might find it easier to run a Docker container that has everything:
Or you can alternative clean and generate code for just one language by cd'ing into that languages directory
and then running the following commands

```shell
docker run --volume $PWD:/app --user 1000 -it cucumber/cucumber-build:latest bash
cd ruby # Or another alternative
make clean generate
```

For Windows (Powershell):

```shell
docker run --volume ${PWD}:/app --user 1000 -it cucumber/cucumber-build:latest bash
```

You can then run the same command as noted previously.
This requires various tooling to be installed on your computer, including Ruby and Node.js.

### New files

If you're adding a new file to the `jsonschema` directory, you'll need to add a reference to it near the top of the `Makefile` at the root in order for it to be included in the code generation.
If you're adding a new file to the `jsonschema` directory, you'll need to add a reference to it near the top of the `Makefile`
at the root in order for it to be included in the code generation.

## Tests

Some of the language-specific directories contain some smoke tests to ensure (de)serialization, validation etc are working right. If you happen to change one of the messages that's constructed by these tests, you may need to update them. If you're not sure, raise a draft PR and see what happens in CI.
Some of the language-specific directories contain some smoke tests to ensure (de)serialization, validation etc
are working right. If you happen to change one of the messages that's constructed by these tests, you may
need to update them. If you're not sure, raise a draft PR and see what happens in CI.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ Cucumber needs to produce results in a machine-readable format so that other too

![messages-stream.svg](messages-stream.svg)

Historically, Cucumber has done this with the `json` and `junit` formatters.
These formats have several shortcomings that are addressed by Cucumber Messages.
Historically, Cucumber did this with the `json` and `junit` formatters.
These formats however, have several shortcomings that are now addressed by using Cucumber Messages.

The `json` formatter is now in maintenance mode for these implementations, and Messages is the preferred standard.
See [utilities](#utilities) for a list of tools that may help with backward and forward compatibility
Expand All @@ -78,15 +78,14 @@ of results.

### Lack of a schema

The JSON report does not have a formal schema. This has led to slightly inconsistent implementations
The JSON reporter does not have a formal schema. This has led to slightly inconsistent implementations
of the JSON formatter in various Cucumber implementations. Consumers of the JSON format have
to anticipate and detect these inconsistencies and try to cope with them.

### Limited information

The `junit` XML format can only contain very limited information such as test case name and status.
While there isn't an official schema for JUnit XML, there are a few defacto ones around, and they
are very limited.
While there isn't an official schema for JUnit XML, there are a few defacto ones around which are very limited.

The `json` format represents the following information:

Expand Down
10 changes: 6 additions & 4 deletions jsonschema/scripts/templates/ruby.enum.rb.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<%- @enums.each do |enum| -%>
<%= underscore(enum[:name]) %>.rb
# frozen_string_literal: true

<% @enums.each do |enum| -%>
# The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/jsonschema/scripts/codegen.rb]
module Cucumber
module Messages
class <%= enum[:name] %>
<%- enum[:values].each_with_index do |value, index| -%>
<%- enum[:values].each do |value| -%>
<%= enum_constant(value) %> = '<%= value %>'
<%- end -%>
end
end
end
<%= "\n" unless enum == @enums.last -%>
<%- end -%>
<% end -%>
39 changes: 33 additions & 6 deletions jsonschema/scripts/templates/ruby.rb.erb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
require 'cucumber/messages/message'
<%- @schemas.each do |key, schema| -%>
<%= underscore(class_name(key)) %>.rb
# frozen_string_literal: true

# The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/jsonschema/scripts/codegen.rb]
#

module Cucumber
module Messages
<%- @schemas.each do |key, schema| %>
##
# Represents the <%= class_name(key) %> message in Cucumber's {message protocol}[https://github.com/cucumber/messages].
##
<%= "#\n " if schema['description'] %><%= format_description(schema['description']) %>
class <%= class_name(key) %> < ::Cucumber::Messages::Message
class <%= class_name(key) %> < Message
<%- schema['properties'].each do |property_name, property| -%>
<%- if property['description'] -%>
##
Expand All @@ -30,7 +30,34 @@ module Cucumber
<%- end -%>
super()
end

##
# Returns a new <%= class_name(key) %> from the given hash.
# If the hash keys are camelCased, they are properly assigned to the
# corresponding snake_cased attributes.
#
# Cucumber::Messages::<%= class_name(key) %>.from_h(some_hash) # => #<Cucumber::Messages::<%= class_name(key) %>:0x... ...>
##
def self.from_h(hash)
return nil if hash.nil?

new(
<%-
schema['properties'].each do |property_name, property|
ref = property['$ref']
items_ref = property.dig('items', '$ref')
-%>
<%- final_key = property_name == schema['properties'].keys.last -%>
<%- comma = final_key ? '' : ',' -%>
<%= "#{underscore(property_name)}: " -%>
<%- if items_ref -%>hash[:<%= property_name -%>]&.map { |item| <%= class_name(items_ref) %>.from_h(item) }<%= comma %>
<%- elsif ref -%><%= class_name(ref) %>.from_h(hash[:<%= property_name %>])<%= comma %>
<%- else -%>hash[:<%= property_name %>]<%= comma %>
<%- end -%>
<%- end -%>
)
end
end
<%- end -%>
end
end
<% end -%>
40 changes: 0 additions & 40 deletions jsonschema/scripts/templates/ruby_deserializers.rb.erb

This file was deleted.

16 changes: 11 additions & 5 deletions ruby/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
inherit_from: .rubocop_todo.yml

inherit_mode:
merge:
- Exclude
Expand All @@ -17,9 +15,16 @@ AllCops:
Gemspec/RequireMFA:
Enabled: false

# Some long comments in the JSON Schema cause this to be un-enforceable
# Generated messages (including the Envelope) aren't tested by the Metrics department because they have many
# input properties for #initialize and .from_h which are generated 1-per-line. This renders most Metrics redundant
Metrics:
Exclude:
- lib/cucumber/messages/*.rb

# Long comments in the generated messages from the JSON Schemas cause this to be un-enforceable
Layout/LineLength:
Max: 1000
Exclude:
- lib/cucumber/messages/*.rb

Naming/MethodParameterName:
AllowedNames:
Expand All @@ -31,7 +36,8 @@ RSpec/MessageSpies:
# Because of the nature of large amounts of Accessors, we disable this cop
# This is because many of them will have custom documentation which are auto-generated from the jsonschema
Style/AccessorGrouping:
Enabled: false
Exclude:
- lib/cucumber/messages/*.rb

Style/Documentation:
Enabled: false
Expand Down
145 changes: 0 additions & 145 deletions ruby/.rubocop_todo.yml

This file was deleted.

Loading

0 comments on commit 556259d

Please sign in to comment.