transpec 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a3e260298c65e466e7a7460347e7f30c0a21756
4
- data.tar.gz: 2c1638289bf22ca3478ffe62c22419451ffe4dcd
3
+ metadata.gz: 007748d38ffe681cd54d6fb29dd4da70bffccf38
4
+ data.tar.gz: 5b5a23a5033dbcbfec53203adb25ced1cd416a26
5
5
  SHA512:
6
- metadata.gz: cf8a5e86460c68c9a5de1148dadab3af4edc88d775992e49069de3f17f689ececc22494c2e9c0ae52f5d4c73813c3d5beb3b7324faed94cd9163f0406d513e63
7
- data.tar.gz: a0b827f6aa1aa0101a459440f2325f362509e6a8c5de0e88c741c93482ecb005d539ac2e61ee0312023ac6a6836589792d29de5f95b4bae616be917fca7b555a
6
+ metadata.gz: 64b41185ba3851b1597ac8c4698674ff92d5b4111169d8f9d3ac2f5afe6a101ceeda41c3cea2c62042f936397b85afb7e8d669868ccd67e0af7db8868d29df2b
7
+ data.tar.gz: 65a49706d64224c8f6f4421b6db6def9f2e727ff01e04b82ec9f2240e21c0ef75903a63b355850235e5522ba1f5beb1c3b16710af507205cf49b6e27a6c25712
@@ -1,5 +1,7 @@
1
1
 
2
2
  AllCops:
3
+ Includes:
4
+ - tasks/*.rake
3
5
  Excludes:
4
6
  - tmp/*
5
7
 
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Master
4
4
 
5
+ ## v0.1.3
6
+
7
+ * Avoid confusing `Excon.stub` with RSpec's `stub` ([#4](https://github.com/yujinakayama/transpec/issues/4))
8
+ * Fix a bug where `be == 1` was converted into `be eq(1)` (now it's converted into `eq(1)`)
9
+ * Fix a bug where `obj.should==1` was converted into `obj.toeq1` (now it's converted into `obj.to eq(1)`)
10
+
5
11
  ## v0.1.2
6
12
 
7
13
  * Continue processing files even if a file has invalid syntax
data/Guardfile CHANGED
@@ -10,6 +10,7 @@ end
10
10
 
11
11
  guard :rubocop do
12
12
  watch(%r{.+\.rb$})
13
+ watch(%r{.+\.rake$})
13
14
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
14
15
  end
15
16
 
data/Rakefile CHANGED
@@ -5,144 +5,8 @@ require 'rubocop/rake_task'
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
  Rubocop::RakeTask.new(:style)
7
7
 
8
- namespace :ci do
9
- desc "#{Rake::Task['spec'].comment} for CI environment"
10
- task :spec do
11
- ENV['CI'] = 'true'
12
-
13
- ENV['CI_REPORTS'] = 'spec/reports'
14
- require 'ci/reporter/rake/rspec'
15
- Rake::Task['ci:setup:rspec'].invoke
16
-
17
- Rake::Task['spec'].invoke
18
- end
19
- end
20
-
21
- desc 'Generate README.md'
22
- task :readme do
23
- require 'erb'
24
- require 'transpec/cli'
25
-
26
- gem_specification = Gem::Specification.load('transpec.gemspec')
27
- rspec_dependency = gem_specification.dependencies.find { |d| d.name == 'rspec' }
28
- rspec_requirement = rspec_dependency.requirement
29
- rspec_version = rspec_requirement.requirements.first.find { |r| r.is_a?(Gem::Version) }
30
-
31
- erb = ERB.new(File.read('README.md.erb'), nil, '-')
32
- content = erb.result(binding)
33
- File.write('README.md', content)
34
- end
35
-
36
- task :abort_unless_latest_readme_is_committed => :readme do
37
- unless Transpec::Git.clean?
38
- warn 'Commit README.md before release.'
39
- exit 1
40
- end
41
- end
42
-
43
- Rake::Task[:release].enhance([:abort_unless_latest_readme_is_committed])
44
-
45
- namespace :test do
46
- projects = [
47
- [:twitter, 'https://github.com/sferik/twitter.git', 'v4.1.0'],
48
- [:guard, 'https://github.com/yujinakayama/guard.git', 'transpec', %w(--without development)],
49
- [:mail, 'https://github.com/yujinakayama/mail.git', 'transpec']
50
- ]
51
-
52
- desc 'Test Transpec on all projects'
53
- task :all => projects.map(&:first)
54
-
55
- projects.each do |name, url, ref, bundler_args|
56
- desc "Test Transpec on #{name.to_s.capitalize} project"
57
- task name do
58
- tmpdir = File.join('tmp', 'projects')
59
-
60
- unless Dir.exist?(tmpdir)
61
- require 'fileutils'
62
- FileUtils.mkdir_p(tmpdir)
63
- end
64
-
65
- Dir.chdir(tmpdir) do
66
- test_on_project(name.to_s.capitalize, url, ref, bundler_args)
67
- end
68
- end
69
- end
70
-
71
- def test_on_project(name, url, ref, bundler_args = nil)
72
- require 'transpec'
73
-
74
- puts " Testing on #{name} Project ".center(80, '=')
75
-
76
- repo_dir = prepare_git_repo(url, ref)
77
-
78
- bundler_args ||= []
79
- # On Travis CI, reuse system gems to speed up build.
80
- bundler_args.concat(%w(--path vendor/bundle)) unless ENV['TRAVIS']
81
-
82
- Dir.chdir(repo_dir) do
83
- with_clean_bundler_env do
84
- sh 'bundle', 'install', *bundler_args
85
- sh File.join(Transpec.root, 'bin', 'transpec'), '--force'
86
- sh 'bundle exec rspec'
87
- end
88
- end
89
- end
90
-
91
- def prepare_git_repo(url, ref)
92
- repo_dir = File.basename(url, '.git')
93
-
94
- needs_clone = false
95
-
96
- if Dir.exist?(repo_dir)
97
- current_ref = nil
98
-
99
- Dir.chdir(repo_dir) do
100
- current_ref = `git describe --all`.chomp.sub(/\Aheads\//, '')
101
- end
102
-
103
- if current_ref == ref
104
- Dir.chdir(repo_dir) do
105
- sh 'git reset --hard'
106
- end
107
- else
108
- require 'fileutils'
109
- FileUtils.rm_rf(repo_dir)
110
- needs_clone = true
111
- end
112
- else
113
- needs_clone = true
114
- end
115
-
116
- if needs_clone
117
- # Disabling checkout here to suppress "detached HEAD" warning.
118
- sh "git clone --no-checkout --depth 1 --branch #{ref} #{url}"
119
-
120
- Dir.chdir(repo_dir) do
121
- sh "git checkout --quiet #{ref}"
122
- end
123
- end
124
-
125
- repo_dir
126
- end
127
-
128
- def with_clean_bundler_env
129
- if defined?(Bundler)
130
- Bundler.with_clean_env do
131
- # Bundler.with_clean_env cleans environment variables
132
- # which are set after bundler is loaded.
133
- prepare_env
134
- yield
135
- end
136
- else
137
- prepare_env
138
- yield
139
- end
140
- end
141
-
142
- def prepare_env
143
- # Disable Coveralls in other projects.
144
- ENV['CI'] = ENV['JENKINS_URL'] = ENV['COVERALLS_RUN_LOCALLY'] = nil
145
- end
8
+ Dir['tasks/**/*.rake'].each do |path|
9
+ load(path)
146
10
  end
147
11
 
148
12
  task default: [:spec, :style, :readme]
@@ -1,14 +1,9 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'transpec/ast/scope_stack'
4
- require 'parser'
5
-
6
3
  module Transpec
7
4
  module AST
8
5
  class Scanner
9
- SCOPE_TYPES = [:module, :class, :sclass, :def, :defs, :block].freeze
10
-
11
- attr_reader :scope_stack
6
+ attr_reader :context
12
7
 
13
8
  def self.scan(origin_node, &block)
14
9
  instance = new(&block)
@@ -19,7 +14,6 @@ module Transpec
19
14
  def initialize(&block)
20
15
  @callback = block
21
16
  @ancestor_nodes = []
22
- @scope_stack = ScopeStack.new
23
17
  end
24
18
 
25
19
  def scan(origin_node, yield_origin_node = false)
@@ -28,27 +22,19 @@ module Transpec
28
22
  yield_node(origin_node) if yield_origin_node
29
23
 
30
24
  @ancestor_nodes.push(origin_node)
31
- @scope_stack.push_scope(origin_node) if scope_node?(origin_node)
32
25
 
33
- origin_node.children.each_with_index do |child, index|
34
- next unless child.is_a?(Parser::AST::Node)
35
- node = child
36
- yield_node(node)
37
- scan(node)
26
+ origin_node.each_child_node do |child_node|
27
+ yield_node(child_node)
28
+ scan(child_node)
38
29
  end
39
30
 
40
- @scope_stack.pop_scope if scope_node?(origin_node)
41
31
  @ancestor_nodes.pop
42
32
  end
43
33
 
44
34
  private
45
35
 
46
36
  def yield_node(node)
47
- @callback.call(node, @ancestor_nodes, @scope_stack.in_example_group_context?)
48
- end
49
-
50
- def scope_node?(node)
51
- SCOPE_TYPES.include?(node.type)
37
+ @callback.call(node, @ancestor_nodes)
52
38
  end
53
39
  end
54
40
  end
@@ -0,0 +1,101 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/util'
4
+
5
+ module Transpec
6
+ class Context
7
+ include Util
8
+
9
+ SCOPE_TYPES = [:module, :class, :sclass, :def, :defs, :block].freeze
10
+
11
+ EXAMPLE_GROUP_METHOD_NAMES = [
12
+ :describe, :context,
13
+ :shared_examples, :shared_context, :share_examples_for, :shared_examples_for
14
+ ].freeze
15
+
16
+ attr_reader :nodes
17
+
18
+ # @param nodes [Array] An array containing from root node to the target node.
19
+ def initialize(nodes)
20
+ @nodes = nodes
21
+ end
22
+
23
+ def scopes
24
+ @scopes ||= begin
25
+ scopes = @nodes.map { |node| scope_type(node) }
26
+ scopes.compact
27
+ end
28
+ end
29
+
30
+ def in_example_group?
31
+ return @in_example_group if instance_variable_defined?(:@in_example_group)
32
+ @in_example_group = in_method_or_block_in_example_group? ||
33
+ in_method_or_block_in_rspec_configure? ||
34
+ in_method_in_module? ||
35
+ in_method_in_top_level?
36
+ end
37
+
38
+ private
39
+
40
+ def scope_type(node)
41
+ return nil unless SCOPE_TYPES.include?(node.type)
42
+ return node.type unless node.type == :block
43
+
44
+ send_node = node.children.first
45
+ receiver_node, method_name, *_ = *send_node
46
+
47
+ if const_name(receiver_node) == 'RSpec' && method_name == :configure
48
+ :rspec_configure
49
+ elsif receiver_node
50
+ node.type
51
+ elsif EXAMPLE_GROUP_METHOD_NAMES.include?(method_name)
52
+ :example_group
53
+ else
54
+ node.type
55
+ end
56
+ end
57
+
58
+ def in_method_or_block_in_example_group?
59
+ scopes_in_example_group = inner_scopes_of(:example_group)
60
+ return false unless scopes_in_example_group
61
+ return false if include_class_scope?(scopes_in_example_group)
62
+ include_method_or_block_scope?(scopes_in_example_group)
63
+ end
64
+
65
+ def in_method_or_block_in_rspec_configure?
66
+ scopes_in_rspec_configure = inner_scopes_of(:rspec_configure)
67
+ return false unless scopes_in_rspec_configure
68
+ return false if include_class_scope?(scopes_in_rspec_configure)
69
+ include_method_or_block_scope?(scopes_in_rspec_configure)
70
+ end
71
+
72
+ def in_method_in_module?
73
+ scopes_in_module = inner_scopes_of(:module)
74
+ return false unless scopes_in_module
75
+ return false if include_class_scope?(scopes_in_module)
76
+ scopes_in_module.include?(:def)
77
+ end
78
+
79
+ def in_method_in_top_level?
80
+ return false unless scopes.first == :def
81
+ scopes_in_method = scopes[1..-1]
82
+ !include_class_scope?(scopes_in_method)
83
+ end
84
+
85
+ def inner_scopes_of(scope_type)
86
+ index = scopes.rindex(scope_type)
87
+ return nil unless index
88
+ scopes[Range.new(index + 1, -1)]
89
+ end
90
+
91
+ def include_class_scope?(scopes)
92
+ !(scopes & [:class, :sclass]).empty?
93
+ end
94
+
95
+ def include_method_or_block_scope?(scopes)
96
+ # TODO: Should validate whether the method taking the block is RSpec's
97
+ # special method. (e.g. #subject, #let, #before, #after)
98
+ !(scopes & [:def, :block]).empty?
99
+ end
100
+ end
101
+ end
@@ -37,8 +37,8 @@ module Transpec
37
37
  failed_overlapping_rewrite = false
38
38
  @source_rewriter.diagnostics.consumer = proc { failed_overlapping_rewrite = true }
39
39
 
40
- AST::Scanner.scan(ast) do |node, ancestor_nodes, in_example_group_context|
41
- dispatch_node(node, ancestor_nodes, in_example_group_context)
40
+ AST::Scanner.scan(ast) do |node, ancestor_nodes|
41
+ dispatch_node(node, ancestor_nodes)
42
42
  end
43
43
 
44
44
  rewritten_source = @source_rewriter.process
@@ -64,14 +64,13 @@ module Transpec
64
64
  ast
65
65
  end
66
66
 
67
- def dispatch_node(node, ancestor_nodes, in_example_group_context)
67
+ def dispatch_node(node, ancestor_nodes)
68
68
  Syntax.all.each do |syntax_class|
69
69
  next unless syntax_class.target_node?(node)
70
70
 
71
71
  syntax = syntax_class.new(
72
72
  node,
73
73
  ancestor_nodes,
74
- in_example_group_context,
75
74
  @source_rewriter
76
75
  )
77
76
 
@@ -1,5 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'transpec/context'
4
+
3
5
  module Transpec
4
6
  class Syntax
5
7
  class NotInExampleGroupContextError < StandardError
@@ -22,8 +24,7 @@ module Transpec
22
24
  end
23
25
  end
24
26
 
25
- attr_reader :node, :ancestor_nodes, :in_example_group_context, :source_rewriter
26
- alias_method :in_example_group_context?, :in_example_group_context
27
+ attr_reader :node, :ancestor_nodes, :source_rewriter
27
28
 
28
29
  def self.all
29
30
  @subclasses ||= []
@@ -47,13 +48,16 @@ module Transpec
47
48
  target_method_names.include?(method_name)
48
49
  end
49
50
 
50
- def initialize(node, ancestor_nodes, in_example_group_context, source_rewriter)
51
+ def initialize(node, ancestor_nodes, source_rewriter)
51
52
  @node = node
52
53
  @ancestor_nodes = ancestor_nodes
53
- @in_example_group_context = in_example_group_context
54
54
  @source_rewriter = source_rewriter
55
55
  end
56
56
 
57
+ def context
58
+ @context ||= Context.new(@ancestor_nodes)
59
+ end
60
+
57
61
  def parent_node
58
62
  @ancestor_nodes.last
59
63
  end
@@ -13,67 +13,105 @@ module Transpec
13
13
  false
14
14
  end
15
15
 
16
- def initialize(node, in_example_group_context, source_rewriter)
16
+ def initialize(node, source_rewriter)
17
17
  @node = node
18
- @in_example_group_context = in_example_group_context
19
18
  @source_rewriter = source_rewriter
20
19
  end
21
20
 
22
21
  def correct_operator!(parenthesize_arg = true)
23
22
  case method_name
24
23
  when :==
25
- replace(selector_range, 'eq')
26
- parenthesize!(parenthesize_arg)
24
+ convert_to_eq!(parenthesize_arg)
27
25
  when :===, :<, :<=, :>, :>=
28
- return if prefixed_with_be?
29
- insert_before(selector_range, 'be ')
26
+ convert_to_be_operator!
30
27
  when :=~
31
- if arg_node.type == :array
32
- replace(selector_range, 'match_array')
33
- else
34
- replace(selector_range, 'match')
35
- end
36
- parenthesize!(parenthesize_arg)
28
+ convert_to_match!(parenthesize_arg)
37
29
  end
38
30
  end
39
31
 
40
32
  def parenthesize!(always = true)
41
33
  return if argument_is_here_document?
42
34
 
43
- case left_parenthesis_range.source
44
- when ' '
45
- if in_parentheses?(arg_node)
46
- remove(left_parenthesis_range)
47
- elsif always || arg_node.type == :hash
48
- replace(left_parenthesis_range, '(')
49
- insert_after(expression_range, ')')
50
- end
51
- when "\n", "\r"
52
- insert_before(left_parenthesis_range, '(')
53
- linefeed = left_parenthesis_range.source
54
- matcher_line_indentation = indentation_of_line(@node)
55
- right_parenthesis = "#{linefeed}#{matcher_line_indentation})"
56
- insert_after(expression_range, right_parenthesis)
35
+ left_of_arg_source = range_in_between_selector_and_arg.source
36
+
37
+ if left_of_arg_source.match(/\A *\Z/)
38
+ parenthesize_single_line!(always)
39
+ elsif left_of_arg_source.match(/\n|\r/)
40
+ parenthesize_multi_line!(Regexp.last_match(0))
57
41
  end
58
42
  end
59
43
 
60
44
  private
61
45
 
62
- def argument_is_here_document?
63
- here_document?(arg_node) ||
64
- arg_node.each_descendent_node.any? { |n| here_document?(n) }
46
+ def convert_to_eq!(parenthesize_arg)
47
+ handle_anterior_of_operator!
48
+ replace(selector_range, 'eq')
49
+ parenthesize!(parenthesize_arg)
50
+ end
51
+
52
+ def convert_to_be_operator!
53
+ return if prefixed_with_be?
54
+ insert_before(selector_range, 'be ')
55
+ end
56
+
57
+ def convert_to_match!(parenthesize_arg)
58
+ handle_anterior_of_operator!
59
+
60
+ if arg_node.type == :array
61
+ replace(selector_range, 'match_array')
62
+ else
63
+ replace(selector_range, 'match')
64
+ end
65
+
66
+ parenthesize!(parenthesize_arg)
67
+ end
68
+
69
+ def handle_anterior_of_operator!
70
+ if prefixed_with_be?
71
+ remove_be!
72
+ elsif range_in_between_receiver_and_selector.source.empty?
73
+ insert_before(selector_range, ' ')
74
+ end
75
+ end
76
+
77
+ def parenthesize_single_line!(always)
78
+ if in_parentheses?(arg_node)
79
+ remove(range_in_between_selector_and_arg)
80
+ elsif always || arg_node.type == :hash
81
+ replace(range_in_between_selector_and_arg, '(')
82
+ insert_after(expression_range, ')')
83
+ elsif range_in_between_selector_and_arg.source.empty?
84
+ insert_after(selector_range, ' ')
85
+ end
86
+ end
87
+
88
+ def parenthesize_multi_line!(linefeed)
89
+ insert_before(range_in_between_selector_and_arg, '(')
90
+ matcher_line_indentation = indentation_of_line(@node)
91
+ right_parenthesis = "#{linefeed}#{matcher_line_indentation})"
92
+ insert_after(expression_range, right_parenthesis)
65
93
  end
66
94
 
67
95
  def prefixed_with_be?
68
- receiver_node == s(:send, nil, :be)
96
+ !be_node.nil?
97
+ end
98
+
99
+ def remove_be!
100
+ be_range = be_node.loc.expression.join(selector_range.begin)
101
+ remove(be_range)
69
102
  end
70
103
 
71
- def left_parenthesis_range
72
- Parser::Source::Range.new(
73
- selector_range.source_buffer,
74
- selector_range.end_pos,
75
- selector_range.end_pos + 1
76
- )
104
+ def be_node
105
+ if receiver_node == s(:send, nil, :be)
106
+ receiver_node
107
+ else
108
+ nil
109
+ end
110
+ end
111
+
112
+ def argument_is_here_document?
113
+ here_document?(arg_node) ||
114
+ arg_node.each_descendent_node.any? { |n| here_document?(n) }
77
115
  end
78
116
  end
79
117
  end