transpec 1.13.1 → 2.0.0

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +63 -22
  5. data/README.md.erb +55 -16
  6. data/lib/transpec/cli.rb +9 -9
  7. data/lib/transpec/commit_message.rb +2 -0
  8. data/lib/transpec/{configuration.rb → config.rb} +7 -6
  9. data/lib/transpec/converter.rb +57 -46
  10. data/lib/transpec/option_parser.rb +23 -25
  11. data/lib/transpec/rspec_version.rb +6 -0
  12. data/lib/transpec/spec_suite.rb +2 -6
  13. data/lib/transpec/syntax/example.rb +2 -15
  14. data/lib/transpec/syntax/example_group.rb +111 -9
  15. data/lib/transpec/syntax/have/dynamic_analysis.rb +1 -1
  16. data/lib/transpec/syntax/mixin/metadata.rb +29 -0
  17. data/lib/transpec/syntax/mixin/rspec_rails.rb +27 -0
  18. data/lib/transpec/syntax/rspec_configure.rb +14 -3
  19. data/lib/transpec/syntax/rspec_configure/{configuration_modification.rb → config_modification.rb} +18 -15
  20. data/lib/transpec/syntax/rspec_configure/framework.rb +7 -7
  21. data/lib/transpec/syntax/rspec_configure/mocks.rb +1 -1
  22. data/lib/transpec/version.rb +3 -3
  23. data/spec/transpec/commit_message_spec.rb +9 -1
  24. data/spec/transpec/{configuration_spec.rb → config_spec.rb} +19 -18
  25. data/spec/transpec/converter_spec.rb +245 -210
  26. data/spec/transpec/option_parser_spec.rb +27 -59
  27. data/spec/transpec/rspec_version_spec.rb +26 -0
  28. data/spec/transpec/syntax/example_group_spec.rb +277 -0
  29. data/spec/transpec/syntax/have_spec.rb +1 -1
  30. data/spec/transpec/syntax/rspec_configure_spec.rb +117 -0
  31. data/tasks/fixtures/guard/2.99.0/COMMIT_EDITMSG +3 -1
  32. data/tasks/fixtures/guard/3.0.0/COMMIT_EDITMSG +3 -1
  33. data/tasks/fixtures/mail/2.99.0/COMMIT_EDITMSG +3 -1
  34. data/tasks/fixtures/mail/3.0.0/COMMIT_EDITMSG +3 -1
  35. data/tasks/fixtures/twitter/2.99.0/COMMIT_EDITMSG +3 -1
  36. data/tasks/fixtures/twitter/3.0.0/COMMIT_EDITMSG +3 -1
  37. data/tasks/readme.rake +3 -2
  38. metadata +8 -6
@@ -2,16 +2,34 @@
2
2
 
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/syntax/mixin/context_sensitive'
5
+ require 'transpec/syntax/mixin/metadata'
5
6
  require 'transpec/syntax/mixin/monkey_patch'
7
+ require 'transpec/syntax/mixin/rspec_rails'
6
8
  require 'transpec/rspec_dsl'
7
9
 
8
10
  module Transpec
9
11
  class Syntax
10
12
  class ExampleGroup < Syntax
11
- include Mixin::ContextSensitive, Mixin::MonkeyPatch, RSpecDSL
13
+ include Mixin::ContextSensitive, Mixin::Metadata, Mixin::MonkeyPatch, Mixin::RSpecRails,
14
+ RSpecDSL, Util
15
+
16
+ DIRECTORY_TO_TYPE_MAP = {
17
+ 'controllers' => :controller,
18
+ 'helpers' => :helper,
19
+ 'mailers' => :mailer,
20
+ 'models' => :model,
21
+ 'requests' => :request,
22
+ 'integration' => :request,
23
+ 'api' => :request,
24
+ 'routing' => :routing,
25
+ 'views' => :view,
26
+ 'features' => :feature
27
+ }
12
28
 
13
29
  def dynamic_analysis_target?
14
- super && receiver_node.nil? && EXAMPLE_GROUP_METHODS.include?(method_name)
30
+ return false unless super
31
+ return false if receiver_node && const_name(receiver_node) != 'RSpec'
32
+ EXAMPLE_GROUP_METHODS.include?(method_name)
15
33
  end
16
34
 
17
35
  def should_be_in_example_group_context?
@@ -19,19 +37,103 @@ module Transpec
19
37
  end
20
38
 
21
39
  def convert_to_non_monkey_patch!
40
+ return if receiver_node
22
41
  insert_before(expression_range, 'RSpec.')
23
- register_record
42
+ report.records << NonMonkeyPatchDescribeRecord.new(self)
43
+ end
44
+
45
+ def add_explicit_type_metadata!
46
+ return unless rspec_rails?
47
+ return unless method_name == :describe
48
+ return if explicit_type_metadata?
49
+
50
+ type = implicit_type_metadata
51
+ return unless type
52
+
53
+ code = ', '
54
+ code << if metadata_hash_style == :arrow
55
+ ":type => #{type.inspect}"
56
+ else
57
+ "type: #{type.inspect}"
58
+ end
59
+
60
+ insert_after(arg_node.loc.expression, code)
61
+
62
+ report.records << ExplicitTypeMetadataRecord.new(self)
63
+ end
64
+
65
+ def implicit_type_metadata
66
+ dirs = file_path.split('/')
67
+ return nil unless dirs.first == 'spec'
68
+ DIRECTORY_TO_TYPE_MAP[dirs[1]]
69
+ end
70
+
71
+ private
72
+
73
+ def explicit_type_metadata?
74
+ metadata_key_nodes.any? do |node|
75
+ next false unless node.sym_type?
76
+ key = node.children.first
77
+ key == :type
78
+ end
79
+ end
80
+
81
+ def file_path
82
+ expression_range.source_buffer.name
83
+ end
84
+
85
+ def metadata_hash_style
86
+ symbol_key_nodes = metadata_key_nodes.select(&:sym_type?)
87
+
88
+ has_colon_separator_pair = symbol_key_nodes.any? do |sym_node|
89
+ !sym_node.loc.expression.source.start_with?(':')
90
+ end
91
+
92
+ if has_colon_separator_pair
93
+ :colon
94
+ else
95
+ :arrow
96
+ end
97
+ end
98
+
99
+ class NonMonkeyPatchDescribeRecord < Record
100
+ attr_reader :example_group
101
+
102
+ def initialize(example_group)
103
+ @example_group = example_group
104
+ end
105
+
106
+ def build_original_syntax
107
+ base_syntax
108
+ end
109
+
110
+ def build_converted_syntax
111
+ "RSpec.#{base_syntax}"
112
+ end
113
+
114
+ def base_syntax
115
+ "#{example_group.method_name} 'something' { }"
116
+ end
24
117
  end
25
118
 
26
- def register_record
27
- original_syntax = method_name.to_s
28
- converted_syntax = "RSpec.#{method_name}"
119
+ class ExplicitTypeMetadataRecord < Record
120
+ attr_reader :example_group
29
121
 
30
- [original_syntax, converted_syntax].each do |syntax|
31
- syntax << " 'something' { }"
122
+ def initialize(example_group)
123
+ @example_group = example_group
32
124
  end
33
125
 
34
- @report.records << Record.new(original_syntax, converted_syntax)
126
+ def build_original_syntax
127
+ "describe 'some #{type}' { }"
128
+ end
129
+
130
+ def build_converted_syntax
131
+ "describe 'some #{type}', :type => #{type.inspect} { }"
132
+ end
133
+
134
+ def type
135
+ example_group.implicit_type_metadata
136
+ end
35
137
  end
36
138
  end
37
139
  end
@@ -30,7 +30,7 @@ module Transpec
30
30
  rewriter.register_request(target_node, key, code, target_type)
31
31
 
32
32
  key = :project_requires_collection_matcher?
33
- code = 'defined?(RSpec::Rails) || defined?(RSpec::CollectionMatchers)'
33
+ code = 'defined?(RSpec::CollectionMatchers)'
34
34
  rewriter.register_request(target_node, key, code, :context)
35
35
  end
36
36
  end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+
6
+ module Transpec
7
+ class Syntax
8
+ module Mixin
9
+ module Metadata
10
+ extend ActiveSupport::Concern
11
+ include Send
12
+
13
+ def metadata_nodes
14
+ arg_nodes[1..-1] || []
15
+ end
16
+
17
+ def metadata_key_nodes
18
+ metadata_nodes.each_with_object([]) do |node, key_nodes|
19
+ if node.hash_type?
20
+ key_nodes.concat(node.children.map { |pair_node| pair_node.children.first })
21
+ else
22
+ key_nodes << node
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ module Mixin
8
+ module RSpecRails
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ define_dynamic_analysis do |rewriter|
13
+ rewriter.register_request(node, :rspec_rails?, 'defined?(RSpec::Rails)', :context)
14
+ end
15
+ end
16
+
17
+ def rspec_rails?
18
+ if runtime_data.present?(node, :rspec_rails?)
19
+ runtime_data[node, :rspec_rails?]
20
+ else
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,17 +1,18 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
+ require 'transpec/syntax/mixin/rspec_rails'
4
5
  require 'transpec/syntax/mixin/send'
5
6
  require 'transpec/util'
6
7
 
7
8
  module Transpec
8
9
  class Syntax
9
10
  class RSpecConfigure < Syntax
10
- require 'transpec/syntax/rspec_configure/configuration_modification'
11
+ require 'transpec/syntax/rspec_configure/config_modification'
11
12
  require 'transpec/syntax/rspec_configure/expectations'
12
13
  require 'transpec/syntax/rspec_configure/mocks'
13
14
 
14
- include Mixin::Send, ConfigurationModification
15
+ include Mixin::Send, Mixin::RSpecRails, ConfigModification
15
16
 
16
17
  define_dynamic_analysis do |rewriter|
17
18
  code = "TranspecAnalysis.global_data[:rspec_configure_run_order] ||= 0\n" \
@@ -25,7 +26,17 @@ module Transpec
25
26
  end
26
27
 
27
28
  def expose_dsl_globally=(boolean)
28
- set_configuration!(:expose_dsl_globally, boolean)
29
+ set_config!(:expose_dsl_globally, boolean)
30
+ end
31
+
32
+ def infer_spec_type_from_file_location!
33
+ return if infer_spec_type_from_file_location?
34
+ return unless rspec_rails?
35
+ add_config!(:infer_spec_type_from_file_location!)
36
+ end
37
+
38
+ def infer_spec_type_from_file_location?
39
+ !find_config_node(:infer_spec_type_from_file_location!).nil?
29
40
  end
30
41
 
31
42
  def expectations
@@ -6,7 +6,7 @@ require 'ast'
6
6
  module Transpec
7
7
  class Syntax
8
8
  class RSpecConfigure
9
- module ConfigurationModification
9
+ module ConfigModification
10
10
  include Util, ::AST::Sexp
11
11
 
12
12
  def block_node
@@ -15,27 +15,27 @@ module Transpec
15
15
 
16
16
  private
17
17
 
18
- def set_configuration!(config_name, value)
19
- setter_node = find_configuration_node("#{config_name}=")
18
+ def set_config!(config_name, value)
19
+ setter_node = find_config_node("#{config_name}=")
20
20
 
21
21
  if setter_node
22
22
  arg_node = setter_node.children[2]
23
23
  source_rewriter.replace(arg_node.loc.expression, value.to_s)
24
24
  else
25
- add_configuration!(config_name, value)
25
+ add_config!(config_name, value)
26
26
  end
27
27
  end
28
28
 
29
- def find_configuration_node(configuration_method_name)
29
+ def find_config_node(config_method_name)
30
30
  return nil unless block_node
31
31
 
32
- configuration_method_name = configuration_method_name.to_sym
32
+ config_method_name = config_method_name.to_sym
33
33
 
34
34
  block_node.each_descendent_node.find do |node|
35
35
  next unless node.send_type?
36
36
  receiver_node, method_name, = *node
37
37
  next unless receiver_node == s(:lvar, block_arg_name)
38
- method_name == configuration_method_name
38
+ method_name == config_method_name
39
39
  end
40
40
  end
41
41
 
@@ -44,20 +44,23 @@ module Transpec
44
44
  first_block_arg_name(block_node)
45
45
  end
46
46
 
47
- module ConfigurationAddition
48
- def add_configuration!(config_name, value)
49
- lines = generate_configuration_lines(config_name, value)
47
+ # TODO: Refactor this to remove messy overrides in Framework.
48
+ module ConfigAddition
49
+ def add_config!(config_name, value = nil)
50
+ lines = generate_config_lines(config_name, value)
50
51
  lines.unshift('') unless empty_block_body?
51
52
  lines.map! { |line| line + "\n" }
52
53
 
53
54
  insertion_position = beginning_of_line_range(block_node_to_insert_code.loc.end)
54
55
  source_rewriter.insert_before(insertion_position, lines.join(''))
55
56
 
56
- block_node_to_insert_code.metadata[:added_configuration] = true
57
+ block_node_to_insert_code.metadata[:added_config] = true
57
58
  end
58
59
 
59
- def generate_configuration_lines(config_name, value)
60
- [body_indentation + "#{config_variable_name}.#{config_name} = #{value}"]
60
+ def generate_config_lines(config_name, value = nil)
61
+ line = body_indentation + "#{config_variable_name}.#{config_name}"
62
+ line << " = #{value}" unless value.nil?
63
+ [line]
61
64
  end
62
65
 
63
66
  def config_variable_name
@@ -75,11 +78,11 @@ module Transpec
75
78
  def empty_block_body?
76
79
  block_node = block_node_to_insert_code
77
80
  (block_node.loc.end.line - block_node.loc.begin.line <= 1) &&
78
- !block_node.metadata[:added_configuration]
81
+ !block_node.metadata[:added_config]
79
82
  end
80
83
  end
81
84
 
82
- include ConfigurationAddition
85
+ include ConfigAddition
83
86
  end
84
87
  end
85
88
  end
@@ -1,12 +1,12 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'transpec/syntax/rspec_configure/configuration_modification'
3
+ require 'transpec/syntax/rspec_configure/config_modification'
4
4
 
5
5
  module Transpec
6
6
  class Syntax
7
7
  class RSpecConfigure
8
8
  class Framework
9
- include ConfigurationModification
9
+ include ConfigModification
10
10
 
11
11
  attr_reader :rspec_configure, :source_rewriter
12
12
 
@@ -34,7 +34,7 @@ module Transpec
34
34
  fail NotImplementedError
35
35
  end
36
36
 
37
- def generate_configuration_lines(config_name, value)
37
+ def generate_config_lines(config_name, value = nil)
38
38
  lines = super
39
39
 
40
40
  unless block_node
@@ -86,7 +86,7 @@ module Transpec
86
86
  indentation_of_line(rspec_configure.node) + (' ' * 2)
87
87
  end
88
88
 
89
- module SyntaxConfiguration
89
+ module SyntaxConfig
90
90
  def syntaxes
91
91
  return [] unless syntaxes_node
92
92
 
@@ -107,7 +107,7 @@ module Transpec
107
107
  fail ArgumentError, 'Syntaxes must be either an array or a symbol.'
108
108
  end
109
109
 
110
- set_configuration!(:syntax, syntaxes.inspect)
110
+ set_config!(:syntax, syntaxes.inspect)
111
111
  end
112
112
 
113
113
  private
@@ -115,7 +115,7 @@ module Transpec
115
115
  def syntaxes_node
116
116
  return @syntaxes_node if instance_variable_defined?(:@syntaxes_node)
117
117
 
118
- syntax_setter_node = find_configuration_node(:syntax=)
118
+ syntax_setter_node = find_config_node(:syntax=)
119
119
 
120
120
  @syntaxes_node = if syntax_setter_node
121
121
  syntax_setter_node.children[2]
@@ -127,7 +127,7 @@ module Transpec
127
127
  class UnknownSyntaxError < StandardError; end
128
128
  end
129
129
 
130
- include SyntaxConfiguration
130
+ include SyntaxConfig
131
131
  end
132
132
  end
133
133
  end
@@ -11,7 +11,7 @@ module Transpec
11
11
  end
12
12
 
13
13
  def yield_receiver_to_any_instance_implementation_blocks=(boolean)
14
- set_configuration!(:yield_receiver_to_any_instance_implementation_blocks, boolean)
14
+ set_config!(:yield_receiver_to_any_instance_implementation_blocks, boolean)
15
15
  end
16
16
  end
17
17
  end
@@ -3,9 +3,9 @@
3
3
  module Transpec
4
4
  # http://semver.org/
5
5
  module Version
6
- MAJOR = 1
7
- MINOR = 13
8
- PATCH = 1
6
+ MAJOR = 2
7
+ MINOR = 0
8
+ PATCH = 0
9
9
 
10
10
  def self.to_s
11
11
  [MAJOR, MINOR, PATCH].join('.')
@@ -55,7 +55,7 @@ module Transpec
55
55
  end
56
56
 
57
57
  it 'has conversion summary' do
58
- body_lines[3..-1].join('').should == <<-END.gsub(/^\s+\|/, '')
58
+ body_lines[3..-3].join('').should == <<-END.gsub(/^\s+\|/, '')
59
59
  |* 2 conversions
60
60
  | from: obj.should
61
61
  | to: expect(obj).to
@@ -65,6 +65,14 @@ module Transpec
65
65
  | to: allow(obj).to receive(:message)
66
66
  END
67
67
  end
68
+
69
+ it 'has blank line after the summary' do
70
+ body_lines[-2].chomp.should be_empty
71
+ end
72
+
73
+ it 'has the URL at the last line' do
74
+ body_lines[-1].chomp.should == 'See also: https://github.com/yujinakayama/transpec#supported-conversions'
75
+ end
68
76
  end
69
77
  end
70
78
  end
@@ -1,14 +1,15 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
- require 'transpec/configuration'
4
+ require 'transpec/config'
5
5
 
6
6
  module Transpec
7
- describe Configuration do
8
- subject(:configuration) { Configuration.new }
7
+ describe Config do
8
+ subject(:config) { Config.new }
9
9
 
10
10
  context 'by default' do
11
11
  [
12
+ [:forced?, false],
12
13
  [:convert_should?, true],
13
14
  [:convert_oneliner?, true],
14
15
  [:convert_should_receive?, true],
@@ -17,19 +18,19 @@ module Transpec
17
18
  [:convert_its?, true],
18
19
  [:convert_pending?, true],
19
20
  [:convert_deprecated_method?, true],
20
- [:parenthesize_matcher_arg?, true],
21
- [:add_receiver_arg_to_any_instance_implementation_block?, true],
22
- [:convert_stub_with_hash_to_allow_to_receive_and_return?, false],
23
21
  [:convert_example_group?, false],
24
22
  [:convert_hook_scope?, false],
25
- [:forced?, false],
23
+ [:convert_stub_with_hash_to_allow_to_receive_and_return?, false],
26
24
  [:skip_dynamic_analysis?, false],
27
25
  [:negative_form_of_to, 'not_to'],
28
26
  [:boolean_matcher_type, :conditional],
29
- [:form_of_be_falsey, 'be_falsey']
27
+ [:form_of_be_falsey, 'be_falsey'],
28
+ [:add_receiver_arg_to_any_instance_implementation_block?, true],
29
+ [:add_explicit_type_metadata_to_example_group?, true],
30
+ [:parenthesize_matcher_arg?, true]
30
31
  ].each do |attribute, value|
31
32
  describe "##{attribute}" do
32
- subject { configuration.send(attribute) }
33
+ subject { config.send(attribute) }
33
34
 
34
35
  it "is #{value.inspect}" do
35
36
  should == value
@@ -42,8 +43,8 @@ module Transpec
42
43
  ['not_to', 'to_not'] .each do |form|
43
44
  context "when #{form.inspect} is passed" do
44
45
  it "sets #{form.inspect}" do
45
- configuration.negative_form_of_to = form
46
- configuration.negative_form_of_to.should == form
46
+ config.negative_form_of_to = form
47
+ config.negative_form_of_to.should == form
47
48
  end
48
49
  end
49
50
  end
@@ -51,7 +52,7 @@ module Transpec
51
52
  context 'when a form other than "not_to" or "to_not" is passed' do
52
53
  it 'raises error' do
53
54
  lambda do
54
- configuration.negative_form_of_to = 'foo'
55
+ config.negative_form_of_to = 'foo'
55
56
  end.should raise_error(ArgumentError)
56
57
  end
57
58
  end
@@ -61,8 +62,8 @@ module Transpec
61
62
  [:conditional, :exact] .each do |type|
62
63
  context "when #{type.inspect} is passed" do
63
64
  it "sets #{type.inspect}" do
64
- configuration.boolean_matcher_type = type
65
- configuration.boolean_matcher_type.should == type
65
+ config.boolean_matcher_type = type
66
+ config.boolean_matcher_type.should == type
66
67
  end
67
68
  end
68
69
  end
@@ -70,7 +71,7 @@ module Transpec
70
71
  context 'when a type other than :conditional or :exact is passed' do
71
72
  it 'raises error' do
72
73
  lambda do
73
- configuration.boolean_matcher_type = :foo
74
+ config.boolean_matcher_type = :foo
74
75
  end.should raise_error(ArgumentError)
75
76
  end
76
77
  end
@@ -80,8 +81,8 @@ module Transpec
80
81
  ['be_falsey', 'be_falsy'] .each do |form|
81
82
  context "when #{form.inspect} is passed" do
82
83
  it "sets #{form.inspect}" do
83
- configuration.form_of_be_falsey = form
84
- configuration.form_of_be_falsey.should == form
84
+ config.form_of_be_falsey = form
85
+ config.form_of_be_falsey.should == form
85
86
  end
86
87
  end
87
88
  end
@@ -89,7 +90,7 @@ module Transpec
89
90
  context 'when a form other than "be_falsey" or "be_falsy" is passed' do
90
91
  it 'raises error' do
91
92
  lambda do
92
- configuration.form_of_be_falsey = 'foo'
93
+ config.form_of_be_falsey = 'foo'
93
94
  end.should raise_error(ArgumentError)
94
95
  end
95
96
  end