RSpec::RfcHelper

RSpec RFC Helper is a RSpec module to help tracking implementation of big specifications, when having only comments in code or tests becomes too tedious to maintain and follow.

Installation

Add the gem to your Gemfile:

gem 'rspec-rfc-helper'

Usage

  1. Write the specs: read the RFC/specifications that needs to be implemented and extract everything that has to be implemented. This is tedious.
  2. Use the gem in Rspec
  3. Sprinkle your tests to reference the specs
  4. Run the tests
  5. Open the report

Writing specs

...in a YAML file

Specs in a YAML file can be loaded easily when integrated in RSpec; the format is simple:

# Optional, the specification/RFC name
name: 
# Optional, the URL to the RFC/specification
url:
# Here we are
specs:
  # You should at least have one section in the file
  #
  # Required. Section/chapter... It's converted to a string when imported
  - section: 1
    # Required. Unique section identifier. IDs of the specs in this section will be prefixed by it. Converted to symbol
    # so only the character class used for symbols should be used.
    id:
    # Optional: URL to the section
    url:
    specs:
      # Optional. A spec without an ID will appear with an "unknown" status in the report. It allows you to fill the
      # specs list without thinking right now how you will identify it.
      # Spec IDS must be unique across all the specs, but are automatically prefixed with the section's ID, which allows
      # definition of two specs with the same ID over different sections.
      - id:
        # Required. Text must be unique across specs. Imperative verbs have to be bracketed, so you can use the same paragraph
        # in multiple specs, targeting something different without losing context.
        text: It [[MUST]] work

For more example, there is a fixture in spec/fixtures/rfc.yaml, and the example spec file in spec/rfc.yaml.

...programmatically

Declaring specs programmatically can be interesting if you manage somehow to process the original specification automatically.

# Create an instance of the Specs class: it holds the specs. "name" and "url" are optional
specs = RSpec::RfcHelper::Specs.new name: 'The easy thing RFC', url: 'https://somewhere'

# Create a section
spec.add_section number: '1.1', title: 'Implementation', id: :implementation

# Add a spec:
# ID is optional. A spec without an ID will appear with an "unknown" status in the report. It allows you to fill the
# specs list without thinking right now how you will identify it.
# Spec IDS must be unique across all the specs, but are automatically prefixed with the section's ID, which allows
# definition of two specs with the same ID over different sections.
#
# Here, spec ID will be :implementation__do_something
spec.add section: '1.1', text: 'It [[MUST]] do something', id: :do_something

# For long texts, use heredocs:
spec.add section: '1.1', text: <<~TXT, id: :do_something
  Some long text, but the context is important to understand
  what you [[MUST]] implement, how you SHOULD do it
  and what you MAY do if you feel like it
TXT

Usage in RSpec

...with the spec file: use the module

# spec_helper.rb

require 'rspec/rfc-helper'

RSpec.configure do |config|
  config.before(:suite) do
    RSpec::RfcHelper.start_from_file 'path/to/your/spec.yaml'
  end

  config.after do |example|
    RSpec::RfcHelper.add_example example
  end

  config.after( :suite) do
    RSpec::RfcHelper.save_markdown_report 'path/to/report.md'
  end
end

...programmatically: use the classes

# spec_helper.rb

require 'rspec-rfc-helper'

RSpec.configure do |config|
  # Putting all the specs in the spec_helper.rb is not a good idea, but as you go programmatically, i'll let you find
  # a way to organize yourself better.
  # The main point here is to use the same instance for the definitions and the usages in the RSpec hooks
  rfc_helper = RSpec::RfcHelper::Spec.new name: 'Plumbus management', url: 'https://somewhere'
  rfc_helper.add_section #...
  rfc_helper.add #...
  # Alternatively, you can still load a file
  rfc_helper = RSpec::RfcHelper::Spec.new_from_file 'path_to_file'

  config.after do |example|
    rfc_helper.add_example example
  end

  config.after( :suite) do
    rfc_helper.save_markdown_report 'path/to/report.md'
  end
end

Reference the specs in your suite

RFC Helper uses the RSpec tagging system to track and assign examples to specs.

RSpec.describe 'Something' do
  # references spec "spec_id" in section "section1"
  it 'works', rfc: :section1__spec_id do
    # ...
  end

  # references spec "spec_id" in section "section1", and "other_spec_id" in "other_section"
  it 'works', rfc: [:section1__spec_id, :other_section__other_spec_id] do
    # ...
  end
end

Development

After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Tools

Well, we use RSpec for testing.

Also, we use Rubocop for code style.

Contributing

All contributions, ideas and discussions are welcome. Feel free to open issues and feature requests on the bug tracker.

You also can join the ExperimentsLabs Matrix chatroom to discuss of the project.