synvert 0.0.13 → 0.0.14

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 (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