transpec 2.2.2 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/transpec/syntax/example.rb +6 -1
- data/lib/transpec/syntax/its.rb +45 -19
- data/lib/transpec/syntax/mixin/block_owner.rb +73 -0
- data/lib/transpec/syntax/mixin/examplish.rb +24 -0
- data/lib/transpec/syntax/oneliner_should.rb +40 -49
- data/lib/transpec/syntax/pending.rb +2 -17
- data/lib/transpec/version.rb +1 -1
- data/spec/{acceptance → integration}/configuration_modification_spec.rb +0 -0
- data/spec/{acceptance → integration}/conversion_spec.rb +31 -0
- data/spec/transpec/dynamic_analyzer_spec.rb +15 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33c531039bdc9609412069c33d3e89135b4b2f86
|
4
|
+
data.tar.gz: 8b4956401c3985d33cc37f6738141702eb9e6e86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af7da633d3f8f61ca7966e1b86ac732bf037e47e78e7241270daadad59582fcaec334bfd37d9426ae817618c1474afc6fe9e488b12aca349fa6ccb615c5e11eb
|
7
|
+
data.tar.gz: e796cfb5e29b16ac5a636e0400771d4398d96a302676bfc4d7c19ad152d757d880348e5367a88c7f9e4835e7f8d560d9e589c31229705df020987234500e45a6
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
## Development
|
4
4
|
|
5
|
+
## v2.2.3
|
6
|
+
|
7
|
+
* Handle `its(:attr) { should have(n).items }`. ([#68](https://github.com/yujinakayama/transpec/pull/68))
|
8
|
+
|
5
9
|
## v2.2.2
|
6
10
|
|
7
11
|
* Fix error on dynamic analysis when the project have `.rspec` file containing some `--require` options and the required file contains some RSpec API.
|
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
4
|
require 'transpec/syntax/mixin/context_sensitive'
|
5
|
+
require 'transpec/syntax/mixin/examplish'
|
5
6
|
require 'transpec/syntax/mixin/metadata'
|
6
7
|
require 'transpec/rspec_dsl'
|
7
8
|
|
8
9
|
module Transpec
|
9
10
|
class Syntax
|
10
11
|
class Example < Syntax
|
11
|
-
include Mixin::ContextSensitive, Mixin::Metadata, RSpecDSL
|
12
|
+
include Mixin::ContextSensitive, Mixin::Examplish, Mixin::Metadata, RSpecDSL
|
12
13
|
|
13
14
|
def dynamic_analysis_target?
|
14
15
|
super && receiver_node.nil? && EXAMPLE_METHODS.include?(method_name)
|
@@ -23,6 +24,10 @@ module Transpec
|
|
23
24
|
convert_pending_metadata_to_skip!
|
24
25
|
end
|
25
26
|
|
27
|
+
def description?
|
28
|
+
!arg_node.nil?
|
29
|
+
end
|
30
|
+
|
26
31
|
private
|
27
32
|
|
28
33
|
def convert_pending_selector_to_skip!
|
data/lib/transpec/syntax/its.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
+
require 'transpec/syntax/mixin/examplish'
|
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 Its < Syntax
|
10
|
-
include Mixin::Send, Util
|
11
|
+
include Mixin::Examplish, Mixin::Send, Util
|
11
12
|
|
12
13
|
define_dynamic_analysis do |rewriter|
|
13
14
|
key = :project_requires_its?
|
@@ -24,15 +25,20 @@ module Transpec
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def convert_to_describe_subject_it!
|
27
|
-
|
28
|
-
|
29
|
-
insert_before(beginning_of_line_range(block_node), front)
|
28
|
+
insert_before(beginning_of_line_range(block_node), front_code)
|
29
|
+
insert_before(expression_range, additional_indentation_for_it)
|
30
30
|
replace(range_from_its_to_front_of_block, 'it ')
|
31
|
-
insert_after(block_node.loc.expression,
|
31
|
+
insert_after(block_node.loc.expression, rear_code)
|
32
|
+
|
33
|
+
increment_block_base_indentation!
|
32
34
|
|
33
35
|
add_record
|
34
36
|
end
|
35
37
|
|
38
|
+
def insert_blank_line_above!
|
39
|
+
insert_before(line_range(node), "\n")
|
40
|
+
end
|
41
|
+
|
36
42
|
def attribute_expression
|
37
43
|
@attribute_expression ||= AttributeExpression.new(attribute_node)
|
38
44
|
end
|
@@ -47,27 +53,42 @@ module Transpec
|
|
47
53
|
node.parent_node
|
48
54
|
end
|
49
55
|
|
56
|
+
def description?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
50
60
|
private
|
51
61
|
|
52
|
-
def
|
53
|
-
|
54
|
-
rear = ''
|
62
|
+
def front_code
|
63
|
+
code = ''
|
55
64
|
|
56
|
-
|
57
|
-
|
65
|
+
if !previous_line_is_blank? && previous_and_current_line_are_same_indentation_level?
|
66
|
+
code << "\n"
|
67
|
+
end
|
58
68
|
|
59
69
|
attributes.each_with_index do |attribute, index|
|
60
|
-
indentation =
|
70
|
+
indentation = block_base_indentation + ' ' * index
|
71
|
+
code << indentation + "describe #{attribute.description} do\n"
|
72
|
+
code << indentation + " subject { super()#{attribute.selector} }\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
code
|
76
|
+
end
|
61
77
|
|
62
|
-
|
63
|
-
|
78
|
+
def rear_code
|
79
|
+
code = ''
|
64
80
|
|
65
|
-
|
81
|
+
attributes.size.downto(1) do |level|
|
82
|
+
indentation = block_base_indentation + ' ' * (level - 1)
|
83
|
+
code << "\n"
|
84
|
+
code << "#{indentation}end"
|
66
85
|
end
|
67
86
|
|
68
|
-
|
87
|
+
code
|
88
|
+
end
|
69
89
|
|
70
|
-
|
90
|
+
def additional_indentation_for_it
|
91
|
+
' ' * attributes.size
|
71
92
|
end
|
72
93
|
|
73
94
|
def previous_line_is_blank?
|
@@ -76,7 +97,7 @@ module Transpec
|
|
76
97
|
end
|
77
98
|
|
78
99
|
def previous_and_current_line_are_same_indentation_level?
|
79
|
-
indentation_of_line(previous_line_source) ==
|
100
|
+
indentation_of_line(previous_line_source) == block_base_indentation
|
80
101
|
end
|
81
102
|
|
82
103
|
def previous_line_source
|
@@ -85,8 +106,13 @@ module Transpec
|
|
85
106
|
nil
|
86
107
|
end
|
87
108
|
|
88
|
-
|
89
|
-
|
109
|
+
# TODO: This is an ad-hoc solution for nested indentation manipulations.
|
110
|
+
def block_base_indentation
|
111
|
+
block_node.metadata[:indentation] ||= indentation_of_line(node)
|
112
|
+
end
|
113
|
+
|
114
|
+
def increment_block_base_indentation!
|
115
|
+
block_node.metadata[:indentation] = block_base_indentation + ' '
|
90
116
|
end
|
91
117
|
|
92
118
|
def range_from_its_to_front_of_block
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
|
+
require 'transpec/util'
|
6
|
+
|
7
|
+
module Transpec
|
8
|
+
class Syntax
|
9
|
+
module Mixin
|
10
|
+
module BlockOwner
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
def convert_singleline_block_to_multiline!
|
14
|
+
return unless block_has_body? # TODO
|
15
|
+
|
16
|
+
has_inserted_linefeed = false
|
17
|
+
|
18
|
+
if block_beginning_line == block_body_line
|
19
|
+
replace(range_between_block_begin_and_body, "\n#{block_base_indentation} ")
|
20
|
+
has_inserted_linefeed = true
|
21
|
+
end
|
22
|
+
|
23
|
+
if block_end_line == block_body_line
|
24
|
+
replace(range_between_block_body_and_end, "\n#{block_base_indentation}")
|
25
|
+
has_inserted_linefeed = true
|
26
|
+
end
|
27
|
+
|
28
|
+
if has_inserted_linefeed
|
29
|
+
replace(block_node.loc.begin, 'do')
|
30
|
+
replace(block_node.loc.end, 'end')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def block_base_indentation
|
35
|
+
Util.indentation_of_line(block_node)
|
36
|
+
end
|
37
|
+
|
38
|
+
def block_has_body?
|
39
|
+
!block_body_node.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
def block_body_node
|
43
|
+
block_node.children[2]
|
44
|
+
end
|
45
|
+
|
46
|
+
def block_beginning_line
|
47
|
+
block_node.loc.begin.line
|
48
|
+
end
|
49
|
+
|
50
|
+
def block_body_line
|
51
|
+
block_body_node.loc.expression.line
|
52
|
+
end
|
53
|
+
|
54
|
+
def block_end_line
|
55
|
+
block_node.loc.end.line
|
56
|
+
end
|
57
|
+
|
58
|
+
def range_between_block_begin_and_body
|
59
|
+
block_node.loc.begin.end.join(block_body_node.loc.expression.begin)
|
60
|
+
end
|
61
|
+
|
62
|
+
def range_between_block_body_and_end
|
63
|
+
block_body_node.loc.expression.end.join(block_node.loc.end.begin)
|
64
|
+
end
|
65
|
+
|
66
|
+
def block_body_range
|
67
|
+
block_body_node = block_node.children[2]
|
68
|
+
block_body_node.loc.expression
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'transpec/syntax/mixin/block_owner'
|
5
|
+
|
6
|
+
module Transpec
|
7
|
+
class Syntax
|
8
|
+
module Mixin
|
9
|
+
module Examplish
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
include Mixin::BlockOwner
|
12
|
+
|
13
|
+
def block_node
|
14
|
+
parent_node.block_type? ? parent_node : nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def insert_description!(description)
|
18
|
+
fail 'This example already has description' if description?
|
19
|
+
insert_before(block_node.loc.begin, "'#{description}' ")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
4
|
require 'transpec/syntax/mixin/should_base'
|
5
|
-
require 'transpec/
|
5
|
+
require 'transpec/syntax/example'
|
6
6
|
require 'transpec/util'
|
7
7
|
require 'active_support/inflector/methods'
|
8
8
|
require 'active_support/inflector/inflections'
|
@@ -24,6 +24,16 @@ module Transpec
|
|
24
24
|
super && receiver_node.nil? && [:should, :should_not].include?(method_name)
|
25
25
|
end
|
26
26
|
|
27
|
+
def conversion_target?
|
28
|
+
return false unless dynamic_analysis_target?
|
29
|
+
return true unless runtime_data.run?(send_analysis_target_node)
|
30
|
+
return false unless defined_in_rspec_source?
|
31
|
+
# #should inside of #its is dynamically defined in MemoizedHelper,
|
32
|
+
# so it cannot be differentiated from user-defined methods by the dynamic analysis in Send.
|
33
|
+
# https://github.com/rspec/rspec-core/blob/v2.14.8/lib/rspec/core/memoized_helpers.rb#L439
|
34
|
+
!example_method_defined_by_user? || in_its?
|
35
|
+
end
|
36
|
+
|
27
37
|
def expectize!(negative_form = 'not_to')
|
28
38
|
replacement = 'is_expected.'
|
29
39
|
replacement << (positive? ? 'to' : negative_form)
|
@@ -60,9 +70,26 @@ module Transpec
|
|
60
70
|
report.records << OnelinerShouldHaveRecord.new(self, have_matcher, negative_form)
|
61
71
|
end
|
62
72
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
73
|
+
def example
|
74
|
+
return @example if instance_variable_defined?(:@example)
|
75
|
+
|
76
|
+
@example = nil
|
77
|
+
|
78
|
+
node.each_ancestor_node do |node|
|
79
|
+
next unless node.block_type?
|
80
|
+
send_node = node.children[0]
|
81
|
+
|
82
|
+
found = Syntax.all_syntaxes.find do |syntax_class|
|
83
|
+
next unless syntax_class.ancestors.include?(Mixin::Examplish)
|
84
|
+
syntax = syntax_class.new(send_node, source_rewriter, runtime_data)
|
85
|
+
next unless syntax.conversion_target?
|
86
|
+
@example = syntax
|
87
|
+
end
|
88
|
+
|
89
|
+
break if found
|
90
|
+
end
|
91
|
+
|
92
|
+
@example
|
66
93
|
end
|
67
94
|
|
68
95
|
def build_description(size)
|
@@ -91,53 +118,17 @@ module Transpec
|
|
91
118
|
fail 'This one-liner #should does not have #have matcher!'
|
92
119
|
end
|
93
120
|
|
94
|
-
unless
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
indentation = indentation_of_line(example_block_node)
|
99
|
-
|
100
|
-
unless linefeed_at_beginning_of_block?
|
101
|
-
replace(left_curly_and_whitespaces_range, "do\n#{indentation} ")
|
102
|
-
end
|
103
|
-
|
104
|
-
unless linefeed_at_end_of_block?
|
105
|
-
replace(whitespaces_and_right_curly_range, "\n#{indentation}end")
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def example_block_node
|
110
|
-
return @example_block_node if instance_variable_defined?(:@example_block_node)
|
111
|
-
|
112
|
-
@example_block_node = node.each_ancestor_node.find do |node|
|
113
|
-
next false unless node.block_type?
|
114
|
-
send_node = node.children.first
|
115
|
-
receiver_node, method_name, = *send_node
|
116
|
-
next false if receiver_node
|
117
|
-
EXAMPLE_METHODS.include?(method_name)
|
121
|
+
unless example.description?
|
122
|
+
example.insert_description!(build_description(have_matcher.size_source))
|
118
123
|
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def generated_description
|
122
|
-
build_description(have_matcher.size_source)
|
123
|
-
end
|
124
124
|
|
125
|
-
|
126
|
-
beginning_to_body_range = example_block_node.loc.begin.join(expression_range.begin)
|
127
|
-
beginning_to_body_range.source.include?("\n")
|
128
|
-
end
|
129
|
-
|
130
|
-
def linefeed_at_end_of_block?
|
131
|
-
body_to_end_range = expression_range.end.join(example_block_node.loc.end)
|
132
|
-
body_to_end_range.source.include?("\n")
|
133
|
-
end
|
125
|
+
example.convert_singleline_block_to_multiline!
|
134
126
|
|
135
|
-
|
136
|
-
expand_range_to_adjacent_whitespaces(example_block_node.loc.begin, :end)
|
127
|
+
example.insert_blank_line_above! if in_its?
|
137
128
|
end
|
138
129
|
|
139
|
-
def
|
140
|
-
|
130
|
+
def in_its?
|
131
|
+
example.is_a?(Its)
|
141
132
|
end
|
142
133
|
|
143
134
|
def add_record(negative_form_of_to)
|
@@ -170,9 +161,9 @@ module Transpec
|
|
170
161
|
private
|
171
162
|
|
172
163
|
def build_original_syntax
|
173
|
-
syntax = should.
|
164
|
+
syntax = should.example.description? ? "it '...' do" : 'it {'
|
174
165
|
syntax << " #{should.method_name} #{have.method_name}(n).#{original_items} "
|
175
|
-
syntax << (should.
|
166
|
+
syntax << (should.example.description? ? 'end' : '}')
|
176
167
|
end
|
177
168
|
|
178
169
|
def build_converted_syntax
|
@@ -185,7 +176,7 @@ module Transpec
|
|
185
176
|
end
|
186
177
|
|
187
178
|
def converted_description
|
188
|
-
if should.
|
179
|
+
if should.example.description?
|
189
180
|
"it '...' do"
|
190
181
|
else
|
191
182
|
"it '#{should.build_description('n')}' do"
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
+
require 'transpec/syntax/mixin/block_owner'
|
4
5
|
require 'transpec/syntax/mixin/context_sensitive'
|
5
6
|
require 'transpec/util'
|
6
7
|
|
7
8
|
module Transpec
|
8
9
|
class Syntax
|
9
10
|
class Pending < Syntax
|
10
|
-
include Mixin::ContextSensitive, Util
|
11
|
+
include Mixin::BlockOwner, Mixin::ContextSensitive, Util
|
11
12
|
|
12
13
|
def dynamic_analysis_target?
|
13
14
|
super && receiver_node.nil? && method_name == :pending
|
@@ -69,22 +70,6 @@ module Transpec
|
|
69
70
|
block_node_taken_by_method(node)
|
70
71
|
end
|
71
72
|
|
72
|
-
def block_body_node
|
73
|
-
block_node.children[2]
|
74
|
-
end
|
75
|
-
|
76
|
-
def block_beginning_line
|
77
|
-
block_node.loc.begin.line
|
78
|
-
end
|
79
|
-
|
80
|
-
def block_body_line
|
81
|
-
block_body_node.loc.expression.line
|
82
|
-
end
|
83
|
-
|
84
|
-
def block_end_line
|
85
|
-
block_node.loc.end.line
|
86
|
-
end
|
87
|
-
|
88
73
|
def range_between_pending_and_body
|
89
74
|
expression_range.end.join(block_body_node.loc.expression.begin)
|
90
75
|
end
|
data/lib/transpec/version.rb
CHANGED
File without changes
|
@@ -79,6 +79,37 @@ module Transpec
|
|
79
79
|
it 'is converted properly' do
|
80
80
|
converted_source.should == expected_source
|
81
81
|
end
|
82
|
+
|
83
|
+
context 'with #its' do
|
84
|
+
let(:source) do
|
85
|
+
<<-END
|
86
|
+
describe 'example' do
|
87
|
+
subject { 'foo' }
|
88
|
+
its(:chars) { should have(3).items }
|
89
|
+
end
|
90
|
+
END
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:expected_source) do
|
94
|
+
<<-END
|
95
|
+
describe 'example' do
|
96
|
+
subject { 'foo' }
|
97
|
+
|
98
|
+
describe '#chars' do
|
99
|
+
subject { super().chars }
|
100
|
+
|
101
|
+
it 'has 3 items' do
|
102
|
+
expect(subject.size).to eq(3)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
END
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'is converted properly' do
|
110
|
+
converted_source.should == expected_source
|
111
|
+
end
|
112
|
+
end
|
82
113
|
end
|
83
114
|
|
84
115
|
describe 'one-liner expectation with operator matcher' do
|
@@ -161,6 +161,21 @@ module Transpec
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
+
context 'when rspec is run via rake task' do
|
165
|
+
before do
|
166
|
+
create_file('Rakefile', <<-END)
|
167
|
+
require 'rspec/core/rake_task'
|
168
|
+
RSpec::Core::RakeTask.new(:spec)
|
169
|
+
END
|
170
|
+
end
|
171
|
+
|
172
|
+
let(:rspec_command) { 'rake spec' }
|
173
|
+
|
174
|
+
it 'does not raise error' do
|
175
|
+
-> { dynamic_analyzer.analyze }.should_not raise_error
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
164
179
|
context 'when there is a .rspec file containing `--require spec_helper`' do
|
165
180
|
before do
|
166
181
|
create_file('.rspec', '--require spec_helper')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transpec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuji Nakayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -295,7 +295,9 @@ files:
|
|
295
295
|
- lib/transpec/syntax/matcher_definition.rb
|
296
296
|
- lib/transpec/syntax/method_stub.rb
|
297
297
|
- lib/transpec/syntax/mixin/any_instance_block.rb
|
298
|
+
- lib/transpec/syntax/mixin/block_owner.rb
|
298
299
|
- lib/transpec/syntax/mixin/context_sensitive.rb
|
300
|
+
- lib/transpec/syntax/mixin/examplish.rb
|
299
301
|
- lib/transpec/syntax/mixin/expect_base.rb
|
300
302
|
- lib/transpec/syntax/mixin/expectizable.rb
|
301
303
|
- lib/transpec/syntax/mixin/matcher_owner.rb
|
@@ -324,8 +326,8 @@ files:
|
|
324
326
|
- lib/transpec/util.rb
|
325
327
|
- lib/transpec/version.rb
|
326
328
|
- spec/.rubocop.yml
|
327
|
-
- spec/
|
328
|
-
- spec/
|
329
|
+
- spec/integration/configuration_modification_spec.rb
|
330
|
+
- spec/integration/conversion_spec.rb
|
329
331
|
- spec/spec_helper.rb
|
330
332
|
- spec/support/cache_helper.rb
|
331
333
|
- spec/support/file_helper.rb
|
@@ -408,8 +410,8 @@ specification_version: 4
|
|
408
410
|
summary: The RSpec syntax converter
|
409
411
|
test_files:
|
410
412
|
- spec/.rubocop.yml
|
411
|
-
- spec/
|
412
|
-
- spec/
|
413
|
+
- spec/integration/configuration_modification_spec.rb
|
414
|
+
- spec/integration/conversion_spec.rb
|
413
415
|
- spec/spec_helper.rb
|
414
416
|
- spec/support/cache_helper.rb
|
415
417
|
- spec/support/file_helper.rb
|