synvert 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +4 -2
  5. data/lib/synvert/cli.rb +87 -18
  6. data/lib/synvert/configuration.rb +9 -0
  7. data/lib/synvert/exceptions.rb +13 -0
  8. data/lib/synvert/node_ext.rb +106 -13
  9. data/lib/synvert/rewriter/action.rb +76 -0
  10. data/lib/synvert/rewriter/condition.rb +14 -0
  11. data/lib/synvert/rewriter/gem_spec.rb +12 -1
  12. data/lib/synvert/rewriter/instance.rb +69 -0
  13. data/lib/synvert/rewriter/scope.rb +10 -0
  14. data/lib/synvert/rewriter.rb +120 -11
  15. data/lib/synvert/snippets/factory_girl/syntax_methods.rb +51 -1
  16. data/lib/synvert/snippets/rails/convert_dynamic_finders.rb +12 -1
  17. data/lib/synvert/snippets/rails/strong_parameters.rb +22 -1
  18. data/lib/synvert/snippets/rails/upgrade_3_0_to_3_1.rb +48 -7
  19. data/lib/synvert/snippets/rails/upgrade_3_1_to_3_2.rb +14 -1
  20. data/lib/synvert/snippets/rails/upgrade_3_2_to_4_0.rb +90 -19
  21. data/lib/synvert/snippets/rspec/be_close_to_be_within.rb +7 -1
  22. data/lib/synvert/snippets/rspec/block_to_expect.rb +9 -1
  23. data/lib/synvert/snippets/rspec/boolean_matcher.rb +8 -1
  24. data/lib/synvert/snippets/rspec/collection_matcher.rb +12 -1
  25. data/lib/synvert/snippets/rspec/its_to_it.rb +34 -1
  26. data/lib/synvert/snippets/rspec/message_expectation.rb +14 -1
  27. data/lib/synvert/snippets/rspec/method_stub.rb +22 -1
  28. data/lib/synvert/snippets/rspec/negative_error_expectation.rb +8 -1
  29. data/lib/synvert/snippets/rspec/new_syntax.rb +5 -1
  30. data/lib/synvert/snippets/rspec/one_liner_expectation.rb +20 -1
  31. data/lib/synvert/snippets/rspec/should_to_expect.rb +15 -1
  32. data/lib/synvert/snippets/rspec/stub_and_mock_to_double.rb +8 -1
  33. data/lib/synvert/snippets/ruby/new_hash_syntax.rb +7 -1
  34. data/lib/synvert/snippets/ruby/new_lambda_syntax.rb +7 -1
  35. data/lib/synvert/version.rb +1 -1
  36. data/lib/synvert.rb +2 -1
  37. data/spec/synvert/rewriter/gem_spec_spec.rb +2 -2
  38. data/spec/synvert/rewriter_spec.rb +71 -34
  39. data/spec/synvert/snippets/rails/upgrade_3_0_to_3_1_spec.rb +2 -2
  40. metadata +4 -4
  41. data/lib/synvert/rewriter_not_found.rb +0 -4
@@ -1,17 +1,28 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Synvert
4
+ # Action defines rewriter action, add, replace or remove code.
4
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.
5
10
  def initialize(instance, code)
6
11
  @instance = instance
7
12
  @code = code
8
13
  @node = @instance.current_node
9
14
  end
10
15
 
16
+ # Line number of the node.
17
+ #
18
+ # @return [Integer] line number.
11
19
  def line
12
20
  @node.loc.expression.line
13
21
  end
14
22
 
23
+ # The rewritten source code with proper indent.
24
+ #
25
+ # @return [String] rewritten code.
15
26
  def rewritten_code
16
27
  if rewritten_source.split("\n").length > 1
17
28
  "\n\n" + rewritten_source.split("\n").map { |line|
@@ -22,24 +33,41 @@ module Synvert
22
33
  end
23
34
  end
24
35
 
36
+ # The rewritten source code.
37
+ #
38
+ # @return [String] rewritten source code.
25
39
  def rewritten_source
26
40
  @rewritten_source ||= @node.rewritten_source(@code)
27
41
  end
28
42
 
43
+ # Compare actions by begin position.
44
+ #
45
+ # @param action [Synvert::Rewriter::Action]
46
+ # @return [Integer] -1, 0 or 1
29
47
  def <=>(action)
30
48
  self.begin_pos <=> action.begin_pos
31
49
  end
32
50
  end
33
51
 
52
+ # ReplaceWithAction to replace code.
34
53
  class Rewriter::ReplaceWithAction < Rewriter::Action
54
+ # Begin position of code to replace.
55
+ #
56
+ # @return [Integer] begin position.
35
57
  def begin_pos
36
58
  @node.loc.expression.begin_pos
37
59
  end
38
60
 
61
+ # End position of code to replace.
62
+ #
63
+ # @return [Integer] end position.
39
64
  def end_pos
40
65
  @node.loc.expression.end_pos
41
66
  end
42
67
 
68
+ # The rewritten source code with proper indent.
69
+ #
70
+ # @return [String] rewritten code.
43
71
  def rewritten_code
44
72
  if rewritten_source.split("\n").length > 1
45
73
  "\n\n" + rewritten_source.split("\n").map { |line|
@@ -52,12 +80,20 @@ module Synvert
52
80
 
53
81
  private
54
82
 
83
+ # Indent of the node
84
+ #
85
+ # @param node [Parser::AST::Node]
86
+ # @return [String] n times whitesphace
55
87
  def indent(node)
56
88
  ' ' * node.indent
57
89
  end
58
90
  end
59
91
 
92
+ # AppendWithAction to append code to the bottom of node body.
60
93
  class Rewriter::AppendAction < Rewriter::Action
94
+ # Begin position to append code.
95
+ #
96
+ # @return [Integer] begin position.
61
97
  def begin_pos
62
98
  if :begin == @node.type
63
99
  @node.loc.expression.end_pos
@@ -66,12 +102,19 @@ module Synvert
66
102
  end
67
103
  end
68
104
 
105
+ # End position, always same to begin position.
106
+ #
107
+ # @return [Integer] end position.
69
108
  def end_pos
70
109
  begin_pos
71
110
  end
72
111
 
73
112
  private
74
113
 
114
+ # Indent of the node.
115
+ #
116
+ # @param node [Parser::AST::Node]
117
+ # @return [String] n times whitesphace
75
118
  def indent(node)
76
119
  if [:block, :class].include? node.type
77
120
  ' ' * (node.indent + 2)
@@ -81,17 +124,27 @@ module Synvert
81
124
  end
82
125
  end
83
126
 
127
+ # InsertAction to insert code to the top of node body.
84
128
  class Rewriter::InsertAction < Rewriter::Action
129
+ # Begin position to insert code.
130
+ #
131
+ # @return [Integer] begin position.
85
132
  def begin_pos
86
133
  insert_position(@node)
87
134
  end
88
135
 
136
+ # End position, always same to begin position.
137
+ #
138
+ # @return [Integer] end position.
89
139
  def end_pos
90
140
  begin_pos
91
141
  end
92
142
 
93
143
  private
94
144
 
145
+ # Insert position.
146
+ #
147
+ # @return [Integer] insert position.
95
148
  def insert_position(node)
96
149
  case node.type
97
150
  when :block
@@ -103,6 +156,10 @@ module Synvert
103
156
  end
104
157
  end
105
158
 
159
+ # Indent of the node.
160
+ #
161
+ # @param node [Parser::AST::Node]
162
+ # @return [String] n times whitesphace
106
163
  def indent(node)
107
164
  if [:block, :class].include? node.type
108
165
  ' ' * (node.indent + 2)
@@ -112,35 +169,54 @@ module Synvert
112
169
  end
113
170
  end
114
171
 
172
+ # InsertAfterAction to insert code next to the node.
115
173
  class Rewriter::InsertAfterAction < Rewriter::Action
174
+ # Begin position to insert code.
175
+ #
176
+ # @return [Integer] begin position.
116
177
  def begin_pos
117
178
  @node.loc.expression.end_pos
118
179
  end
119
180
 
181
+ # End position, always same to begin position.
182
+ #
183
+ # @return [Integer] end position.
120
184
  def end_pos
121
185
  begin_pos
122
186
  end
123
187
 
124
188
  private
125
189
 
190
+ # Indent of the node.
191
+ #
192
+ # @param node [Parser::AST::Node]
193
+ # @return [String] n times whitesphace
126
194
  def indent(node)
127
195
  ' ' * node.indent
128
196
  end
129
197
  end
130
198
 
199
+ # RemoveAction to remove code.
131
200
  class Rewriter::RemoveAction < Rewriter::Action
132
201
  def initialize(instance, code=nil)
133
202
  super
134
203
  end
135
204
 
205
+ # Begin position of code to replace.
206
+ #
207
+ # @return [Integer] begin position.
136
208
  def begin_pos
137
209
  @node.loc.expression.begin_pos
138
210
  end
139
211
 
212
+ # End position of code to replace.
213
+ #
214
+ # @return [Integer] end position.
140
215
  def end_pos
141
216
  @node.loc.expression.end_pos
142
217
  end
143
218
 
219
+ # The rewritten code, always empty string.
144
220
  def rewritten_code
145
221
  ''
146
222
  end
@@ -1,19 +1,29 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Synvert
4
+ # Condition checks if rules matches.
4
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]
5
12
  def initialize(instance, rules, &block)
6
13
  @instance = instance
7
14
  @rules = rules
8
15
  @block = block
9
16
  end
10
17
 
18
+ # If condition matches, run the block code.
11
19
  def process
12
20
  @instance.instance_eval &@block if match?
13
21
  end
14
22
  end
15
23
 
24
+ # IfExistCondition checks if matching node exists in the node children.
16
25
  class Rewriter::IfExistCondition < Rewriter::Condition
26
+ # check if any child node matches the rules.
17
27
  def match?
18
28
  match = false
19
29
  @instance.current_node.recursive_children do |child_node|
@@ -23,7 +33,9 @@ module Synvert
23
33
  end
24
34
  end
25
35
 
36
+ # UnlessExistCondition checks if matching node doesn't exist in the node children.
26
37
  class Rewriter::UnlessExistCondition < Rewriter::Condition
38
+ # check if none of child node matches the rules.
27
39
  def match?
28
40
  match = false
29
41
  @instance.current_node.recursive_children do |child_node|
@@ -33,7 +45,9 @@ module Synvert
33
45
  end
34
46
  end
35
47
 
48
+ # IfExistCondition checks if node has only one child node and the child node matches rules.
36
49
  class Rewriter::IfOnlyExistCondition < Rewriter::Condition
50
+ # check if only have one child node and the child node matches rules.
37
51
  def match?
38
52
  @instance.current_node.body.size == 1 &&
39
53
  @instance.current_node.body.first.match?(@instance, @rules)
@@ -1,8 +1,15 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Synvert
4
+ # GemSpec checks and compares gem version.
4
5
  class Rewriter::GemSpec
5
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.
6
13
  def initialize(name, comparator)
7
14
  @name = name
8
15
  if Hash === comparator
@@ -14,6 +21,10 @@ module Synvert
14
21
  end
15
22
  end
16
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.
17
28
  def match?
18
29
  gemfile_lock_path = File.join(Configuration.instance.get(:path), 'Gemfile.lock')
19
30
  if File.exists? gemfile_lock_path
@@ -24,7 +35,7 @@ module Synvert
24
35
  false
25
36
  end
26
37
  else
27
- raise LoadError.new 'Gemfile.lock does not exist'
38
+ raise GemfileLockNotFound.new 'Gemfile.lock does not exist'
28
39
  end
29
40
  end
30
41
  end
@@ -1,15 +1,33 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Synvert
4
+ # Instance is an execution unit, it finds specified ast nodes,
5
+ # checks if the nodes match some conditions, then add, replace or remove code.
6
+ #
7
+ # One instance can contains one or many [Synvert::Rewriter::Scope] and [Synvert::Rewriter::Condition].
4
8
  class Rewriter::Instance
9
+ # @!attribute [rw] current_node
10
+ # @return current parsing node
11
+ # @!attribute [rw] current_source
12
+ # @return current source code of file
13
+ # @!attribute [rw] current_file
14
+ # @return current filename
5
15
  attr_accessor :current_node, :current_source, :current_file
6
16
 
17
+ # Initialize an instance.
18
+ #
19
+ # @param file_pattern [String] pattern to find files, e.g. spec/**/*_spec.rb
20
+ # @param block [Block] block code to find nodes, match conditions and rewrite code.
21
+ # @return [Synvert::Rewriter::Instance]
7
22
  def initialize(file_pattern, &block)
8
23
  @actions = []
9
24
  @file_pattern = file_pattern
10
25
  @block = block
11
26
  end
12
27
 
28
+ # Process the instance.
29
+ # It finds all files, for each file, it executes the block code, gets all rewrite actions,
30
+ # and rewrite source code back to original file.
13
31
  def process
14
32
  parser = Parser::CurrentRuby.new
15
33
  file_pattern = File.join(Configuration.instance.get(:path), @file_pattern)
@@ -41,50 +59,97 @@ module Synvert
41
59
  end
42
60
  end
43
61
 
62
+ # Gets current node, it allows to get current node in block code.
63
+ #
64
+ # @return [Parser::AST::Node]
44
65
  def node
45
66
  @current_node
46
67
  end
47
68
 
69
+ #######
70
+ # DSL #
71
+ #######
72
+
73
+ # Parse within_node dsl, it creates a [Synvert::Rewriter::Scope] to find matching ast nodes,
74
+ # then continue operating on each matching ast node.
75
+ #
76
+ # @param rules [Hash] rules to find mathing ast nodes.
77
+ # @param block [Block] block code to continue operating on the matching nodes.
48
78
  def within_node(rules, &block)
49
79
  Rewriter::Scope.new(self, rules, &block).process
50
80
  end
51
81
 
52
82
  alias with_node within_node
53
83
 
84
+ # Parse if_exist_node dsl, it creates a [Synvert::Rewriter::IfExistCondition] to check
85
+ # if matching nodes exist in the child nodes, if so, then continue operating on each matching ast node.
86
+ #
87
+ # @param rules [Hash] rules to check mathing ast nodes.
88
+ # @param block [Block] block code to continue operating on the matching nodes.
54
89
  def if_exist_node(rules, &block)
55
90
  Rewriter::IfExistCondition.new(self, rules, &block).process
56
91
  end
57
92
 
93
+ # Parse unless_exist_node dsl, it creates a [Synvert::Rewriter::UnlessExistCondition] to check
94
+ # if matching nodes doesn't exist in the child nodes, if so, then continue operating on each matching ast node.
95
+ #
96
+ # @param rules [Hash] rules to check mathing ast nodes.
97
+ # @param block [Block] block code to continue operating on the matching nodes.
58
98
  def unless_exist_node(rules, &block)
59
99
  Rewriter::UnlessExistCondition.new(self, rules, &block).process
60
100
  end
61
101
 
102
+ # Parse if_only_exist_node dsl, it creates a [Synvert::Rewriter::IfOnlyExistCondition] to check
103
+ # if current node has only one child node and the child node matches rules,
104
+ # if so, then continue operating on each matching ast node.
105
+ #
106
+ # @param rules [Hash] rules to check mathing ast nodes.
107
+ # @param block [Block] block code to continue operating on the matching nodes.
62
108
  def if_only_exist_node(rules, &block)
63
109
  Rewriter::IfOnlyExistCondition.new(self, rules, &block).process
64
110
  end
65
111
 
112
+ # Parse append dsl, it creates a [Synvert::Rewriter::AppendAction] to
113
+ # append the code to the bottom of current node body.
114
+ #
115
+ # @param code [String] code need to be appended.
66
116
  def append(code)
67
117
  @actions << Rewriter::AppendAction.new(self, code)
68
118
  end
69
119
 
120
+ # Parse insert dsl, it creates a [Synvert::Rewriter::InsertAction] to
121
+ # insert the code to the top of current node body.
122
+ #
123
+ # @param code [String] code need to be inserted.
70
124
  def insert(code)
71
125
  @actions << Rewriter::InsertAction.new(self, code)
72
126
  end
73
127
 
128
+ # Parse insert_after dsl, it creates a [Synvert::Rewriter::InsertAfterAction] to
129
+ # insert the code next to the current node.
130
+ #
131
+ # @param code [String] code need to be inserted.
74
132
  def insert_after(node)
75
133
  @actions << Rewriter::InsertAfterAction.new(self, node)
76
134
  end
77
135
 
136
+ # Parse replace_with dsl, it creates a [Synvert::Rewriter::ReplaceWithAction] to
137
+ # replace current node with code.
138
+ #
139
+ # @param code [String] code need to be replaced with.
78
140
  def replace_with(code)
79
141
  @actions << Rewriter::ReplaceWithAction.new(self, code)
80
142
  end
81
143
 
144
+ # Parse remove dsl, it creates a [Synvert::Rewriter::RemoveAction] to current node.
82
145
  def remove
83
146
  @actions << Rewriter::RemoveAction.new(self)
84
147
  end
85
148
 
86
149
  private
87
150
 
151
+ # It changes source code from bottom to top, and it can change source code twice at the same time.
152
+ # So if there is an overlap between two actions, it removes the conflict actions and operate them in the next loop.
88
153
  def check_conflict_actions
89
154
  i = @actions.length - 1
90
155
  @conflict_actions = []
@@ -97,6 +162,10 @@ module Synvert
97
162
  @conflict_actions
98
163
  end
99
164
 
165
+ # It checks if code is removed and that line is empty.
166
+ #
167
+ # @param source [String] source code of file
168
+ # @param line [String] the line number
100
169
  def remove_code_or_whole_line(source, line)
101
170
  newline_at_end_of_line = source[-1] == "\n"
102
171
  source_arr = source.split("\n")
@@ -1,13 +1,21 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Synvert
4
+ # Scope finds the child nodes which match rules.
4
5
  class Rewriter::Scope
6
+ # Initialize a scope
7
+ #
8
+ # @param instance [Synvert::Rewriter::Instance]
9
+ # @param rules [Hash]
10
+ # @param block [Block]
5
11
  def initialize(instance, rules, &block)
6
12
  @instance = instance
7
13
  @rules = rules
8
14
  @block = block
9
15
  end
10
16
 
17
+ # Find the matching nodes. It checks the current node and iterates all child nodes,
18
+ # then run the block code for each matching node.
11
19
  def process
12
20
  current_node = @instance.current_node
13
21
  return unless current_node
@@ -27,6 +35,8 @@ module Synvert
27
35
 
28
36
  private
29
37
 
38
+ # Set instance current node properly and process.
39
+ # @param node [Parser::AST::Node]
30
40
  def process_with_node(node)
31
41
  @instance.current_node = node
32
42
  yield
@@ -1,4 +1,20 @@
1
+ # encoding: utf-8
2
+
1
3
  module Synvert
4
+ # Rewriter is the top level namespace in a snippet.
5
+ #
6
+ # One Rewriter can contain one or many [Synvert::Rewriter::Instance],
7
+ # which define the behavior what files and what codes to detect and rewrite to what code.
8
+ #
9
+ # Synvert::Rewriter.new 'factory_girl_short_syntax', 'use FactoryGirl short syntax' do
10
+ # if_gem 'factory_girl', {gte: '2.0.0'}
11
+ #
12
+ # within_files 'spec/**/*.rb' do
13
+ # with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
14
+ # replace_with "create({{arguments}})"
15
+ # end
16
+ # end
17
+ # end
2
18
  class Rewriter
3
19
  autoload :Action, 'synvert/rewriter/action'
4
20
  autoload :AppendAction, 'synvert/rewriter/action'
@@ -19,11 +35,28 @@ module Synvert
19
35
  autoload :GemSpec, 'synvert/rewriter/gem_spec'
20
36
 
21
37
  class <<self
38
+ # Register a rewriter with its name.
39
+ #
40
+ # @param name [String] the unique rewriter name.
41
+ # @param rewriter [Synvert::Rewriter] the rewriter to register.
22
42
  def register(name, rewriter)
23
43
  @rewriters ||= {}
24
44
  @rewriters[name.to_s] = rewriter
25
45
  end
26
46
 
47
+ # Fetch a rewriter by name.
48
+ #
49
+ # @param name [String] rewrtier name.
50
+ # @return [Synvert::Rewriter] the matching rewriter.
51
+ def fetch(name)
52
+ @rewriters[name.to_s]
53
+ end
54
+
55
+ # Get a registered rewriter by name and process that rewriter.
56
+ #
57
+ # @param name [String] the rewriter name.
58
+ # @return [Synvert::Rewriter] the registered rewriter.
59
+ # @raise [Synvert::RewriterNotFound] if the registered rewriter is not found.
27
60
  def call(name)
28
61
  if (rewriter = @rewriters[name.to_s])
29
62
  rewriter.process
@@ -33,34 +66,87 @@ module Synvert
33
66
  end
34
67
  end
35
68
 
69
+ # Get all available rewriters
70
+ #
71
+ # @return [Array<Synvert::Rewriter>]
36
72
  def availables
37
73
  @rewriters.values
38
74
  end
39
75
 
76
+ # Clear all registered rewriters.
40
77
  def clear
41
78
  @rewriters.clear
42
79
  end
43
80
  end
44
81
 
45
- attr_reader :name, :description, :todo_list
46
-
47
- def initialize(name, description, &block)
82
+ # @!attribute [r] name
83
+ # @return [String] the unique name of rewriter
84
+ # @!attribute [r] sub_snippets
85
+ # @return [Array<Synvert::Rewriter>] all rewriters this rewiter calls.
86
+ attr_reader :name, :sub_snippets
87
+
88
+ # Initialize a rewriter.
89
+ # When a rewriter is initialized, it is also registered.
90
+ #
91
+ # @param name [String] name of the rewriter.
92
+ # @param block [Block] a block defines the behaviors of the rewriter, block code won't be called when initialization.
93
+ # @return [Synvert::Rewriter]
94
+ def initialize(name, &block)
48
95
  @name = name
49
- @description = description
50
96
  @block = block
51
97
  @helpers = []
98
+ @sub_snippets = []
52
99
  self.class.register(name, self)
53
100
  end
54
101
 
102
+ # Process the rewriter.
103
+ # It will call the block.
55
104
  def process
56
105
  self.instance_eval &@block
57
106
  end
58
107
 
108
+ # Process rewriter with sandbox mode.
109
+ # It will call the block but doesn't change any file.
110
+ def process_with_sandbox
111
+ @sandbox = true
112
+ self.process
113
+ @sandbox = false
114
+ end
115
+
116
+ #######
117
+ # DSL #
118
+ #######
119
+
120
+ # Parse description dsl, it sets description of the rewrite.
121
+ # Or get description.
122
+ #
123
+ # @param description [String] rewriter description.
124
+ # @return rewriter description.
125
+ def description(description=nil)
126
+ if description
127
+ @description = description
128
+ else
129
+ @description
130
+ end
131
+ end
132
+
133
+ # Parse if_gem dsl, it compares version of the specified gem.
134
+ #
135
+ # @param name [String] gem name.
136
+ # @param comparator [Hash] equal, less than or greater than specified version, e.g. {gte: '2.0.0'},
137
+ # key can be eq, lt, gt, lte, gte or ne.
59
138
  def if_gem(name, comparator)
60
139
  @gem_spec = Rewriter::GemSpec.new(name, comparator)
61
140
  end
62
141
 
63
- def within_file(file_pattern, &block)
142
+ # Parse within_files dsl, it finds specified files.
143
+ # It creates a [Synvert::Rewriter::Instance] to rewrite code.
144
+ #
145
+ # @param file_pattern [String] pattern to find files, e.g. spec/**/*_spec.rb
146
+ # @param block [Block] the block to rewrite code in the matching files.
147
+ def within_files(file_pattern, &block)
148
+ return if @sandbox
149
+
64
150
  if !@gem_spec || @gem_spec.match?
65
151
  instance = Rewriter::Instance.new(file_pattern, &block)
66
152
  @helpers.each { |helper| instance.singleton_class.send(:define_method, helper[:name], &helper[:block]) }
@@ -68,24 +154,47 @@ module Synvert
68
154
  end
69
155
  end
70
156
 
71
- alias within_files within_file
157
+ # Parse within_file dsl, it finds a specifiled file.
158
+ alias within_file within_files
159
+
160
+ # Parses add_file dsl, it adds a new file.
161
+ #
162
+ # @param filename [String] file name of newly created file.
163
+ # @param content [String] file body of newly created file.
164
+ def add_file(filename, content)
165
+ return if @sandbox
72
166
 
73
- def add_file(file, content)
74
- File.open file, 'w' do |file|
167
+ File.open filename, 'w' do |file|
75
168
  file.write content
76
169
  end
77
170
  end
78
171
 
172
+ # Parse add_snippet dsl, it calls anther rewriter.
173
+ #
174
+ # @param name [String] name of another rewriter.
79
175
  def add_snippet(name)
80
- self.class.call(name)
176
+ @sub_snippets << self.class.call(name)
81
177
  end
82
178
 
179
+ # Parse helper_method dsl, it defines helper method for [Synvert::Rewriter::Instance].
180
+ #
181
+ # @param name [String] helper method name.
182
+ # @param block [Block] helper method block.
83
183
  def helper_method(name, &block)
84
184
  @helpers << {name: name, block: block}
85
185
  end
86
186
 
87
- def todo(list)
88
- @todo_list = list
187
+ # Parse todo dsl, it sets todo of the rewriter.
188
+ # Or get todo.
189
+ #
190
+ # @param todo_list [String] rewriter todo.
191
+ # @return [String] rewriter todo.
192
+ def todo(todo=nil)
193
+ if todo
194
+ @todo = todo
195
+ else
196
+ @todo
197
+ end
89
198
  end
90
199
  end
91
200
  end