transpec 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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