Skip to content

Commit

Permalink
Merge eef2f68 into 749e1b7
Browse files Browse the repository at this point in the history
  • Loading branch information
flyerhzm committed Oct 11, 2019
2 parents 749e1b7 + eef2f68 commit 7c1424a
Show file tree
Hide file tree
Showing 52 changed files with 639 additions and 479 deletions.
6 changes: 4 additions & 2 deletions lib/synvert/core.rb
@@ -1,7 +1,9 @@
require "synvert/core/version"
# frozen_string_literal: true

require 'synvert/core/version'

# coding: utf-8
require "synvert/core/version"
require 'synvert/core/version'
require 'bundler'
require 'parser'
require 'parser/current'
Expand Down
2 changes: 2 additions & 0 deletions lib/synvert/core/configuration.rb
@@ -1,4 +1,6 @@
# encoding: utf-8
# frozen_string_literal: true

require 'singleton'

module Synvert::Core
Expand Down
1 change: 1 addition & 0 deletions lib/synvert/core/engine.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
# frozen_string_literal: true

module Synvert::Core
# Engine defines how to encode / decode other files (like erb).
Expand Down
53 changes: 31 additions & 22 deletions lib/synvert/core/engine/erb.rb
@@ -1,19 +1,21 @@
# encoding: utf-8
# frozen_string_literal: true

require 'erubis'

module Synvert::Core
module Engine
ERUBY_EXPR_SPLITTER = "; ;"
ERUBY_STMT_SPLITTER = "; ;"
ERUBY_EXPR_SPLITTER = '; ;'
ERUBY_STMT_SPLITTER = '; ;'

class ERB
class <<self
class << self
# convert erb to ruby code.
#
# @param source [String] erb source code.
# @return [String] ruby source code.
def encode(source)
Erubis.new(source.gsub("-%>", "%>"), :escape => false, :trim => false).src
Erubis.new(source.gsub('-%>', '%>'), escape: false, trim: false).src
end

# convert ruby code to erb.
Expand All @@ -27,25 +29,31 @@ def decode(source)
source = remove_erubis_buf(source)
end

private
private

def decode_ruby_stmt(source)
source.gsub(/#{ERUBY_STMT_SPLITTER}(.+?)#{ERUBY_STMT_SPLITTER}/m) { "<%#{$1}%>" }
end

def decode_ruby_output(source)
source.gsub(/@output_buffer.append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m) { "<%=#{$1}%>" }
.gsub(/@output_buffer.append= (.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m) { |m| "<%=#{m.sub("@output_buffer.append= ", "").sub(ERUBY_EXPR_SPLITTER, "")}%>" }
source.gsub(/@output_buffer.append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m) { "<%=#{$1}%>" }.gsub(
/@output_buffer.append= (.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m
) { |m| "<%=#{m.sub('@output_buffer.append= ', '').sub(ERUBY_EXPR_SPLITTER, '')}%>" }
end

def decode_html_output(source)
source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text($1) }
.gsub(/@output_buffer.safe_append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m) { reverse_escape_text($1) }
.gsub(/@output_buffer.safe_append=(.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m) { reverse_escape_text($1) }
source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text($1) }.gsub(
/@output_buffer.safe_append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/m
) { reverse_escape_text($1) }.gsub(
/@output_buffer.safe_append=(.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/m
) { reverse_escape_text($1) }
end

def remove_erubis_buf(source)
source.sub("@output_buffer = output_buffer || ActionView::OutputBuffer.new;", "").sub("@output_buffer.to_s", "")
source.sub('@output_buffer = output_buffer || ActionView::OutputBuffer.new;', '').sub(
'@output_buffer.to_s',
''
)
end

def reverse_escape_text(source)
Expand All @@ -58,7 +66,7 @@ def reverse_escape_text(source)
class Erubis < ::Erubis::Eruby
def add_preamble(src)
@newline_pending = 0
src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
src << '@output_buffer = output_buffer || ActionView::OutputBuffer.new;'
end

def add_text(src, text)
Expand Down Expand Up @@ -101,22 +109,23 @@ def add_expr_literal(src, code)
def add_expr_escaped(src, code)
flush_newline_if_pending(src)
if code =~ BLOCK_EXPR
src << "@output_buffer.safe_append= " << code << ERUBY_EXPR_SPLITTER
src << '@output_buffer.safe_append= ' << code << ERUBY_EXPR_SPLITTER
else
src << "@output_buffer.safe_append=(" << code << ");" << ERUBY_EXPR_SPLITTER
src << '@output_buffer.safe_append=(' << code << ');' << ERUBY_EXPR_SPLITTER
end
end

def add_stmt(src, code)
flush_newline_if_pending(src)
if code != "\n" && code != ""
index = if code =~ /\A(\s*)\r?\n/
$1.length
elsif code =~ /\A(\s+)/
$1.end_with?(' ') ? $1.length - 1 : $1.length
else
0
end
if code != "\n" && code != ''
index =
if code =~ /\A(\s*)\r?\n/
$1.length
elsif code =~ /\A(\s+)/
$1.end_with?(' ') ? $1.length - 1 : $1.length
else
0
end
code.insert(index, ERUBY_STMT_SPLITTER)
code.insert(-1, ERUBY_STMT_SPLITTER[0...-1])
end
Expand Down
11 changes: 5 additions & 6 deletions lib/synvert/core/exceptions.rb
@@ -1,13 +1,12 @@
# frozen_string_literal: true

module Synvert::Core
# Rewriter not found exception.
class RewriterNotFound < Exception
end
class RewriterNotFound < Exception; end

# Gemfile.lock not found exception.
class GemfileLockNotFound < Exception
end
class GemfileLockNotFound < Exception; end

# Method not supported exception.
class MethodNotSupported < Exception
end
class MethodNotSupported < Exception; end
end
60 changes: 25 additions & 35 deletions lib/synvert/core/node_ext.rb
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Parser::AST
# ArgumentsNode allows to handle all args as one node or handle all args as an array.
class ArgumentsNode
Expand All @@ -23,11 +25,13 @@ def method_missing(meth, *args, &block)
end

# Parser::AST::Node monkey patch.

class Node
# Get name node of :class, :module, :const, :mlhs, :def and :defs node.
#
# @return [Parser::AST::Node] name node.
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.

def name
case self.type
when :class, :module, :def, :arg, :blockarg, :restarg
Expand Down Expand Up @@ -96,6 +100,7 @@ def message
#
# @return [Array<Parser::AST::Node>] arguments node.
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.

def arguments
case self.type
when :def, :block
Expand Down Expand Up @@ -127,6 +132,7 @@ def caller
#
# @return [Array<Parser::AST::Node>] body node.
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.

def body
case self.type
when :begin
Expand Down Expand Up @@ -234,7 +240,7 @@ def value
# @return [Parser::AST::Node] variable nodes.
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
def left_value
if [:masgn, :lvasgn, :ivasgn].include? self.type
if %i[masgn lvasgn ivasgn].include? self.type
self.children[0]
else
raise Synvert::Core::MethodNotSupported.new "left_value is not handled for #{self.debug_info}"
Expand All @@ -246,7 +252,7 @@ def left_value
# @return [Array<Parser::AST::Node>] variable nodes.
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
def right_value
if [:masgn, :lvasgn, :ivasgn].include? self.type
if %i[masgn lvasgn ivasgn].include? self.type
self.children[1]
else
raise Synvert::Core::MethodNotSupported.new "right_value is not handled for #{self.debug_info}"
Expand Down Expand Up @@ -277,27 +283,24 @@ def to_value
end

def to_s
if :mlhs == self.type
"(#{self.children.map(&:name).join(', ')})"
end
"(#{self.children.map(&:name).join(', ')})" if :mlhs == self.type
end

def debug_info
"\n" + [
"file: #{self.loc.expression.source_buffer.name}",
"line: #{self.loc.expression.line}",
"source: #{self.to_source}",
"node: #{self.inspect}"
].join("\n")
"\n" +
[
"file: #{self.loc.expression.source_buffer.name}",
"line: #{self.loc.expression.line}",
"source: #{self.to_source}",
"node: #{self.inspect}"
].join("\n")
end

# Get the source code of current node.
#
# @return [String] source code.
def to_source
if self.loc.expression
self.loc.expression.source
end
self.loc.expression.source if self.loc.expression
end

# Get the indent of current node.
Expand Down Expand Up @@ -372,9 +375,9 @@ def rewritten_source(code)
lines_count = lines.length
if lines_count > 1 && lines_count == evaluated.size
new_code = []
lines.each_with_index { |line, index|
new_code << (index == 0 ? line : line[evaluated.first.indent-2..-1])
}
lines.each_with_index do |line, index|
new_code << (index == 0 ? line : line[evaluated.first.indent - 2..-1])
end
new_code.join("\n")
else
source
Expand All @@ -393,7 +396,7 @@ def rewritten_source(code)
end
end

private
private

# Compare actual value with expected value.
#
Expand All @@ -404,15 +407,10 @@ def rewritten_source(code)
def match_value?(actual, expected)
case expected
when Symbol
if Parser::AST::Node === actual
actual.to_source == ":#{expected}"
else
actual.to_sym == expected
end
Parser::AST::Node === actual ? actual.to_source == ":#{expected}" : actual.to_sym == expected
when String
if Parser::AST::Node === actual
actual.to_source == expected ||
(actual.to_source[0] == ':' && actual.to_source[1..-1] == expected) ||
actual.to_source == expected || (actual.to_source[0] == ':' && actual.to_source[1..-1] == expected) ||
actual.to_source[1...-1] == expected
else
actual.to_s == expected
Expand All @@ -429,11 +427,7 @@ def match_value?(actual, expected)
when NilClass
actual.nil?
when Numeric
if Parser::AST::Node === actual
actual.children[0] == expected
else
actual == expected
end
Parser::AST::Node === actual ? actual.children[0] == expected : actual == expected
when TrueClass
:true == actual.type
when FalseClass
Expand Down Expand Up @@ -470,11 +464,7 @@ def flat_hash(h, k = [])
# @param multi_keys [Array<Symbol>]
# @return [Object] actual value.
def actual_value(node, multi_keys)
multi_keys.inject(node) { |n, key|
if n
key == :source ? n.send(key) : n.send(key)
end
}
multi_keys.inject(node) { |n, key| key == :source ? n.send(key) : n.send(key) if n }
end

# Get expected value from rules.
Expand Down
22 changes: 9 additions & 13 deletions lib/synvert/core/rewriter.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
# frozen_string_literal: true

module Synvert::Core
# Rewriter is the top level namespace in a snippet.
Expand Down Expand Up @@ -42,7 +43,7 @@ class Rewriter
autoload :RubyVersion, 'synvert/core/rewriter/ruby_version'
autoload :GemSpec, 'synvert/core/rewriter/gem_spec'

class <<self
class << self
# Register a rewriter with its group and name.
#
# @param group [String] the rewriter group.
Expand Down Expand Up @@ -93,11 +94,7 @@ def call(group, name)
# @return [Boolean] true if the rewriter exist.
def exist?(group, name)
group, name = group.to_s, name.to_s
if rewriters[group] && rewriters[group][name]
true
else
false
end
rewriters[group] && rewriters[group][name] ? true : false
end

# Get all available rewriters
Expand All @@ -112,7 +109,7 @@ def clear
rewriters.clear
end

private
private

def rewriters
@rewriters ||= {}
Expand Down Expand Up @@ -178,7 +175,7 @@ def add_warning(warning)
#
# @param description [String] rewriter description.
# @return rewriter description.
def description(description=nil)
def description(description = nil)
if description
@description = description
else
Expand Down Expand Up @@ -208,11 +205,10 @@ def if_gem(name, comparator)
# @param file_pattern [String] pattern to find files, e.g. spec/**/*_spec.rb
# @param options [Hash] instance options.
# @param block [Block] the block to rewrite code in the matching files.
def within_files(file_pattern, options={}, &block)
def within_files(file_pattern, options = {}, &block)
return if @sandbox

if (!@ruby_version || @ruby_version.match?) &&
(!@gem_spec || @gem_spec.match?)
if (!@ruby_version || @ruby_version.match?) && (!@gem_spec || @gem_spec.match?)
Rewriter::Instance.new(self, file_pattern, options, &block).process
end
end
Expand Down Expand Up @@ -262,15 +258,15 @@ def add_snippet(group, name)
# @param name [String] helper method name.
# @param block [Block] helper method block.
def helper_method(name, &block)
@helpers << {name: name, block: block}
@helpers << { name: name, block: block }
end

# Parse todo dsl, it sets todo of the rewriter.
# Or get todo.
#
# @param todo_list [String] rewriter todo.
# @return [String] rewriter todo.
def todo(todo=nil)
def todo(todo = nil)
if todo
@todo = todo
else
Expand Down

0 comments on commit 7c1424a

Please sign in to comment.