The RSpec syntax converter
Transpec is a tool for converting your specs to the latest RSpec syntax with static and dynamic code analysis.
With Transpec you can upgrade your RSpec 2 specs to RSpec 3 in no time.
It supports conversions for almost all of the RSpec 3 changes – not only the expect syntax.
Also, you can use it on your RSpec 2 project even if you're not going to upgrade it to RSpec 3 for now.
Check out the following posts for the new RSpec syntax and the changes in RSpec 3:
If you are going to use Transpec in the upgrade process to RSpec 3, read the RSpec official guide:
Here's an example spec:
…Transpec would convert it to the following form:
…You can see actual conversion examples below:
Simply install transpec with gem command:
$ gem install transpecNormally you don't need to add transpec to your Gemfile or *.gemspec since this isn't a tool to be used daily.
Before converting your specs:
rspec gem dependency 2.14 or later. If not, change your Gemfile or *.gemspec to do so.rspec and check if all the specs pass.Then, run transpec in the project root directory:
$ cd some-project
$ transpecThis will run the specs, convert them, and overwrite all spec files in the spec directory.
After the conversion, run rspec again and check whether everything is still green:
$ bundle exec rspecIf it's green, commit the changes with an auto-generated message that describes the conversion summary and helps your team members to understand the new syntax:
$ git commit -aeF .git/COMMIT_EDITMSGAnd you are done!
You can pass transpec arbitrary paths to convert:
# You always need to be in the project root directory
$ cd some-project
# Convert only files in `features` directory
$ transpec features
# Convert only files in `spec/foo` and `spec/bar` directory
$ transpec spec/foo spec/bar
# Convert only `spec/baz_spec.rb`
$ transpec spec/baz_spec.rbNote that the current working directory always needs to be the project root directory, so that Transpec can know where the root is.
You can disable specific conversions that are enabled by default with -k/--keep option,
and enable conversions that are disabled by default with the -v/--convert option.
If you are willing to try the latest and modern syntax, run the following on RSpec 3:
$ transpec --convert example_group,hook_scopeSee -k/--keep and -v/--convert for more details.
Though Transpec ships with sensible defaults that essentially conform to the RSpec 3 defaults, you can customize the conversion behavior.
-f/--forceForce processing even if the current Git repository is not clean.
$ git status --short
M spec/spec_helper.rb
$ transpec
The current Git repository is not clean. Aborting. If you want to proceed forcibly, use -f/--force option.
$ transpec --force
Copying project for dynamic analysis...
Running dynamic analysis with command "bundle exec rspec"...-c/--rspec-commandSpecify a command to run your specs which is used for dynamic analysis.
Transpec needs to run your specs in a copied project directory for dynamic analysis.
If your project requires some special setup or commands to run specs, use this option.
bundle exec rspec is used by default.
Note that the command to run dynamic analysis does not affect to the files or specs to be converted.
This means that even if you specify a command that only runs a subset of the files in your spec suite or a subset of the specs in a file, every spec will be converted.
For this reason, it's recommended to provide a command that runs full spec suite to -c/--rspec-command.
If you want to convert only a subset of the files in a spec suite, pass the paths to transpec.
See Advanced Usage for more details.
You can change the temporary directory that the your project will be copied
by specifying the TMPDIR environment variable.
$ transpec --rspec-command "./special_setup.sh && bundle exec rspec"-k/--keepKeep specific syntaxes by disabling conversions.
$ transpec --keep should_receive,stubNote that some syntaxes are available only if your project's RSpec is specific version or later. If they are unavailable, conversions for such syntaxes will be disabled automatically.
| Type | Target Syntax | Converted Syntax |
|---|---|---|
should |
obj.should matcher |
expect(obj).to matcher |
oneliner |
it { should ... } |
it { is_expected.to ... } |
should_receive |
obj.should_receive(:message) |
expect(obj).to receive(:message) |
stub |
obj.stub(:message) |
allow(obj).to receive(:message) |
have_items |
expect(obj).to have(n).items |
expect(obj.size).to eq(n) |
its |
its(:attr) { } |
describe '#attr' { subject { }; it { } } |
pending |
pending 'is an example' { } |
skip 'is an example' { } |
deprecated |
All other deprecated syntaxes | Latest syntaxes |
See Supported Conversions for more details.
-v/--convertEnable specific conversions that are disabled by default.
$ transpec --convert example_groupMost of these target syntaxes are not deprecated in both RSpec 2 and 3, but the new syntaxes provide more modern and clear ways.
| Type | Target Syntax | Converted Syntax |
|---|---|---|
example_group |
describe 'something' { } |
RSpec.describe 'something' { } |
hook_scope |
before(:all) { } |
before(:context) { } |
stub_with_hash |
obj.stub(:message => value) |
allow(obj).to receive(:message).and_return(value) |
Note: Specifying stub_with_hash enables conversion of obj.stub(:message => value)
to allow(obj).to receive(:message).and_return(value)
when allow(obj).to receive_messages(:message => value) is unavailable (prior to RSpec 3.0),
and it will be converted to multiple statements if the hash includes multiple pairs.
If your project's RSpec is 3.0 or later, it will be converted to receive_messages(:message => value)
regardless of this option.
See Supported Conversions - Method stubs with a hash argument for more details.
-o/--convert-onlyConvert specific syntaxes while keeping all other syntaxes.
This option would be useful when you want to convert a non-deprecated syntax
while keeping another syntax that would be converted by default.
(e.g. converting the hook scope aliases while keeping the one-liner should).
$ transpec --convert-only example_group,hook_scope-s/--skip-dynamic-analysisSkip dynamic analysis and convert with only static analysis. The use of this option is basically discouraged since it significantly decreases the overall conversion accuracy.
This would be useful only if your spec suite takes really long (like an hour) to run and you prefer a combination of the rough but fast conversion by Transpec and manual fixes after that.
-n/--negative-formSpecify a negative form of to which is used in the expect syntax.
Either not_to or to_not.
not_to is used by default.
$ transpec --negative-form to_not-b/--boolean-matcherSpecify a boolean matcher type which be_true and be_false will be converted to.
Any of truthy,falsey, truthy,falsy or true,false can be specified.
truthy,falsey is used by default.
$ transpec --boolean-matcher true,falseSee Supported Conversions - Boolean matchers for more details.
-e/--explicit-spec-typeAdd explicit spec :type metadata to example groups in a project using rspec-rails.
See Supported Conversions - Implicit spec types in rspec-rails for more details.
-a/--no-yield-any-instanceSuppress yielding receiver instances to any_instance implementation blocks as the first block argument.
By default in RSpec 3, any_instance implementation blocks will be yielded the receiving
instance as the first block argument, and by default Transpec converts specs by adding instance arguments to the blocks so that they conform to the behavior of RSpec 3.
Specifying this option suppresses the conversion and keeps them compatible with RSpec 2.
Note that this is not same as --keep deprecated since this configures yield_receiver_to_any_instance_implementation_blocks with RSpec.configure.
See Supported Conversions - any_instance implementation blocks for more details.
-p/--no-parens-matcher-argSuppress parenthesizing arguments of matchers when converting
should with operator matcher to expect with non-operator matcher
(the expect syntax does not directly support the operator matchers).
Note that it will be parenthesized even if this option is specified
when parentheses are necessary to keep the meaning of the expression.
…You might see the following warning while conversion:
Cannot convert #should into #expect since #expect is not available in the context.
spec/awesome_spec.rb:4: 1.should == 1This message would be shown with specs like:
describe '#should that cannot be converted to #expect' do
class MyAwesomeTestRunner
def run
1.should == 1
end
end
it 'is 1' do
test_runner = MyAwesomeTestRunner.new
test_runner.run
end
endshould is defined on BasicObject class, so you can use should everywhere.expect is defined on RSpec::Matchers module which is included by RSpec::Core::ExampleGroup class, so you can use expect only where self is an instance of RSpec::Core::ExampleGroup (i.e. in it blocks, :each hook blocks or included module methods) or other classes that explicitly include RSpec::Matchers.With the above example, in the context of 1.should == 1, the self is an instance of MyAwesomeTestRunner.
Transpec tracks contexts and skips conversion if the syntax cannot be converted in a case like this.
Include or extend any of the following module to make RSpec syntax available in the context:
RSpec::Matchers for expect(obj).to some_matcherRSpec::Mocks::ExampleMethods for expect/allow(obj).to receive(:message) class MyAwesomeTestRunner
include RSpec::Matchers
def run
1.should == 1
end
endThen run transpec again.
shouldThere are two types of should:
describe 'the monkey-patched should' do
subject { [] }
it 'is empty' do
subject.should be_empty
# ^^^^^^ BasicObject#should in RSNo open issues yet, or sync has not completed.