synvert 0.0.17 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/CHANGELOG.md +4 -0
  4. data/README.md +7 -26
  5. data/bin/synvert +0 -1
  6. data/lib/synvert/cli.rb +26 -14
  7. data/lib/synvert/snippet.rb +17 -0
  8. data/lib/synvert/version.rb +1 -1
  9. data/lib/synvert.rb +3 -11
  10. data/synvert.gemspec +2 -3
  11. metadata +6 -85
  12. data/lib/synvert/configuration.rb +0 -25
  13. data/lib/synvert/exceptions.rb +0 -13
  14. data/lib/synvert/node_ext.rb +0 -319
  15. data/lib/synvert/rewriter/action.rb +0 -224
  16. data/lib/synvert/rewriter/condition.rb +0 -56
  17. data/lib/synvert/rewriter/gem_spec.rb +0 -42
  18. data/lib/synvert/rewriter/instance.rb +0 -185
  19. data/lib/synvert/rewriter/scope.rb +0 -46
  20. data/lib/synvert/rewriter.rb +0 -200
  21. data/lib/synvert/snippets/check_syntax.rb +0 -5
  22. data/lib/synvert/snippets/factory_girl/syntax_methods.rb +0 -98
  23. data/lib/synvert/snippets/rails/convert_dynamic_finders.rb +0 -93
  24. data/lib/synvert/snippets/rails/strong_parameters.rb +0 -93
  25. data/lib/synvert/snippets/rails/upgrade_3_0_to_3_1.rb +0 -135
  26. data/lib/synvert/snippets/rails/upgrade_3_1_to_3_2.rb +0 -42
  27. data/lib/synvert/snippets/rails/upgrade_3_2_to_4_0.rb +0 -230
  28. data/lib/synvert/snippets/rspec/be_close_to_be_within.rb +0 -18
  29. data/lib/synvert/snippets/rspec/block_to_expect.rb +0 -22
  30. data/lib/synvert/snippets/rspec/boolean_matcher.rb +0 -20
  31. data/lib/synvert/snippets/rspec/collection_matcher.rb +0 -34
  32. data/lib/synvert/snippets/rspec/its_to_it.rb +0 -89
  33. data/lib/synvert/snippets/rspec/message_expectation.rb +0 -41
  34. data/lib/synvert/snippets/rspec/method_stub.rb +0 -84
  35. data/lib/synvert/snippets/rspec/negative_error_expectation.rb +0 -21
  36. data/lib/synvert/snippets/rspec/new_syntax.rb +0 -18
  37. data/lib/synvert/snippets/rspec/one_liner_expectation.rb +0 -71
  38. data/lib/synvert/snippets/rspec/should_to_expect.rb +0 -50
  39. data/lib/synvert/snippets/rspec/stub_and_mock_to_double.rb +0 -22
  40. data/lib/synvert/snippets/ruby/new_hash_syntax.rb +0 -21
  41. data/lib/synvert/snippets/ruby/new_lambda_syntax.rb +0 -20
  42. data/spec/spec_helper.rb +0 -26
  43. data/spec/support/parser_helper.rb +0 -5
  44. data/spec/synvert/node_ext_spec.rb +0 -201
  45. data/spec/synvert/rewriter/action_spec.rb +0 -225
  46. data/spec/synvert/rewriter/condition_spec.rb +0 -106
  47. data/spec/synvert/rewriter/gem_spec_spec.rb +0 -52
  48. data/spec/synvert/rewriter/instance_spec.rb +0 -163
  49. data/spec/synvert/rewriter/scope_spec.rb +0 -42
  50. data/spec/synvert/rewriter_spec.rb +0 -153
  51. data/spec/synvert/snippets/factory_girl/syntax_methods_spec.rb +0 -154
  52. data/spec/synvert/snippets/rails/convert_dynamic_finders_spec.rb +0 -83
  53. data/spec/synvert/snippets/rails/strong_parameters_spec.rb +0 -132
  54. data/spec/synvert/snippets/rails/upgrade_3_0_to_3_1_spec.rb +0 -88
  55. data/spec/synvert/snippets/rails/upgrade_3_1_to_3_2_spec.rb +0 -41
  56. data/spec/synvert/snippets/rails/upgrade_3_2_to_4_0_spec.rb +0 -299
  57. data/spec/synvert/snippets/rspec/new_syntax_spec.rb +0 -183
  58. data/spec/synvert/snippets/ruby/new_hash_syntax_spec.rb +0 -27
  59. data/spec/synvert/snippets/ruby/new_lambda_syntax_spec.rb +0 -27
@@ -1,319 +0,0 @@
1
- # Parser::AST::Node monkey patch.
2
- class Parser::AST::Node
3
- # Get name node of :class, :module, :def and :defs node.
4
- #
5
- # @return [Parser::AST::Node] name node.
6
- # @raise [Synvert::MethodNotSupported] if calls on other node.
7
- def name
8
- case self.type
9
- when :class, :module, :def
10
- self.children[0]
11
- when :defs
12
- self.children[1]
13
- else
14
- raise Synvert::MethodNotSupported.new "name is not handled for #{self.inspect}"
15
- end
16
- end
17
-
18
- # Get receiver node of :send node.
19
- #
20
- # @return [Parser::AST::Node] receiver node.
21
- # @raise [Synvert::MethodNotSupported] if calls on other node.
22
- def receiver
23
- if :send == self.type
24
- self.children[0]
25
- else
26
- raise Synvert::MethodNotSupported.new "receiver is not handled for #{self.inspect}"
27
- end
28
- end
29
-
30
- # Get message node of :send node.
31
- #
32
- # @return [Parser::AST::Node] mesage node.
33
- # @raise [Synvert::MethodNotSupported] if calls on other node.
34
- def message
35
- if :send == self.type
36
- self.children[1]
37
- else
38
- raise Synvert::MethodNotSupported.new "message is not handled for #{self.inspect}"
39
- end
40
- end
41
-
42
- # Get arguments node of :send, :block or :defined? node.
43
- #
44
- # @return [Array<Parser::AST::Node>] arguments node.
45
- # @raise [Synvert::MethodNotSupported] if calls on other node.
46
- def arguments
47
- case self.type
48
- when :send
49
- self.children[2..-1]
50
- when :block
51
- self.children[1].children
52
- when :defined?
53
- self.children
54
- else
55
- raise Synvert::MethodNotSupported.new "arguments is not handled for #{self.inspect}"
56
- end
57
- end
58
-
59
- # Get caller node of :block node.
60
- #
61
- # @return [Parser::AST::Node] caller node.
62
- # @raise [Synvert::MethodNotSupported] if calls on other node.
63
- def caller
64
- if :block == self.type
65
- self.children[0]
66
- else
67
- raise Synvert::MethodNotSupported.new "caller is not handled for #{self.inspect}"
68
- end
69
- end
70
-
71
- # Get body node of :begin or :block node.
72
- #
73
- # @return [Array<Parser::AST::Node>] body node.
74
- # @raise [Synvert::MethodNotSupported] if calls on other node.
75
- def body
76
- case self.type
77
- when :begin
78
- self.children
79
- when :block
80
- :begin == self.children[2].type ? self.children[2].children : [self.children[2]]
81
- else
82
- raise Synvert::MethodNotSupported.new "body is not handled for #{self.inspect}"
83
- end
84
- end
85
-
86
- # Get condition node of :if node.
87
- #
88
- # @return [Parser::AST::Node] condition node.
89
- # @raise [Synvert::MethodNotSupported] if calls on other node.
90
- def condition
91
- if :if == self.type
92
- self.children[0]
93
- else
94
- raise Synvert::MethodNotSupported.new "condition is not handled for #{self.inspect}"
95
- end
96
- end
97
-
98
- # Get keys node of :hash node.
99
- #
100
- # @return [Array<Parser::AST::Node>] keys node.
101
- # @raise [Synvert::MethodNotSupported] if calls on other node.
102
- def keys
103
- if :hash == self.type
104
- self.children.map { |child| child.children[0] }
105
- else
106
- raise Synvert::MethodNotSupported.new "keys is not handled for #{self.inspect}"
107
- end
108
- end
109
-
110
- # Get values node of :hash node.
111
- #
112
- # @return [Array<Parser::AST::Node>] values node.
113
- # @raise [Synvert::MethodNotSupported] if calls on other node.
114
- def values
115
- if :hash == self.type
116
- self.children.map { |child| child.children[1] }
117
- else
118
- raise Synvert::MethodNotSupported.new "keys is not handled for #{self.inspect}"
119
- end
120
- end
121
-
122
- # Get key node of hash :pair node.
123
- #
124
- # @return [Parser::AST::Node] key node.
125
- # @raise [Synvert::MethodNotSupported] if calls on other node.
126
- def key
127
- if :pair == self.type
128
- self.children.first
129
- else
130
- raise Synvert::MethodNotSupported.new "key is not handled for #{self.inspect}"
131
- end
132
- end
133
-
134
- # Get value node of hash :pair node.
135
- #
136
- # @return [Parser::AST::Node] value node.
137
- # @raise [Synvert::MethodNotSupported] if calls on other node.
138
- def value
139
- if :pair == self.type
140
- self.children.last
141
- else
142
- raise Synvert::MethodNotSupported.new "value is not handled for #{self.inspect}"
143
- end
144
- end
145
-
146
- # Get the source code of current node.
147
- #
148
- # @param instance [Synvert::Rewriter::Instance]
149
- # @return [String] source code.
150
- def source(instance)
151
- if self.loc.expression
152
- instance.current_source[self.loc.expression.begin_pos...self.loc.expression.end_pos]
153
- end
154
- end
155
-
156
- # Get the indent of current node.
157
- #
158
- # @return [Integer] indent.
159
- def indent
160
- self.loc.expression.column
161
- end
162
-
163
- # Recursively iterate all child nodes of current node.
164
- #
165
- # @yield [child] Gives a child node.
166
- # @yieldparam child [Parser::AST::Node] child node
167
- def recursive_children
168
- self.children.each do |child|
169
- if Parser::AST::Node === child
170
- yield child
171
- child.recursive_children { |c| yield c }
172
- end
173
- end
174
- end
175
-
176
- # Match current node with rules.
177
- #
178
- # @param instance [Synvert::Rewriter::Instance] used to get crrent source code.
179
- # @param rules [Hash] rules to match.
180
- # @return true if matches.
181
- def match?(instance, rules)
182
- flat_hash(rules).keys.all? do |multi_keys|
183
- if multi_keys.last == :any
184
- actual_values = actual_value(self, instance, multi_keys[0...-1])
185
- expected = expected_value(rules, multi_keys)
186
- actual_values.any? { |actual| match_value?(instance, actual, expected) }
187
- elsif multi_keys.last == :not
188
- actual = actual_value(self, instance, multi_keys[0...-1])
189
- expected = expected_value(rules, multi_keys)
190
- !match_value?(instance, actual, expected)
191
- else
192
- actual = actual_value(self, instance, multi_keys)
193
- expected = expected_value(rules, multi_keys)
194
- match_value?(instance, actual, expected)
195
- end
196
- end
197
- end
198
-
199
- # Get rewritten source code.
200
- # @example
201
- # node.rewritten_source("create({{arguments}})") #=> "create(:post)"
202
- #
203
- # @param code [String] raw code.
204
- # @return [String] rewritten code, replace string in block {{ }} in raw code.
205
- # @raise [Synvert::MethodNotSupported] if string in block {{ }} does not support.
206
- def rewritten_source(code)
207
- code.gsub(/{{(.*?)}}/m) do
208
- evaluated = self.instance_eval $1
209
- case evaluated
210
- when Parser::AST::Node
211
- source = evaluated.loc.expression.source_buffer.source
212
- source[evaluated.loc.expression.begin_pos...evaluated.loc.expression.end_pos]
213
- when Array
214
- if evaluated.size > 0
215
- source = evaluated.first.loc.expression.source_buffer.source
216
- source[evaluated.first.loc.expression.begin_pos...evaluated.last.loc.expression.end_pos]
217
- end
218
- when String
219
- evaluated
220
- when NilClass
221
- 'nil'
222
- else
223
- raise Synvert::MethodNotSupported.new "rewritten_source is not handled for #{evaluated.inspect}"
224
- end
225
- end
226
- end
227
-
228
- private
229
-
230
- # Compare actual value with expected value.
231
- #
232
- # @param instance [Synvert::Rewriter::Instance] used to get source code.
233
- # @param actual [Object] actual value.
234
- # @param expected [Object] expected value.
235
- # @return [Integer] -1, 0 or 1.
236
- # @raise [Synvert::MethodNotSupported] if expected class is not supported.
237
- def match_value?(instance, actual, expected)
238
- case expected
239
- when Symbol
240
- if Parser::AST::Node === actual
241
- actual.source(instance) == ":#{expected}"
242
- else
243
- actual.to_sym == expected
244
- end
245
- when String
246
- if Parser::AST::Node === actual
247
- actual.source(instance) == expected || actual.source(instance)[1...-1] == expected
248
- else
249
- actual.to_s == expected
250
- end
251
- when Regexp
252
- if Parser::AST::Node === actual
253
- actual.source(instance) =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
254
- else
255
- actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
256
- end
257
- when Array
258
- actual.zip(expected).all? { |a, e| match_value?(instance, a, e) }
259
- when NilClass
260
- actual.nil?
261
- when Numeric
262
- if Parser::AST::Node === actual
263
- actual.children[0] == expected
264
- else
265
- actual == expected
266
- end
267
- when TrueClass
268
- :true == actual.type
269
- when FalseClass
270
- :false == actual.type
271
- when Parser::AST::Node
272
- actual == expected
273
- else
274
- raise Synvert::MethodNotSupported.new "#{expected.class} is not handled for match_value?"
275
- end
276
- end
277
-
278
- # Convert a hash to flat one.
279
- #
280
- # @example
281
- # flat_hash(type: 'block', caller: {type: 'send', receiver: 'RSpec'})
282
- # #=> {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
283
- # @param h [Hash] original hash.
284
- # @return flatten hash.
285
- def flat_hash(h, k = [])
286
- new_hash = {}
287
- h.each_pair do |key, val|
288
- if val.is_a?(Hash)
289
- new_hash.merge!(flat_hash(val, k + [key]))
290
- else
291
- new_hash[k + [key]] = val
292
- end
293
- end
294
- new_hash
295
- end
296
-
297
- # Get actual value from the node.
298
- #
299
- # @param node [Parser::AST::Node]
300
- # @param instance [Synvert::Rewriter::Instance]
301
- # @param multi_keys [Array<Symbol>]
302
- # @return [Object] actual value.
303
- def actual_value(node, instance, multi_keys)
304
- multi_keys.inject(node) { |n, key|
305
- if n
306
- key == :source ? n.send(key, instance) : n.send(key)
307
- end
308
- }
309
- end
310
-
311
- # Get expected value from rules.
312
- #
313
- # @param rules [Hash]
314
- # @param multi_keys [Array<Symbol>]
315
- # @return [Object] expected value.
316
- def expected_value(rules, multi_keys)
317
- multi_keys.inject(rules) { |o, key| o[key] }
318
- end
319
- end
@@ -1,224 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # Action defines rewriter action, add, replace or remove code.
5
- class Rewriter::Action
6
- # Initialize an action.
7
- #
8
- # @param instance [Synvert::Rewriter::Instance]
9
- # @param code {String] new code to add, replace or remove.
10
- def initialize(instance, code)
11
- @instance = instance
12
- @code = code
13
- @node = @instance.current_node
14
- end
15
-
16
- # Line number of the node.
17
- #
18
- # @return [Integer] line number.
19
- def line
20
- @node.loc.expression.line
21
- end
22
-
23
- # The rewritten source code with proper indent.
24
- #
25
- # @return [String] rewritten code.
26
- def rewritten_code
27
- if rewritten_source.split("\n").length > 1
28
- "\n\n" + rewritten_source.split("\n").map { |line|
29
- indent(@node) + line
30
- }.join("\n")
31
- else
32
- "\n" + indent(@node) + rewritten_source
33
- end
34
- end
35
-
36
- # The rewritten source code.
37
- #
38
- # @return [String] rewritten source code.
39
- def rewritten_source
40
- @rewritten_source ||= @node.rewritten_source(@code)
41
- end
42
-
43
- # Compare actions by begin position.
44
- #
45
- # @param action [Synvert::Rewriter::Action]
46
- # @return [Integer] -1, 0 or 1
47
- def <=>(action)
48
- self.begin_pos <=> action.begin_pos
49
- end
50
- end
51
-
52
- # ReplaceWithAction to replace code.
53
- class Rewriter::ReplaceWithAction < Rewriter::Action
54
- # Begin position of code to replace.
55
- #
56
- # @return [Integer] begin position.
57
- def begin_pos
58
- @node.loc.expression.begin_pos
59
- end
60
-
61
- # End position of code to replace.
62
- #
63
- # @return [Integer] end position.
64
- def end_pos
65
- @node.loc.expression.end_pos
66
- end
67
-
68
- # The rewritten source code with proper indent.
69
- #
70
- # @return [String] rewritten code.
71
- def rewritten_code
72
- if rewritten_source.split("\n").length > 1
73
- "\n\n" + rewritten_source.split("\n").map { |line|
74
- indent(@node) + line
75
- }.join("\n")
76
- else
77
- rewritten_source
78
- end
79
- end
80
-
81
- private
82
-
83
- # Indent of the node
84
- #
85
- # @param node [Parser::AST::Node]
86
- # @return [String] n times whitesphace
87
- def indent(node)
88
- ' ' * node.indent
89
- end
90
- end
91
-
92
- # AppendWithAction to append code to the bottom of node body.
93
- class Rewriter::AppendAction < Rewriter::Action
94
- # Begin position to append code.
95
- #
96
- # @return [Integer] begin position.
97
- def begin_pos
98
- if :begin == @node.type
99
- @node.loc.expression.end_pos
100
- else
101
- @node.loc.expression.end_pos - 4
102
- end
103
- end
104
-
105
- # End position, always same to begin position.
106
- #
107
- # @return [Integer] end position.
108
- def end_pos
109
- begin_pos
110
- end
111
-
112
- private
113
-
114
- # Indent of the node.
115
- #
116
- # @param node [Parser::AST::Node]
117
- # @return [String] n times whitesphace
118
- def indent(node)
119
- if [:block, :class].include? node.type
120
- ' ' * (node.indent + 2)
121
- else
122
- ' ' * node.indent
123
- end
124
- end
125
- end
126
-
127
- # InsertAction to insert code to the top of node body.
128
- class Rewriter::InsertAction < Rewriter::Action
129
- # Begin position to insert code.
130
- #
131
- # @return [Integer] begin position.
132
- def begin_pos
133
- insert_position(@node)
134
- end
135
-
136
- # End position, always same to begin position.
137
- #
138
- # @return [Integer] end position.
139
- def end_pos
140
- begin_pos
141
- end
142
-
143
- private
144
-
145
- # Insert position.
146
- #
147
- # @return [Integer] insert position.
148
- def insert_position(node)
149
- case node.type
150
- when :block
151
- node.children[1].children.empty? ? node.children[0].loc.expression.end_pos + 3 : node.children[1].loc.expression.end_pos
152
- when :class
153
- node.children[1] ? node.children[1].loc.expression.end_pos : node.children[0].loc.expression.end_pos
154
- else
155
- node.children.last.loc.expression.end_pos
156
- end
157
- end
158
-
159
- # Indent of the node.
160
- #
161
- # @param node [Parser::AST::Node]
162
- # @return [String] n times whitesphace
163
- def indent(node)
164
- if [:block, :class].include? node.type
165
- ' ' * (node.indent + 2)
166
- else
167
- ' ' * node.indent
168
- end
169
- end
170
- end
171
-
172
- # InsertAfterAction to insert code next to the node.
173
- class Rewriter::InsertAfterAction < Rewriter::Action
174
- # Begin position to insert code.
175
- #
176
- # @return [Integer] begin position.
177
- def begin_pos
178
- @node.loc.expression.end_pos
179
- end
180
-
181
- # End position, always same to begin position.
182
- #
183
- # @return [Integer] end position.
184
- def end_pos
185
- begin_pos
186
- end
187
-
188
- private
189
-
190
- # Indent of the node.
191
- #
192
- # @param node [Parser::AST::Node]
193
- # @return [String] n times whitesphace
194
- def indent(node)
195
- ' ' * node.indent
196
- end
197
- end
198
-
199
- # RemoveAction to remove code.
200
- class Rewriter::RemoveAction < Rewriter::Action
201
- def initialize(instance, code=nil)
202
- super
203
- end
204
-
205
- # Begin position of code to replace.
206
- #
207
- # @return [Integer] begin position.
208
- def begin_pos
209
- @node.loc.expression.begin_pos
210
- end
211
-
212
- # End position of code to replace.
213
- #
214
- # @return [Integer] end position.
215
- def end_pos
216
- @node.loc.expression.end_pos
217
- end
218
-
219
- # The rewritten code, always empty string.
220
- def rewritten_code
221
- ''
222
- end
223
- end
224
- end
@@ -1,56 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # Condition checks if rules matches.
5
- class Rewriter::Condition
6
- # Initialize a condition.
7
- #
8
- # @param instance [Synvert::Rewriter::Instance]
9
- # @param rules [Hash]
10
- # @param block [Block]
11
- # @return [Synvert::Rewriter::Condition]
12
- def initialize(instance, rules, &block)
13
- @instance = instance
14
- @rules = rules
15
- @block = block
16
- end
17
-
18
- # If condition matches, run the block code.
19
- def process
20
- @instance.instance_eval &@block if match?
21
- end
22
- end
23
-
24
- # IfExistCondition checks if matching node exists in the node children.
25
- class Rewriter::IfExistCondition < Rewriter::Condition
26
- # check if any child node matches the rules.
27
- def match?
28
- match = false
29
- @instance.current_node.recursive_children do |child_node|
30
- match = match || (child_node && child_node.match?(@instance, @rules))
31
- end
32
- match
33
- end
34
- end
35
-
36
- # UnlessExistCondition checks if matching node doesn't exist in the node children.
37
- class Rewriter::UnlessExistCondition < Rewriter::Condition
38
- # check if none of child node matches the rules.
39
- def match?
40
- match = false
41
- @instance.current_node.recursive_children do |child_node|
42
- match = match || (child_node && child_node.match?(@instance, @rules))
43
- end
44
- !match
45
- end
46
- end
47
-
48
- # IfExistCondition checks if node has only one child node and the child node matches rules.
49
- class Rewriter::IfOnlyExistCondition < Rewriter::Condition
50
- # check if only have one child node and the child node matches rules.
51
- def match?
52
- @instance.current_node.body.size == 1 &&
53
- @instance.current_node.body.first.match?(@instance, @rules)
54
- end
55
- end
56
- end
@@ -1,42 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # GemSpec checks and compares gem version.
5
- class Rewriter::GemSpec
6
- OPERATORS = {eq: '==', lt: '<', gt: '>', lte: '<=', gte: '>=', ne: '!='}
7
-
8
- # Initialize a gem_spec.
9
- #
10
- # @param name [String] gem name
11
- # @param comparator [Hash] comparator to gem version, e.g. {eg: '2.0.0'},
12
- # comparator key can be eq, lt, gt, lte, gte or ne.
13
- def initialize(name, comparator)
14
- @name = name
15
- if Hash === comparator
16
- @operator = comparator.keys.first
17
- @version = Gem::Version.new comparator.values.first
18
- else
19
- @operator = :eq
20
- @version = Gem::Version.new comparator
21
- end
22
- end
23
-
24
- # Check if the specified gem version in Gemfile.lock matches gem_spec comparator.
25
- #
26
- # @return [Boolean] true if matches, otherwise false.
27
- # @raise [Synvert::GemfileLockNotFound] raise if Gemfile.lock does not exist.
28
- def match?
29
- gemfile_lock_path = File.join(Configuration.instance.get(:path), 'Gemfile.lock')
30
- if File.exists? gemfile_lock_path
31
- parser = Bundler::LockfileParser.new(File.read(gemfile_lock_path))
32
- if spec = parser.specs.find { |spec| spec.name == @name }
33
- Gem::Version.new(spec.version).send(OPERATORS[@operator], @version)
34
- else
35
- false
36
- end
37
- else
38
- raise GemfileLockNotFound.new 'Gemfile.lock does not exist'
39
- end
40
- end
41
- end
42
- end