synvert 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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