Skip to content

Commit

Permalink
Merge branch 'check-whether-rspec-rails-is-used-via-gemfile'
Browse files Browse the repository at this point in the history
This closes #88.
  • Loading branch information
yujinakayama committed Dec 12, 2014
2 parents bd9c6e1 + a7662c2 commit 9d72abf
Show file tree
Hide file tree
Showing 30 changed files with 610 additions and 298 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ LineLength:
MethodLength:
Max: 17

ParameterLists:
Max: 6

CyclomaticComplexity:
Max: 8

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Development

* Check whether rspec-rails is used in the target project via `Gemfile.lock` when `-s/--skip-dynamic-analysis` option is specified. ([#88](https://github.com/yujinakayama/transpec/issues/88))

## v2.3.8

* Fix an error on processing one-liner `should` that is not directly enclosed in an example block. ([#93](https://github.com/yujinakayama/transpec/issues/93))
Expand Down
6 changes: 3 additions & 3 deletions lib/transpec/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def process(paths)
runtime_data = run_dynamic_analysis(paths)
end

spec_suite = SpecSuite.new(paths, runtime_data)
spec_suite = SpecSuite.new(project, paths, runtime_data)
# Actually #analyze does not need to be invoked here, but doing this will avoid long freeze
# while conversion of files.
puts 'Gathering the spec suite data...'
Expand All @@ -70,7 +70,7 @@ def run_dynamic_analysis(paths)

puts 'Copying the project for dynamic analysis...'

DynamicAnalyzer.new(rspec_command: config.rspec_command) do |analyzer|
DynamicAnalyzer.new(project: project, rspec_command: config.rspec_command) do |analyzer|
puts "Running dynamic analysis with command #{analyzer.rspec_command.inspect}..."
runtime_data = analyzer.analyze(paths)
end
Expand All @@ -83,7 +83,7 @@ def run_dynamic_analysis(paths)
def convert_spec(spec, spec_suite)
puts "Converting #{spec.path}"

converter = Converter.new(spec_suite, config, project.rspec_version)
converter = Converter.new(spec_suite, project, config)
converter.convert_file!(spec)

warn_annotations(converter.report)
Expand Down
18 changes: 11 additions & 7 deletions lib/transpec/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

require 'transpec/base_rewriter'
require 'transpec/config'
require 'transpec/project'
require 'transpec/report'
require 'transpec/rspec_version'
require 'transpec/spec_suite'
require 'transpec/syntax'

Expand All @@ -13,29 +13,33 @@ module Transpec
class Converter < BaseRewriter # rubocop:disable ClassLength
include Syntax::Dispatcher

attr_reader :spec_suite, :config, :rspec_version, :report
attr_reader :spec_suite, :project, :config, :report

alias_method :convert_file!, :rewrite_file!
alias_method :convert_source, :rewrite_source
alias_method :convert, :rewrite

def initialize(spec_suite = nil, config = nil, rspec_version = nil)
def initialize(spec_suite = nil, project = nil, config = nil)
@spec_suite = spec_suite || SpecSuite.new
@project = project || Project.new
@config = config || Config.new
@rspec_version = rspec_version || Transpec.required_rspec_version
@report = Report.new
end

def runtime_data
spec_suite.runtime_data
end

def rspec_version
project.rspec_version
end

def process(ast, source_rewriter)
return unless ast

ast.each_node do |node|
begin
dispatch_node(node, source_rewriter, runtime_data, report)
dispatch_node(node, runtime_data, project, source_rewriter, report)
rescue ConversionError => error
report.conversion_errors << error
end
Expand Down Expand Up @@ -88,7 +92,7 @@ def process_method_stub(method_stub)
if !method_stub.hash_arg? ||
rspec_version.receive_messages_available? ||
config.convert_stub_with_hash_to_allow_to_receive_and_return?
method_stub.allowize!(rspec_version)
method_stub.allowize!
elsif config.convert_deprecated_method?
method_stub.convert_deprecated_method!
end
Expand Down Expand Up @@ -166,7 +170,7 @@ def process_example_group(example_group)

def process_rspec_configure(rspec_configure)
if config.convert_deprecated_method?
rspec_configure.convert_deprecated_options!(rspec_version)
rspec_configure.convert_deprecated_options!
end

if spec_suite.main_rspec_configure_node?(rspec_configure.node)
Expand Down
4 changes: 2 additions & 2 deletions lib/transpec/dynamic_analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def initialize(options = {})
end

def default_rspec_command
if project.require_bundler?
if project.using_bundler?
'bundle exec rspec'
else
'rspec'
Expand Down Expand Up @@ -76,7 +76,7 @@ def run_rspec(paths)
def rewrite_specs(paths)
rewriter = Rewriter.new

spec_suite = SpecSuite.new(paths)
spec_suite = SpecSuite.new(project, paths)

spec_suite.specs.each do |spec|
next if spec.error
Expand Down
23 changes: 18 additions & 5 deletions lib/transpec/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,26 @@ def basename
File.basename(path)
end

def require_bundler?
gemfile_path = File.join(path, 'Gemfile')
File.exist?(gemfile_path)
def using_bundler?
File.exist?(gemfile_lock_path)
end

def depend_on_rspec_rails?
return @depend_on_rspec_rails if instance_variable_defined?(:@depend_on_rspec_rails)
return @depend_on_rspec_rails = false unless using_bundler?

require 'bundler'
gemfile_lock_content = File.read(gemfile_lock_path)
lockfile = Bundler::LockfileParser.new(gemfile_lock_content)
@depend_on_rspec_rails = lockfile.specs.any? { |gem| gem.name == 'rspec-rails' }
end

def rspec_version
@rspec_version ||= RSpecVersion.new(fetch_rspec_version)
end

def with_bundler_clean_env
if defined?(Bundler) && require_bundler?
if defined?(Bundler) && using_bundler?
Bundler.with_clean_env do
# Bundler.with_clean_env cleans environment variables
# which are set after bundler is loaded.
Expand All @@ -38,9 +47,13 @@ def with_bundler_clean_env

private

def gemfile_lock_path
@gemfile_lock_path ||= File.join(path, 'Gemfile.lock')
end

def fetch_rspec_version
command = 'rspec --version'
command = 'bundle exec ' + command if require_bundler?
command = 'bundle exec ' + command if using_bundler?

output = nil

Expand Down
15 changes: 9 additions & 6 deletions lib/transpec/spec_suite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ module Transpec
class SpecSuite
include Syntax::Dispatcher

attr_reader :runtime_data
attr_reader :project, :target_paths, :runtime_data

def initialize(base_paths = [], runtime_data = nil)
@base_paths = base_paths
def initialize(project = Project.new, target_paths = [], runtime_data = nil)
@project = project
@target_paths = target_paths
@runtime_data = runtime_data
@analyzed = false
end

def specs
@specs ||= SpecFileFinder.find(@base_paths).map do |path|
ProcessedSource.from_file(path)
@specs ||= Dir.chdir(project.path) do
SpecFileFinder.find(target_paths).map do |path|
ProcessedSource.from_file(path)
end
end
end

Expand All @@ -30,7 +33,7 @@ def analyze
specs.each do |spec|
next unless spec.ast
spec.ast.each_node do |node|
dispatch_node(node, nil, runtime_data)
dispatch_node(node, runtime_data, project)
end
end

Expand Down
18 changes: 13 additions & 5 deletions lib/transpec/syntax.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'transpec/conversion_error'
require 'transpec/dynamic_analyzer/runtime_data'
require 'transpec/project'
require 'transpec/record'
require 'transpec/report'
require 'transpec/static_context_inspector'
Expand Down Expand Up @@ -53,12 +54,14 @@ def snake_case_name(module_name)
module Transpec
class Syntax
module Dispatcher
def dispatch_node(node, source_rewriter = nil, runtime_data = nil, report = nil)
# rubocop:disable LineLength
def dispatch_node(node, runtime_data = nil, project = nil, source_rewriter = nil, report = nil)
Syntax.standalone_syntaxes.find do |syntax_class|
syntax = syntax_class.new(node, source_rewriter, runtime_data, report)
syntax = syntax_class.new(node, runtime_data, project, source_rewriter, report)
dispatch_syntax(syntax)
end
end
# rubocop:enable LineLength

def dispatch_syntax(syntax)
return false unless syntax.conversion_target?
Expand Down Expand Up @@ -145,7 +148,7 @@ class Syntax
extend Collection
include Rewritable, DynamicAnalysis

attr_reader :node, :source_rewriter, :runtime_data, :report
attr_reader :node, :runtime_data, :project, :source_rewriter, :report

def self.standalone?
true
Expand All @@ -155,10 +158,11 @@ def self.snake_case_name
@snake_cake_name ||= ModuleUtil.snake_case_name(name)
end

def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
def initialize(node, runtime_data = nil, project = nil, source_rewriter = nil, report = nil)
@node = node
@source_rewriter = source_rewriter
@runtime_data = runtime_data || DynamicAnalyzer::RuntimeData.new
@project = project || Project.new
@source_rewriter = source_rewriter
@report = report || Report.new
end

Expand Down Expand Up @@ -186,6 +190,10 @@ def expression_range
node.loc.expression
end

def rspec_version
project.rspec_version
end

def inspect
"#<#{self.class}: #{node.type}>"
end
Expand Down
2 changes: 1 addition & 1 deletion lib/transpec/syntax/method_stub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def unstub?
[:unstub, :unstub!].include?(method_name)
end

def allowize!(rspec_version)
def allowize!
return if method_name == :stub_chain && !rspec_version.receive_message_chain_available?

unless allow_to_receive_available?
Expand Down
4 changes: 3 additions & 1 deletion lib/transpec/syntax/mixin/matcher_owner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def add_matcher(matcher_class)

define_method(accessor) do
return instance_variable_get(ivar) if instance_variable_defined?(ivar)
matcher = matcher_class.new(matcher_node, self, source_rewriter, runtime_data, report)
matcher = matcher_class.new(
matcher_node, self, runtime_data, project, source_rewriter, report
)
instance_variable_set(ivar, matcher)
end

Expand Down
6 changes: 4 additions & 2 deletions lib/transpec/syntax/mixin/owned_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ def standalone?
end
end

def initialize(node, expectation, source_rewriter = nil, runtime_data = nil, report = nil)
super(node, source_rewriter, runtime_data, report)
# rubocop:disable LineLength
def initialize(node, expectation, runtime_data = nil, project = nil, source_rewriter = nil, report = nil)
super(node, runtime_data, project, source_rewriter, report)
@expectation = expectation
end
# rubocop:enable LineLength
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/transpec/syntax/mixin/rspec_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def rspec_rails?
if runtime_data.present?(node, :rspec_rails?)
runtime_data[node, :rspec_rails?]
else
true
project.depend_on_rspec_rails?
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/transpec/syntax/oneliner_should.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def example

found = Syntax.all_syntaxes.find do |syntax_class|
next unless syntax_class.ancestors.include?(Mixin::Examplish)
syntax = syntax_class.new(send_node, source_rewriter, runtime_data)
syntax = syntax_class.new(send_node, runtime_data, project, source_rewriter)
next unless syntax.conversion_target?
@example = syntax
end
Expand Down
6 changes: 4 additions & 2 deletions lib/transpec/syntax/operator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ class Operator < Syntax
end
end

def initialize(node, expectation, source_rewriter = nil, runtime_data = nil, report = nil)
def initialize(*args)
node = args.shift

operator_node = if node == BE_NODE
node.parent
else
node
end

super(operator_node, expectation, source_rewriter, runtime_data, report)
super(operator_node, *args)
end

def dynamic_analysis_target?
Expand Down
2 changes: 1 addition & 1 deletion lib/transpec/syntax/rspec_configure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def infer_spec_type_from_file_location?
!find_config_node(:infer_spec_type_from_file_location!).nil?
end

def convert_deprecated_options!(rspec_version) # rubocop:disable MethodLength
def convert_deprecated_options! # rubocop:disable MethodLength
replace_config!(:backtrace_clean_patterns, :backtrace_exclusion_patterns)
replace_config!(:backtrace_clean_patterns=, :backtrace_exclusion_patterns=)
replace_config!(:color_enabled=, :color=)
Expand Down
7 changes: 6 additions & 1 deletion spec/support/shared_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

# Include 'dynamic analysis objects' after this context so that this nil will be overridden.
let(:runtime_data) { nil }

let(:project) do
require 'transpec/project'
Transpec::Project.new
end
end

# This context requires `source` to be defined with #let.
Expand Down Expand Up @@ -49,7 +54,7 @@
shared_context 'syntax object' do |syntax_class, name|
let(name) do
ast.each_node do |node|
syntax = syntax_class.new(node, source_rewriter, runtime_data)
syntax = syntax_class.new(node, runtime_data, project, source_rewriter)
return syntax if syntax.conversion_target?
end

Expand Down
Loading

0 comments on commit 9d72abf

Please sign in to comment.