123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- ##
- ## $Release: 2.7.0 $
- ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
- ##
- require 'erubis/util'
- module Erubis
- ##
- ## convert
- ##
- module Converter
- attr_accessor :preamble, :postamble, :escape
- def self.supported_properties # :nodoc:
- return [
- [:preamble, nil, "preamble (no preamble when false)"],
- [:postamble, nil, "postamble (no postamble when false)"],
- [:escape, nil, "escape expression or not in default"],
- ]
- end
- def init_converter(properties={})
- @preamble = properties[:preamble]
- @postamble = properties[:postamble]
- @escape = properties[:escape]
- end
- ## convert input string into target language
- def convert(input)
- codebuf = "" # or []
- @preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
- convert_input(codebuf, input)
- @postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
- @_proc = nil # clear cached proc object
- return codebuf # or codebuf.join()
- end
- protected
- ##
- ## detect spaces at beginning of line
- ##
- def detect_spaces_at_bol(text, is_bol)
- lspace = nil
- if text.empty?
- lspace = "" if is_bol
- elsif text[-1] == ?\n
- lspace = ""
- else
- rindex = text.rindex(?\n)
- if rindex
- s = text[rindex+1..-1]
- if s =~ /\A[ \t]*\z/
- lspace = s
- #text = text[0..rindex]
- text[rindex+1..-1] = ''
- end
- else
- if is_bol && text =~ /\A[ \t]*\z/
- #lspace = text
- #text = nil
- lspace = text.dup
- text[0..-1] = ''
- end
- end
- end
- return lspace
- end
- ##
- ## (abstract) convert input to code
- ##
- def convert_input(codebuf, input)
- not_implemented
- end
- end
- module Basic
- end
- ##
- ## basic converter which supports '<% ... %>' notation.
- ##
- module Basic::Converter
- include Erubis::Converter
- def self.supported_properties # :nodoc:
- return [
- [:pattern, '<% %>', "embed pattern"],
- [:trim, true, "trim spaces around <% ... %>"],
- ]
- end
- attr_accessor :pattern, :trim
- def init_converter(properties={})
- super(properties)
- @pattern = properties[:pattern]
- @trim = properties[:trim] != false
- end
- protected
- ## return regexp of pattern to parse eRuby script
- def pattern_regexp(pattern)
- @prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
- #return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
- #return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
- return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
- end
- module_function :pattern_regexp
- #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
- #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
- #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
- DEFAULT_REGEXP = pattern_regexp('<% %>')
- public
- def convert_input(src, input)
- pat = @pattern
- regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
- pos = 0
- is_bol = true # is beginning of line
- input.scan(regexp) do |indicator, code, tailch, rspace|
- match = Regexp.last_match()
- len = match.begin(0) - pos
- text = input[pos, len]
- pos = match.end(0)
- ch = indicator ? indicator[0] : nil
- lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
- is_bol = rspace ? true : false
- add_text(src, text) if text && !text.empty?
- ## * when '<%= %>', do nothing
- ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
- if ch == ?= # <%= %>
- rspace = nil if tailch && !tailch.empty?
- add_text(src, lspace) if lspace
- add_expr(src, code, indicator)
- add_text(src, rspace) if rspace
- elsif ch == ?\# # <%# %>
- n = code.count("\n") + (rspace ? 1 : 0)
- if @trim && lspace && rspace
- add_stmt(src, "\n" * n)
- else
- add_text(src, lspace) if lspace
- add_stmt(src, "\n" * n)
- add_text(src, rspace) if rspace
- end
- elsif ch == ?% # <%% %>
- s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
- add_text(src, s)
- else # <% %>
- if @trim && lspace && rspace
- add_stmt(src, "#{lspace}#{code}#{rspace}")
- else
- add_text(src, lspace) if lspace
- add_stmt(src, code)
- add_text(src, rspace) if rspace
- end
- end
- end
- #rest = $' || input # ruby1.8
- rest = pos == 0 ? input : input[pos..-1] # ruby1.9
- add_text(src, rest)
- end
- ## add expression code to src
- def add_expr(src, code, indicator)
- case indicator
- when '='
- @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
- when '=='
- @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
- when '==='
- add_expr_debug(src, code)
- end
- end
- end
- module PI
- end
- ##
- ## Processing Instructions (PI) converter for XML.
- ## this class converts '<?rb ... ?>' and '${...}' notation.
- ##
- module PI::Converter
- include Erubis::Converter
- def self.desc # :nodoc:
- "use processing instructions (PI) instead of '<% %>'"
- end
- def self.supported_properties # :nodoc:
- return [
- [:trim, true, "trim spaces around <% ... %>"],
- [:pi, 'rb', "PI (Processing Instrunctions) name"],
- [:embchar, '@', "char for embedded expression pattern('@{...}@')"],
- [:pattern, '<% %>', "embed pattern"],
- ]
- end
- attr_accessor :pi, :prefix
- def init_converter(properties={})
- super(properties)
- @trim = properties.fetch(:trim, true)
- @pi = properties[:pi] if properties[:pi]
- @embchar = properties[:embchar] || '@'
- @pattern = properties[:pattern]
- @pattern = '<% %>' if @pattern.nil? #|| @pattern == true
- end
- def convert(input)
- code = super(input)
- return @header || @footer ? "#{@header}#{code}#{@footer}" : code
- end
- protected
- def convert_input(codebuf, input)
- unless @regexp
- @pi ||= 'e'
- ch = Regexp.escape(@embchar)
- if @pattern
- left, right = @pattern.split(' ')
- @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
- else
- @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
- end
- end
- #
- is_bol = true
- pos = 0
- input.scan(@regexp) do |pi_arg, stmt, rspace,
- indicator1, expr1, indicator2, expr2|
- match = Regexp.last_match
- len = match.begin(0) - pos
- text = input[pos, len]
- pos = match.end(0)
- lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
- is_bol = stmt && rspace ? true : false
- add_text(codebuf, text) # unless text.empty?
- #
- if stmt
- if @trim && lspace && rspace
- add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
- else
- add_text(codebuf, lspace) if lspace
- add_pi_stmt(codebuf, stmt, pi_arg)
- add_text(codebuf, rspace) if rspace
- end
- else
- add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
- end
- end
- #rest = $' || input # ruby1.8
- rest = pos == 0 ? input : input[pos..-1] # ruby1.9
- add_text(codebuf, rest)
- end
- #--
- #def convert_input(codebuf, input)
- # parse_stmts(codebuf, input)
- # #parse_stmts2(codebuf, input)
- #end
- #
- #def parse_stmts(codebuf, input)
- # #regexp = pattern_regexp(@pattern)
- # @pi ||= 'e'
- # @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
- # is_bol = true
- # pos = 0
- # input.scan(@stmt_pattern) do |pi_arg, code, rspace|
- # match = Regexp.last_match
- # len = match.begin(0) - pos
- # text = input[pos, len]
- # pos = match.end(0)
- # lspace = detect_spaces_at_bol(text, is_bol)
- # is_bol = rspace ? true : false
- # parse_exprs(codebuf, text) # unless text.empty?
- # if @trim && lspace && rspace
- # add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
- # else
- # add_text(codebuf, lspace)
- # add_pi_stmt(codebuf, code, pi_arg)
- # add_text(codebuf, rspace)
- # end
- # end
- # rest = $' || input
- # parse_exprs(codebuf, rest)
- #end
- #
- #def parse_exprs(codebuf, input)
- # unless @expr_pattern
- # ch = Regexp.escape(@embchar)
- # if @pattern
- # left, right = @pattern.split(' ')
- # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
- # else
- # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
- # end
- # end
- # pos = 0
- # input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
- # indicator = indicator1 || indicator2
- # code = code1 || code2
- # match = Regexp.last_match
- # len = match.begin(0) - pos
- # text = input[pos, len]
- # pos = match.end(0)
- # add_text(codebuf, text) # unless text.empty?
- # add_pi_expr(codebuf, code, indicator)
- # end
- # rest = $' || input
- # add_text(codebuf, rest)
- #end
- #++
- def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
- case pi_arg
- when nil ; add_stmt(codebuf, code)
- when 'header' ; @header = code
- when 'footer' ; @footer = code
- when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
- when 'value' ; add_expr_literal(codebuf, code)
- else ; add_stmt(codebuf, code)
- end
- end
- def add_pi_expr(codebuf, code, indicator) # :nodoc:
- case indicator
- when nil, '', '==' # @{...}@ or <%== ... %>
- @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
- when '!', '=' # @!{...}@ or <%= ... %>
- @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
- when '!!', '===' # @!!{...}@ or <%=== ... %>
- add_expr_debug(codebuf, code)
- else
- # ignore
- end
- end
- end
- end
|