synvert-core 0.3.0 → 0.4.0
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 +4 -4
- data/CHANGELOG.md +9 -3
- data/lib/synvert/core.rb +2 -0
- data/lib/synvert/core/engine.rb +8 -0
- data/lib/synvert/core/engine/erb.rb +139 -0
- data/lib/synvert/core/node_ext.rb +10 -1
- data/lib/synvert/core/rewriter.rb +1 -0
- data/lib/synvert/core/rewriter/action.rb +38 -0
- data/lib/synvert/core/rewriter/instance.rb +8 -0
- data/lib/synvert/core/version.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- data/spec/synvert/core/engine/erb_spec.rb +45 -0
- data/spec/synvert/core/node_ext_spec.rb +17 -0
- data/synvert-core.gemspec +1 -0
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e006c23fc6ca2d1398bfaf32db73c4ced664a94e
|
4
|
+
data.tar.gz: d7dc0a2a30fb4e544f4bd25307b4177ed6914f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c05837b831a3c9aa02c1c0bd5a88adeeddafd98114a562462749d3f92a4728b0fd1e38415cd26d7816a46705c5528285a33705c480018abdb59fb9a9c82d01bd
|
7
|
+
data.tar.gz: 857e3cbd4cfc5ca0c77dc452e615a23006436418c600b09c6738dbee267abbb71042ddbc1a2b7a0b65f531cef0b24811ee19b8fa6edfa97ef9043a32cd77a025
|
data/CHANGELOG.md
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 0.4.0 (2014-07-26)
|
4
|
+
|
5
|
+
* Add erb support
|
6
|
+
* Add replace_erb_stmt_with_expr dsl
|
7
|
+
* Improve Parser::AST::Node#to_value
|
8
|
+
|
9
|
+
## 0.3.0 (2014-07-12)
|
4
10
|
|
5
11
|
* Rename node.source(instance) to node.to_source
|
6
12
|
* Add has_key? and hash_value helper methods for hash node
|
7
13
|
* Fix Instance#check_conflict_actions
|
8
14
|
|
9
|
-
## 0.2.0
|
15
|
+
## 0.2.0 (2014-05-16)
|
10
16
|
|
11
17
|
* Add remove_file dsl
|
12
18
|
* Add warn dsl
|
13
19
|
* Return empty array if no available rewriters
|
14
20
|
|
15
|
-
## 0.1.0
|
21
|
+
## 0.1.0 (2014-05-04)
|
16
22
|
|
17
23
|
* Abstract from synvert
|
data/lib/synvert/core.rb
CHANGED
@@ -7,12 +7,14 @@ require 'parser'
|
|
7
7
|
require 'parser/current'
|
8
8
|
require 'ast'
|
9
9
|
require 'active_support/inflector'
|
10
|
+
require 'erubis'
|
10
11
|
require 'synvert/core/node_ext'
|
11
12
|
|
12
13
|
module Synvert
|
13
14
|
module Core
|
14
15
|
autoload :Configuration, 'synvert/core/configuration'
|
15
16
|
autoload :Rewriter, 'synvert/core/rewriter'
|
17
|
+
autoload :Engine, 'synvert/core/engine'
|
16
18
|
autoload :RewriterNotFound, 'synvert/core/exceptions'
|
17
19
|
autoload :GemfileLockNotFound, 'synvert/core/exceptions'
|
18
20
|
autoload :MethodNotSupported, 'synvert/core/exceptions'
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'erubis'
|
3
|
+
|
4
|
+
module Synvert::Core
|
5
|
+
module Engine
|
6
|
+
ERUBY_EXPR_SPLITTER = "; ;"
|
7
|
+
ERUBY_STMT_SPLITTER = "; ;"
|
8
|
+
|
9
|
+
class ERB
|
10
|
+
class <<self
|
11
|
+
# convert erb to ruby code.
|
12
|
+
#
|
13
|
+
# @param source [String] erb source code.
|
14
|
+
# @return [String] ruby source code.
|
15
|
+
def encode(source)
|
16
|
+
Erubis.new(source.gsub("-%>", "%>"), :escape => false, :trim => false).src
|
17
|
+
end
|
18
|
+
|
19
|
+
# convert ruby code to erb.
|
20
|
+
#
|
21
|
+
# @param source [String] ruby source code.
|
22
|
+
# @return [String] erb source code.
|
23
|
+
def decode(source)
|
24
|
+
source = decode_ruby_stmt(source)
|
25
|
+
source = decode_ruby_output(source)
|
26
|
+
source = decode_html_output(source)
|
27
|
+
source = remove_erubis_buf(source)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def decode_ruby_stmt(source)
|
33
|
+
source.gsub(/#{ERUBY_STMT_SPLITTER}(.+?)#{ERUBY_STMT_SPLITTER}/m) { "<%#{$1}%>" }
|
34
|
+
end
|
35
|
+
|
36
|
+
def decode_ruby_output(source)
|
37
|
+
source.gsub(/@output_buffer.append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m) { "<%=#{$1}%>" }
|
38
|
+
.gsub(/@output_buffer.append= (.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m) { |m| "<%=#{m.sub("@output_buffer.append= ", "").sub(ERUBY_EXPR_SPLITTER, "")}%>" }
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_html_output(source)
|
42
|
+
source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text($1) }
|
43
|
+
.gsub(/@output_buffer.safe_append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m) { reverse_escape_text($1) }
|
44
|
+
.gsub(/@output_buffer.safe_append=(.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m) { reverse_escape_text($1) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_erubis_buf(source)
|
48
|
+
source.sub("@output_buffer = output_buffer || ActionView::OutputBuffer.new;", "").sub("@output_buffer.to_s", "")
|
49
|
+
end
|
50
|
+
|
51
|
+
def reverse_escape_text(source)
|
52
|
+
source.gsub("\\\\", "\\").gsub("\\'", "'")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# borrowed from rails
|
58
|
+
class Erubis < ::Erubis::Eruby
|
59
|
+
def add_preamble(src)
|
60
|
+
@newline_pending = 0
|
61
|
+
src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_text(src, text)
|
65
|
+
return if text.empty?
|
66
|
+
|
67
|
+
if text == "\n"
|
68
|
+
@newline_pending += 1
|
69
|
+
else
|
70
|
+
src << "@output_buffer.safe_append='"
|
71
|
+
src << "\n" * @newline_pending if @newline_pending > 0
|
72
|
+
src << escape_text(text)
|
73
|
+
src << "'.freeze;"
|
74
|
+
|
75
|
+
@newline_pending = 0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Erubis toggles <%= and <%== behavior when escaping is enabled.
|
80
|
+
# We override to always treat <%== as escaped.
|
81
|
+
def add_expr(src, code, indicator)
|
82
|
+
case indicator
|
83
|
+
when '=='
|
84
|
+
add_expr_escaped(src, code)
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
91
|
+
|
92
|
+
def add_expr_literal(src, code)
|
93
|
+
flush_newline_if_pending(src)
|
94
|
+
if code =~ BLOCK_EXPR
|
95
|
+
src << '@output_buffer.append= ' << code << ERUBY_EXPR_SPLITTER
|
96
|
+
else
|
97
|
+
src << '@output_buffer.append=(' << code << ');' << ERUBY_EXPR_SPLITTER
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_expr_escaped(src, code)
|
102
|
+
flush_newline_if_pending(src)
|
103
|
+
if code =~ BLOCK_EXPR
|
104
|
+
src << "@output_buffer.safe_append= " << code << ERUBY_EXPR_SPLITTER
|
105
|
+
else
|
106
|
+
src << "@output_buffer.safe_append=(" << code << ");" << ERUBY_EXPR_SPLITTER
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_stmt(src, code)
|
111
|
+
flush_newline_if_pending(src)
|
112
|
+
if code != "\n" && code != ""
|
113
|
+
index = if code =~ /\A(\s*)\r?\n/
|
114
|
+
$1.length
|
115
|
+
elsif code =~ /\A(\s+)/
|
116
|
+
$1.end_with?(' ') ? $1.length - 1 : $1.length
|
117
|
+
else
|
118
|
+
0
|
119
|
+
end
|
120
|
+
code.insert(index, ERUBY_STMT_SPLITTER)
|
121
|
+
code.insert(-1, ERUBY_STMT_SPLITTER[0...-1])
|
122
|
+
end
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def add_postamble(src)
|
127
|
+
flush_newline_if_pending(src)
|
128
|
+
src << '@output_buffer.to_s'
|
129
|
+
end
|
130
|
+
|
131
|
+
def flush_newline_if_pending(src)
|
132
|
+
if @newline_pending > 0
|
133
|
+
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
|
134
|
+
@newline_pending = 0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -176,10 +176,18 @@ class Parser::AST::Node
|
|
176
176
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
177
177
|
def to_value
|
178
178
|
case self.type
|
179
|
-
when :str, :sym
|
179
|
+
when :int, :str, :sym
|
180
180
|
self.children.last
|
181
|
+
when :true
|
182
|
+
true
|
183
|
+
when :false
|
184
|
+
false
|
181
185
|
when :array
|
182
186
|
self.children.map(&:to_value)
|
187
|
+
when :irange
|
188
|
+
(self.children.first.to_value..self.children.last.to_value)
|
189
|
+
when :begin
|
190
|
+
self.children.first.to_value
|
183
191
|
else
|
184
192
|
raise Synvert::Core::MethodNotSupported.new "to_value is not handled for #{self.inspect}"
|
185
193
|
end
|
@@ -295,6 +303,7 @@ private
|
|
295
303
|
actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
|
296
304
|
end
|
297
305
|
when Array
|
306
|
+
return false unless expected.length == actual.length
|
298
307
|
actual.zip(expected).all? { |a, e| match_value?(a, e) }
|
299
308
|
when NilClass
|
300
309
|
actual.nil?
|
@@ -21,6 +21,7 @@ module Synvert::Core
|
|
21
21
|
autoload :InsertAction, 'synvert/core/rewriter/action'
|
22
22
|
autoload :InsertAfterAction, 'synvert/core/rewriter/action'
|
23
23
|
autoload :ReplaceWithAction, 'synvert/core/rewriter/action'
|
24
|
+
autoload :ReplaceErbStmtWithExprAction, 'synvert/core/rewriter/action'
|
24
25
|
autoload :RemoveAction, 'synvert/core/rewriter/action'
|
25
26
|
|
26
27
|
autoload :Warning, 'synvert/core/rewriter/warning'
|
@@ -221,4 +221,42 @@ module Synvert::Core
|
|
221
221
|
''
|
222
222
|
end
|
223
223
|
end
|
224
|
+
|
225
|
+
# ReplaceErbStmtWithExprAction to replace erb stmt code to expr,
|
226
|
+
# e.g. <% form_for ... %> => <%= form_for ... %>.
|
227
|
+
class Rewriter::ReplaceErbStmtWithExprAction < Rewriter::Action
|
228
|
+
def initialize(instance, code=nil)
|
229
|
+
super
|
230
|
+
end
|
231
|
+
|
232
|
+
# Begin position of code to replace.
|
233
|
+
#
|
234
|
+
# @return [Integer] begin position.
|
235
|
+
def begin_pos
|
236
|
+
node_begin_pos = @node.loc.expression.begin_pos
|
237
|
+
while @instance.current_source[node_begin_pos -= 1] == ' '
|
238
|
+
end
|
239
|
+
node_begin_pos - Engine::ERUBY_STMT_SPLITTER.length + 1
|
240
|
+
end
|
241
|
+
|
242
|
+
# End position of code to replace.
|
243
|
+
#
|
244
|
+
# @return [Integer] end position.
|
245
|
+
def end_pos
|
246
|
+
node_begin_pos = @node.loc.expression.begin_pos
|
247
|
+
node_end_pos = @node.loc.expression.end_pos
|
248
|
+
node_begin_pos += @instance.current_source[node_begin_pos..node_end_pos].index "do"
|
249
|
+
while @instance.current_source[node_begin_pos += 1] != '@'
|
250
|
+
end
|
251
|
+
node_begin_pos
|
252
|
+
end
|
253
|
+
|
254
|
+
# The rewritten erb expr code.
|
255
|
+
#
|
256
|
+
# @return [String] rewritten code.
|
257
|
+
def rewritten_code
|
258
|
+
@instance.current_source[begin_pos...end_pos].sub(Engine::ERUBY_STMT_SPLITTER, "@output_buffer.append= ")
|
259
|
+
.sub(Engine::ERUBY_STMT_SPLITTER, Engine::ERUBY_EXPR_SPLITTER)
|
260
|
+
end
|
261
|
+
end
|
224
262
|
end
|
@@ -44,6 +44,7 @@ module Synvert::Core
|
|
44
44
|
unless Configuration.instance.get(:skip_files).include? file_path
|
45
45
|
begin
|
46
46
|
source = File.read(file_path)
|
47
|
+
source = Engine::ERB.encode(source) if file_path =~ /\.erb$/
|
47
48
|
buffer = Parser::Source::Buffer.new file_path
|
48
49
|
buffer.source = source
|
49
50
|
|
@@ -64,6 +65,7 @@ module Synvert::Core
|
|
64
65
|
end
|
65
66
|
@actions = []
|
66
67
|
|
68
|
+
source = Engine::ERB.decode(source) if file_path =~ /\.erb/
|
67
69
|
File.write file_path, source
|
68
70
|
end while !@conflict_actions.empty?
|
69
71
|
end
|
@@ -152,6 +154,12 @@ module Synvert::Core
|
|
152
154
|
@actions << Rewriter::ReplaceWithAction.new(self, code)
|
153
155
|
end
|
154
156
|
|
157
|
+
# Parse replace_erb_stmt_with_expr dsl, it creates a [Synvert::Core::Rewriter::ReplaceErbStmtWithExprAction] to
|
158
|
+
# replace erb stmt code to expr code.
|
159
|
+
def replace_erb_stmt_with_expr
|
160
|
+
@actions << Rewriter::ReplaceErbStmtWithExprAction.new(self)
|
161
|
+
end
|
162
|
+
|
155
163
|
# Parse remove dsl, it creates a [Synvert::Core::Rewriter::RemoveAction] to current node.
|
156
164
|
def remove
|
157
165
|
@actions << Rewriter::RemoveAction.new(self)
|
data/lib/synvert/core/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Synvert::Core
|
4
|
+
describe Engine::ERB do
|
5
|
+
it "encodes / decodes" do
|
6
|
+
source =<<-EOF
|
7
|
+
<%content_for :head do%>
|
8
|
+
<style>
|
9
|
+
body {
|
10
|
+
background-image: url(<%= asset_path('bg.png') %>);
|
11
|
+
}
|
12
|
+
</style>
|
13
|
+
<%end%>
|
14
|
+
|
15
|
+
<%
|
16
|
+
foo = 'bar'
|
17
|
+
post = Post.find(:first)
|
18
|
+
bar = 'foo'
|
19
|
+
%>
|
20
|
+
|
21
|
+
<% if User.current &&
|
22
|
+
User.current.admin %>
|
23
|
+
<%= rounded_content("page") do %>
|
24
|
+
<div class='test'>
|
25
|
+
<% if post %>
|
26
|
+
<div id="title"><%= foo %></div>
|
27
|
+
<% form_for post do |f| %>
|
28
|
+
<label><%= link_to_function 'test', "confirm('test');" %></label>
|
29
|
+
<%= f.text_field 'bar' %>
|
30
|
+
<% end %>
|
31
|
+
<% end %></div>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
EOF
|
35
|
+
encoded_source = Engine::ERB.encode(source)
|
36
|
+
buffer = Parser::Source::Buffer.new "(test)"
|
37
|
+
buffer.source = encoded_source
|
38
|
+
parser = Parser::CurrentRuby.new
|
39
|
+
parser.reset
|
40
|
+
parser.parse buffer
|
41
|
+
|
42
|
+
expect(Engine::ERB.decode(encoded_source)).to eq source
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -149,6 +149,11 @@ describe Parser::AST::Node do
|
|
149
149
|
end
|
150
150
|
|
151
151
|
describe "#to_value" do
|
152
|
+
it 'gets for int' do
|
153
|
+
node = parse("1")
|
154
|
+
expect(node.to_value).to eq 1
|
155
|
+
end
|
156
|
+
|
152
157
|
it 'gets for string' do
|
153
158
|
node = parse("'str'")
|
154
159
|
expect(node.to_value).to eq "str"
|
@@ -159,6 +164,18 @@ describe Parser::AST::Node do
|
|
159
164
|
expect(node.to_value).to eq :str
|
160
165
|
end
|
161
166
|
|
167
|
+
it 'get for boolean' do
|
168
|
+
node = parse("true")
|
169
|
+
expect(node.to_value).to be_truthy
|
170
|
+
node = parse("false")
|
171
|
+
expect(node.to_value).to be_falsey
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'get for range' do
|
175
|
+
node = parse("(1..10)")
|
176
|
+
expect(node.to_value).to eq (1..10)
|
177
|
+
end
|
178
|
+
|
162
179
|
it 'gets for array' do
|
163
180
|
node = parse("['str', :str]")
|
164
181
|
expect(node.to_value).to eq ['str', :str]
|
data/synvert-core.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "parser"
|
22
22
|
spec.add_runtime_dependency "activesupport"
|
23
|
+
spec.add_runtime_dependency "erubis"
|
23
24
|
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
26
|
spec.add_development_dependency "rake"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synvert-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: erubis
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,6 +111,8 @@ files:
|
|
97
111
|
- Rakefile
|
98
112
|
- lib/synvert/core.rb
|
99
113
|
- lib/synvert/core/configuration.rb
|
114
|
+
- lib/synvert/core/engine.rb
|
115
|
+
- lib/synvert/core/engine/erb.rb
|
100
116
|
- lib/synvert/core/exceptions.rb
|
101
117
|
- lib/synvert/core/node_ext.rb
|
102
118
|
- lib/synvert/core/rewriter.rb
|
@@ -110,6 +126,7 @@ files:
|
|
110
126
|
- spec/spec_helper.rb
|
111
127
|
- spec/support/parser_helper.rb
|
112
128
|
- spec/synvert/core/configuration_spec.rb
|
129
|
+
- spec/synvert/core/engine/erb_spec.rb
|
113
130
|
- spec/synvert/core/node_ext_spec.rb
|
114
131
|
- spec/synvert/core/rewriter/action_spec.rb
|
115
132
|
- spec/synvert/core/rewriter/condition_spec.rb
|
@@ -147,6 +164,7 @@ test_files:
|
|
147
164
|
- spec/spec_helper.rb
|
148
165
|
- spec/support/parser_helper.rb
|
149
166
|
- spec/synvert/core/configuration_spec.rb
|
167
|
+
- spec/synvert/core/engine/erb_spec.rb
|
150
168
|
- spec/synvert/core/node_ext_spec.rb
|
151
169
|
- spec/synvert/core/rewriter/action_spec.rb
|
152
170
|
- spec/synvert/core/rewriter/condition_spec.rb
|