synvert 0.0.3 → 0.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee5d52cf95df07b26f5bb50cbee385209ce3b59d
4
- data.tar.gz: b077dd95e2e34be6c39af959ca9d9a7fc3352ecb
3
+ metadata.gz: a16d51a6f5e6376390a8d50951f1adaca53f6737
4
+ data.tar.gz: 295744d184ca5bbea1cf1faa0fef5428aeb8a402
5
5
  SHA512:
6
- metadata.gz: e3b9411dc8752fada8cd1a86eebb995d38e82fcdcc4169f6ef69941b743bbb025c3bf2e29015af3827f6d9116e7564b235f6d32ced48728ad30762e8380e389d
7
- data.tar.gz: 372f93f527fa4d6a22c07f5b8c1bca2b178d9589df2155f1ec67b67486ea8abacd47a269ffecc9dbe931d2a45f56df2c2532fae4f2c2f78ade50cc18bbc49b5e
6
+ metadata.gz: 259cbde5e5e77897abcf7f7c3c0557f9ecfe13ce4ba0638035dbf96147c536465818044cdaa10cc648bd487bf54806aca1c8d1208a358c6a4d530ef8c56892c8
7
+ data.tar.gz: 52fc74d210b5236e2cccb196d460a485421c99f47d7d825b86d86edb4f6813195cea04b5bd1b5a3ae8ecd2dd6e59fb9250aef407266b12ed0952968d2be8affd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.0.4
4
+
5
+ * Test snippets
6
+ * Lazily execute blocks that allows executing any ruby code
7
+ * Be able to save parsed data and use them later
8
+
3
9
  ## 0.0.3
4
10
 
5
11
  * Add snippet to upgrade rails 3.2 to rails 4.0
data/lib/synvert.rb CHANGED
@@ -4,6 +4,7 @@ require 'bundler'
4
4
  require 'parser'
5
5
  require 'parser/current'
6
6
  require 'ast'
7
+ require 'active_support/inflector'
7
8
  require 'synvert/node_ext'
8
9
 
9
10
  module Synvert
@@ -1,6 +1,6 @@
1
1
  class Parser::AST::Node
2
2
  def name
3
- if :class == self.type
3
+ if [:class, :def].include? self.type
4
4
  self.children[0]
5
5
  else
6
6
  raise NotImplementedError.new "name is not handled for #{self.inspect}"
@@ -60,25 +60,9 @@ class Parser::AST::Node
60
60
  end
61
61
  end
62
62
 
63
- def to_ast
64
- self
65
- end
66
-
67
- def to_s
68
- case self.type
69
- when :const
70
- self.children.compact.map(&:to_s).join('::')
71
- when :sym
72
- ':' + self.children[0].to_s
73
- when :str
74
- "'" + self.children[0].to_s + "'"
75
- when :arg, :lvar, :ivar
76
- self.children[0].to_s
77
- when :self
78
- 'self'
79
- when :send
80
- self.children[1].to_s
81
- else
63
+ def source(instance)
64
+ if self.loc.expression
65
+ instance.current_source[self.loc.expression.begin_pos...self.loc.expression.end_pos]
82
66
  end
83
67
  end
84
68
 
@@ -101,21 +85,21 @@ class Parser::AST::Node
101
85
  end
102
86
  end
103
87
 
104
- def match?(options)
88
+ def match?(instance, options)
105
89
  flat_hash(options).keys.all? do |multi_keys|
106
90
  if multi_keys.last == :any
107
- actual_values = actual_value(self, multi_keys[0...-1])
91
+ actual_values = actual_value(self, instance, multi_keys[0...-1])
108
92
  expected = expected_value(options, multi_keys)
109
- actual_values.any? { |actual| match_value?(actual, expected) }
93
+ actual_values.any? { |actual| match_value?(instance, actual, expected) }
110
94
  else
111
- actual = actual_value(self, multi_keys)
95
+ actual = actual_value(self, instance, multi_keys)
112
96
  expected = expected_value(options, multi_keys)
113
- match_value?(actual, expected)
97
+ match_value?(instance, actual, expected)
114
98
  end
115
99
  end
116
100
  end
117
101
 
118
- def to_source(code)
102
+ def rewritten_source(code)
119
103
  code.gsub(/{{(.*?)}}/m) do
120
104
  evaluated = self.instance_eval $1
121
105
  case evaluated
@@ -128,23 +112,31 @@ class Parser::AST::Node
128
112
  when String
129
113
  evaluated
130
114
  else
131
- raise NotImplementedError.new "to_source is not handled for #{evaluated.inspect}"
115
+ raise NotImplementedError.new "rewritten_source is not handled for #{evaluated.inspect}"
132
116
  end
133
117
  end
134
118
  end
135
119
 
136
120
  private
137
121
 
138
- def match_value?(actual, expected)
122
+ def match_value?(instance, actual, expected)
139
123
  case expected
140
124
  when Symbol
141
125
  actual.to_sym == expected
142
126
  when String
143
- actual.to_s == expected || actual.to_s == "'#{expected}'"
127
+ if Parser::AST::Node === actual
128
+ actual.source(instance) == expected
129
+ else
130
+ actual.to_s == expected
131
+ end
144
132
  when Regexp
145
- actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
133
+ if Parser::AST::Node === actual
134
+ actual.source(instance) =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
135
+ else
136
+ actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
137
+ end
146
138
  when Array
147
- actual.zip(expected).all? { |a, e| match_value?(a, e) }
139
+ actual.zip(expected).all? { |a, e| match_value?(instance, a, e) }
148
140
  when NilClass
149
141
  actual.nil?
150
142
  when Parser::AST::Node
@@ -166,8 +158,12 @@ private
166
158
  new_hash
167
159
  end
168
160
 
169
- def actual_value(node, multi_keys)
170
- multi_keys.inject(node) { |n, key| n.send(key) if n }
161
+ def actual_value(node, instance, multi_keys)
162
+ multi_keys.inject(node) { |n, key|
163
+ if n
164
+ key == :source ? n.send(key, instance) : n.send(key)
165
+ end
166
+ }
171
167
  end
172
168
 
173
169
  def expected_value(options, multi_keys)
@@ -1,6 +1,7 @@
1
1
  module Synvert
2
2
  class Rewriter
3
3
  autoload :Action, 'synvert/rewriter/action'
4
+ autoload :AppendAction, 'synvert/rewriter/action'
4
5
  autoload :InsertAction, 'synvert/rewriter/action'
5
6
  autoload :InsertAfterAction, 'synvert/rewriter/action'
6
7
  autoload :ReplaceWithAction, 'synvert/rewriter/action'
@@ -20,14 +21,21 @@ module Synvert
20
21
 
21
22
  def initialize(description, &block)
22
23
  @description = description
23
- @instances = []
24
- instance_eval &block if block_given?
24
+ @block = block
25
+ @assignments = {}
26
+ end
27
+
28
+ def set(name, key, value)
29
+ @assignments[name] ||= {}
30
+ @assignments[name][key] = value
31
+ end
32
+
33
+ def get(name, key)
34
+ @assignments[name] and @assignments[name][key]
25
35
  end
26
36
 
27
37
  def process
28
- if @gem_spec.match?
29
- @instances.each { |instance| instance.process }
30
- end
38
+ self.instance_eval &@block
31
39
  end
32
40
 
33
41
  def gem_spec(name, version)
@@ -35,9 +43,9 @@ module Synvert
35
43
  end
36
44
 
37
45
  def within_file(file_pattern, &block)
38
- instance = Rewriter::Instance.new(file_pattern)
39
- instance.instance_eval &block if block_given?
40
- @instances << instance
46
+ if @gem_spec.match?
47
+ Rewriter::Instance.new(self, file_pattern, &block).process
48
+ end
41
49
  end
42
50
 
43
51
  alias within_files within_file
@@ -2,42 +2,92 @@
2
2
 
3
3
  module Synvert
4
4
  class Rewriter::Action
5
- def initialize(code)
5
+ def initialize(instance, code)
6
+ @instance = instance
6
7
  @code = code
8
+ @node = @instance.current_node
7
9
  end
8
10
 
9
- def rewrite(source, node)
10
- raise NotImplementedError.new 'rewrite method is not implemented'
11
+ def line
12
+ @node.loc.expression.line
13
+ end
14
+
15
+ def rewritten_code
16
+ if rewritten_source.split("\n").length > 1
17
+ "\n\n" + rewritten_source.split("\n").map { |line|
18
+ indent(@node) + line
19
+ }.join("\n")
20
+ else
21
+ "\n" + indent(@node) + rewritten_source
22
+ end
23
+ end
24
+
25
+ def rewritten_source
26
+ @rewritten_source ||= @node.rewritten_source(@code)
27
+ end
28
+
29
+ def <=>(action)
30
+ self.begin_pos <=> action.begin_pos
11
31
  end
12
32
  end
13
33
 
14
34
  class Rewriter::ReplaceWithAction < Rewriter::Action
15
- def rewrite(source, node)
16
- begin_pos = node.loc.expression.begin_pos
17
- end_pos = node.loc.expression.end_pos
18
- source[begin_pos...end_pos] = node.to_source(@code)
19
- source
35
+ def begin_pos
36
+ @node.loc.expression.begin_pos
37
+ end
38
+
39
+ def end_pos
40
+ @node.loc.expression.end_pos
41
+ end
42
+
43
+ def rewritten_code
44
+ @node.rewritten_source(@code)
45
+ end
46
+ end
47
+
48
+ class Rewriter::AppendAction < Rewriter::Action
49
+ def begin_pos
50
+ @node.loc.expression.end_pos - 4
51
+ end
52
+
53
+ def end_pos
54
+ begin_pos
55
+ end
56
+
57
+ private
58
+
59
+ def indent(node)
60
+ if [:block, :class].include? node.type
61
+ ' ' * (node.indent + 2)
62
+ else
63
+ ' ' * node.indent
64
+ end
20
65
  end
21
66
  end
22
67
 
23
68
  class Rewriter::InsertAction < Rewriter::Action
24
- def rewrite(source, node)
25
- source[insert_position(node), 0] = "\n" + insert_indent(node) + node.to_source(@code)
26
- source
69
+ def begin_pos
70
+ insert_position(@node)
71
+ end
72
+
73
+ def end_pos
74
+ begin_pos
27
75
  end
28
76
 
77
+ private
78
+
29
79
  def insert_position(node)
30
80
  case node.type
31
81
  when :block
32
- node.children[1].loc.expression.end_pos
82
+ node.children[1].children.empty? ? node.children[0].loc.expression.end_pos + 3 : node.children[1].loc.expression.end_pos
33
83
  when :class
34
- node.children[0].loc.expression.end_pos
84
+ node.children[1] ? node.children[1].loc.expression.end_pos : node.children[0].loc.expression.end_pos
35
85
  else
36
86
  node.children.last.loc.expression.end_pos
37
87
  end
38
88
  end
39
89
 
40
- def insert_indent(node)
90
+ def indent(node)
41
91
  if [:block, :class].include? node.type
42
92
  ' ' * (node.indent + 2)
43
93
  else
@@ -47,38 +97,36 @@ module Synvert
47
97
  end
48
98
 
49
99
  class Rewriter::InsertAfterAction < Rewriter::Action
50
- def rewrite(source, node)
51
- source[node.loc.expression.end_pos, 0] = "\n" + insert_indent(node) + node.to_source(@code)
52
- source
100
+ def begin_pos
101
+ @node.loc.expression.end_pos
53
102
  end
54
103
 
55
- def insert_indent(node)
104
+ def end_pos
105
+ begin_pos
106
+ end
107
+
108
+ private
109
+
110
+ def indent(node)
56
111
  ' ' * node.indent
57
112
  end
58
113
  end
59
114
 
60
115
  class Rewriter::RemoveAction < Rewriter::Action
61
- def initialize
116
+ def initialize(instance, code=nil)
117
+ super
62
118
  end
63
119
 
64
- def rewrite(source, node)
65
- begin_pos = node.loc.expression.begin_pos
66
- end_pos = node.loc.expression.end_pos
67
- line = node.loc.expression.line
68
- source[begin_pos...end_pos] = ''
69
- remove_code_or_whole_line(source, line)
120
+ def begin_pos
121
+ @node.loc.expression.begin_pos
70
122
  end
71
123
 
72
- private
73
- def remove_code_or_whole_line(source, line)
74
- newline_at_end_of_line = source[-1] == "\n"
75
- source_arr = source.split("\n")
76
- if source_arr[line - 1] && source_arr[line - 1].strip.empty?
77
- source_arr.delete_at(line - 1)
78
- source_arr.join("\n") + (newline_at_end_of_line ? "\n" : '')
79
- else
80
- source
81
- end
124
+ def end_pos
125
+ @node.loc.expression.end_pos
126
+ end
127
+
128
+ def rewritten_code
129
+ ''
82
130
  end
83
131
  end
84
132
  end
@@ -2,28 +2,31 @@
2
2
 
3
3
  module Synvert
4
4
  class Rewriter::Condition
5
- def initialize(options)
5
+ def initialize(instance, options, &block)
6
+ @instance = instance
6
7
  @options = options
8
+ @block = block
9
+ end
10
+
11
+ def process
12
+ @instance.instance_eval &@block if match?
7
13
  end
8
14
  end
9
15
 
10
16
  class Rewriter::UnlessExistCondition < Rewriter::Condition
11
- def matching_nodes(nodes)
12
- nodes.find_all { |node|
13
- match = false
14
- node.recursive_children do |child_node|
15
- match = match || (child_node && child_node.match?(@options))
16
- end
17
- !match
18
- }
17
+ def match?
18
+ match = false
19
+ @instance.current_node.recursive_children do |child_node|
20
+ match = match || (child_node && child_node.match?(@instance, @options))
21
+ end
22
+ !match
19
23
  end
20
24
  end
21
25
 
22
26
  class Rewriter::IfOnlyExistCondition < Rewriter::Condition
23
- def matching_nodes(nodes)
24
- nodes.find_all { |node|
25
- :begin != node.body.type && node.body.match?(@options)
26
- }
27
+ def match?
28
+ :begin != @instance.current_node.body.type &&
29
+ @instance.current_node.body.match?(@instance, @options)
27
30
  end
28
31
  end
29
32
  end
@@ -2,64 +2,102 @@
2
2
 
3
3
  module Synvert
4
4
  class Rewriter::Instance
5
- def initialize(file_pattern)
5
+ attr_accessor :current_node, :current_source, :current_file
6
+
7
+ def initialize(rewriter, file_pattern, &block)
8
+ @rewriter = rewriter
9
+ @actions = []
6
10
  @file_pattern = file_pattern
7
- @scopes_or_conditions = []
11
+ @block = block
8
12
  end
9
13
 
10
14
  def process
11
15
  parser = Parser::CurrentRuby.new
12
16
  file_pattern = File.join(Configuration.instance.get(:path), @file_pattern)
13
- Dir.glob(file_pattern).each do |path|
14
- source = File.read(path)
15
- buffer = Parser::Source::Buffer.new path
17
+ Dir.glob(file_pattern).each do |file_path|
18
+ source = File.read(file_path)
19
+ buffer = Parser::Source::Buffer.new file_path
16
20
  buffer.source = source
17
21
 
18
22
  parser.reset
19
23
  ast = parser.parse buffer
20
24
 
21
- matching_nodes = [ast]
22
- @scopes_or_conditions.each do |scope_or_condition|
23
- matching_nodes = scope_or_condition.matching_nodes(matching_nodes)
24
- end
25
- matching_nodes.reverse.each do |node|
26
- source = @action.rewrite(source, node)
25
+ @current_file = file_path
26
+ @current_source = source
27
+ @current_node = ast
28
+ instance_eval &@block
29
+ @current_node = ast
30
+
31
+ @actions.sort.reverse.each do |action|
32
+ source[action.begin_pos...action.end_pos] = action.rewritten_code
33
+ source = remove_code_or_whole_line(source, action.line)
27
34
  end
28
- File.write path, source
35
+ @actions = []
36
+
37
+ File.write file_path, source
29
38
  end
30
39
  end
31
40
 
41
+ def node
42
+ @current_node
43
+ end
44
+
32
45
  def within_node(options, &block)
33
- @scopes_or_conditions << Rewriter::Scope.new(options)
34
- instance_eval &block if block_given?
46
+ Rewriter::Scope.new(self, options, &block).process
35
47
  end
36
48
 
37
49
  alias with_node within_node
38
50
 
39
51
  def unless_exist_node(options, &block)
40
- @scopes_or_conditions << Rewriter::UnlessExistCondition.new(options)
41
- instance_eval &block if block_given?
52
+ Rewriter::UnlessExistCondition.new(self, options, &block).process
42
53
  end
43
54
 
44
55
  def if_only_exist_node(options, &block)
45
- @scopes_or_conditions << Rewriter::IfOnlyExistCondition.new(options)
46
- instance_eval &block if block_given?
56
+ Rewriter::IfOnlyExistCondition.new(self, options, &block).process
57
+ end
58
+
59
+ def append(code)
60
+ @actions << Rewriter::AppendAction.new(self, code)
47
61
  end
48
62
 
49
63
  def insert(code)
50
- @action = Rewriter::InsertAction.new(code)
64
+ @actions << Rewriter::InsertAction.new(self, code)
51
65
  end
52
66
 
53
67
  def insert_after(node)
54
- @action = Rewriter::InsertAfterAction.new(node)
68
+ @actions << Rewriter::InsertAfterAction.new(self, node)
55
69
  end
56
70
 
57
71
  def replace_with(code)
58
- @action = Rewriter::ReplaceWithAction.new(code)
72
+ @actions << Rewriter::ReplaceWithAction.new(self, code)
59
73
  end
60
74
 
61
75
  def remove
62
- @action = Rewriter::RemoveAction.new
76
+ @actions << Rewriter::RemoveAction.new(self)
77
+ end
78
+
79
+ def assign(name, key, value)
80
+ @rewriter.set name, key, value
81
+ end
82
+
83
+ def fetch(name, key)
84
+ @rewriter.get name, key
85
+ end
86
+
87
+ private
88
+
89
+ def remove_code_or_whole_line(source, line)
90
+ newline_at_end_of_line = source[-1] == "\n"
91
+ source_arr = source.split("\n")
92
+ if source_arr[line - 1] && source_arr[line - 1].strip.empty?
93
+ source_arr.delete_at(line - 1)
94
+ if source_arr[line - 2] && source_arr[line - 2].strip.empty? && source_arr[line - 1] && source_arr[line - 1].strip.empty?
95
+ source_arr.delete_at(line - 1)
96
+ end
97
+ source_arr.join("\n") + (newline_at_end_of_line ? "\n" : '')
98
+ else
99
+ source
100
+ end
63
101
  end
64
102
  end
65
103
  end