PageRenderTime 91ms CodeModel.GetById 69ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/bundle/ruby/1.8/gems/erubis-2.6.6/contrib/erubis

https://bitbucket.org/jstanco/tweetsearch
Ruby | 3330 lines | 1932 code | 614 blank | 784 comment | 276 complexity | 02f7cd7e95faaa90def31c2c42c06c8a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1#!/usr/bin/env ruby
   2
   3###
   4### $Release: 2.6.6 $
   5### copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
   6###
   7
   8#--begin of require 'erubis/main'
   9###
  10### $Release: 2.6.6 $
  11### copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  12###
  13
  14require 'yaml'
  15#--begin of require 'erubis'
  16##
  17## $Release: 2.6.6 $
  18## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  19##
  20
  21##
  22## an implementation of eRuby
  23##
  24## ex.
  25##   input = <<'END'
  26##    <ul>
  27##     <% for item in @list %>
  28##      <li><%= item %>
  29##          <%== item %></li>
  30##     <% end %>
  31##    </ul>
  32##   END
  33##   list = ['<aaa>', 'b&b', '"ccc"']
  34##   eruby = Erubis::Eruby.new(input)
  35##   puts "--- code ---"
  36##   puts eruby.src
  37##   puts "--- result ---"
  38##   context = Erubis::Context.new()   # or new(:list=>list)
  39##   context[:list] = list
  40##   puts eruby.evaluate(context)
  41##
  42## result:
  43##   --- source ---
  44##   _buf = ''; _buf << '<ul>
  45##   ';  for item in @list 
  46##    _buf << '  <li>'; _buf << ( item ).to_s; _buf << '
  47##   '; _buf << '      '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
  48##   ';  end 
  49##    _buf << '</ul>
  50##   ';
  51##   _buf.to_s
  52##   --- result ---
  53##    <ul>
  54##      <li><aaa>
  55##          &lt;aaa&gt;</li>
  56##      <li>b&b
  57##          b&amp;b</li>
  58##      <li>"ccc"
  59##          &quot;ccc&quot;</li>
  60##    </ul>
  61##
  62
  63
  64module Erubis
  65  VERSION = ('$Release: 2.6.6 $' =~ /([.\d]+)/) && $1
  66end
  67
  68#--begin of require 'erubis/engine'
  69##
  70## $Release: 2.6.6 $
  71## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  72##
  73
  74
  75#--begin of require 'erubis/generator'
  76##
  77## $Release: 2.6.6 $
  78## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  79##
  80
  81#--begin of require 'abstract'
  82##
  83## $Rev: 1 $
  84## $Release: 0.1.0 $
  85## copyright(c) 2006 kuwata-lab.com all rights reserved.
  86##
  87##
  88## helper to define abstract method in Ruby.
  89##
  90##
  91## example1. (shorter notation)
  92##
  93##   require 'abstract'
  94##   class Foo
  95##     abstract_method 'arg1, arg2=""', :method1, :method2, :method3
  96##   end
  97##
  98##
  99## example2. (RDoc friendly notation)
 100##
 101##   require 'abstract'
 102##   class Bar
 103##     # ... method1 description ...
 104##     def method1(arg1, arg2="")
 105##       not_implemented
 106##     end
 107##
 108##     # ... method2 description ...
 109##     def method2(arg1, arg2="")
 110##       not_implemented
 111##     end
 112##   end
 113##
 114
 115
 116##
 117class Module
 118
 119  ##
 120  ## define abstract methods
 121  ##
 122  def abstract_method args_str, *method_names
 123    method_names.each do |name|
 124      module_eval <<-END
 125        def #{name}(#{args_str})
 126          mesg = "class \#{self.class.name} must implement abstract method `#{self.name}##{name}()'."
 127          #mesg = "\#{self.class.name}##{name}() is not implemented."
 128          err = NotImplementedError.new mesg
 129          err.set_backtrace caller()
 130          raise err
 131        end
 132      END
 133    end
 134  end
 135
 136end
 137
 138
 139##
 140module Kernel
 141
 142  ##
 143  ## raise NotImplementedError
 144  ##
 145  def not_implemented     #:doc:
 146    backtrace = caller()
 147    method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
 148    mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
 149    #mesg = "#{self.class.name}##{method_name}() is not implemented."
 150    err = NotImplementedError.new mesg
 151    err.set_backtrace backtrace
 152    raise err
 153  end
 154  private :not_implemented
 155
 156end
 157#--end of require 'abstract'
 158
 159module Erubis
 160
 161
 162  ##
 163  ## code generator, called by Converter module
 164  ##
 165  module Generator
 166
 167    def self.supported_properties()  # :nodoc:
 168      return [
 169              [:escapefunc,    nil,    "escape function name"],
 170            ]
 171    end
 172
 173    attr_accessor :escapefunc
 174
 175    def init_generator(properties={})
 176      @escapefunc = properties[:escapefunc]
 177    end
 178
 179
 180    ## (abstract) escape text string
 181    ##
 182    ## ex.
 183    ##   def escape_text(text)
 184    ##     return text.dump
 185    ##     # or return "'" + text.gsub(/['\\]/, '\\\\\&') + "'"
 186    ##   end
 187    def escape_text(text)
 188      not_implemented
 189    end
 190
 191    ## return escaped expression code (ex. 'h(...)' or 'htmlspecialchars(...)')
 192    def escaped_expr(code)
 193      code.strip!
 194      return "#{@escapefunc}(#{code})"
 195    end
 196
 197    ## (abstract) add @preamble to src
 198    def add_preamble(src)
 199      not_implemented
 200    end
 201
 202    ## (abstract) add text string to src
 203    def add_text(src, text)
 204      not_implemented
 205    end
 206
 207    ## (abstract) add statement code to src
 208    def add_stmt(src, code)
 209      not_implemented
 210    end
 211
 212    ## (abstract) add expression literal code to src. this is called by add_expr().
 213    def add_expr_literal(src, code)
 214      not_implemented
 215    end
 216
 217    ## (abstract) add escaped expression code to src. this is called by add_expr().
 218    def add_expr_escaped(src, code)
 219      not_implemented
 220    end
 221
 222    ## (abstract) add expression code to src for debug. this is called by add_expr().
 223    def add_expr_debug(src, code)
 224      not_implemented
 225    end
 226
 227    ## (abstract) add @postamble to src
 228    def add_postamble(src)
 229      not_implemented
 230    end
 231
 232
 233  end
 234
 235
 236end
 237#--end of require 'erubis/generator'
 238#--begin of require 'erubis/converter'
 239##
 240## $Release: 2.6.6 $
 241## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 242##
 243
 244#--already included require 'abstract'
 245
 246module Erubis
 247
 248
 249  ##
 250  ## convert
 251  ##
 252  module Converter
 253
 254    attr_accessor :preamble, :postamble, :escape
 255
 256    def self.supported_properties    # :nodoc:
 257      return [
 258              [:preamble,  nil,    "preamble (no preamble when false)"],
 259              [:postamble, nil,    "postamble (no postamble when false)"],
 260              [:escape,    nil,    "escape expression or not in default"],
 261             ]
 262    end
 263
 264    def init_converter(properties={})
 265      @preamble  = properties[:preamble]
 266      @postamble = properties[:postamble]
 267      @escape    = properties[:escape]
 268    end
 269
 270    ## convert input string into target language
 271    def convert(input)
 272      codebuf = ""    # or []
 273      @preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
 274      convert_input(codebuf, input)
 275      @postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
 276      @_proc = nil    # clear cached proc object
 277      return codebuf  # or codebuf.join()
 278    end
 279
 280    protected
 281
 282    ##
 283    ## detect spaces at beginning of line
 284    ##
 285    def detect_spaces_at_bol(text, is_bol)
 286      lspace = nil
 287      if text.empty?
 288        lspace = "" if is_bol
 289      elsif text[-1] == ?\n
 290        lspace = ""
 291      else
 292        rindex = text.rindex(?\n)
 293        if rindex
 294          s = text[rindex+1..-1]
 295          if s =~ /\A[ \t]*\z/
 296            lspace = s
 297            #text = text[0..rindex]
 298            text[rindex+1..-1] = ''
 299          end
 300        else
 301          if is_bol && text =~ /\A[ \t]*\z/
 302            #lspace = text
 303            #text = nil
 304            lspace = text.dup
 305            text[0..-1] = ''
 306          end
 307        end
 308      end
 309      return lspace
 310    end
 311
 312    ##
 313    ## (abstract) convert input to code
 314    ##
 315    def convert_input(codebuf, input)
 316      not_implemented
 317    end
 318
 319  end
 320
 321
 322  module Basic
 323  end
 324
 325
 326  ##
 327  ## basic converter which supports '<% ... %>' notation.
 328  ##
 329  module Basic::Converter
 330    include Erubis::Converter
 331
 332    def self.supported_properties    # :nodoc:
 333      return [
 334              [:pattern,  '<% %>', "embed pattern"],
 335              [:trim,      true,   "trim spaces around <% ... %>"],
 336             ]
 337    end
 338
 339    attr_accessor :pattern, :trim
 340
 341    def init_converter(properties={})
 342      super(properties)
 343      @pattern = properties[:pattern]
 344      @trim    = properties[:trim] != false
 345    end
 346
 347    protected
 348
 349    ## return regexp of pattern to parse eRuby script
 350    def pattern_regexp(pattern)
 351      @prefix, @postfix = pattern.split()   # '<% %>' => '<%', '%>'
 352      #return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
 353      #return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
 354      return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
 355    end
 356    module_function :pattern_regexp
 357
 358    #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
 359    #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
 360    #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
 361    DEFAULT_REGEXP = pattern_regexp('<% %>')
 362
 363    public
 364
 365    def convert_input(src, input)
 366      pat = @pattern
 367      regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
 368      pos = 0
 369      is_bol = true     # is beginning of line
 370      input.scan(regexp) do |indicator, code, tailch, rspace|
 371        match = Regexp.last_match()
 372        len  = match.begin(0) - pos
 373        text = input[pos, len]
 374        pos  = match.end(0)
 375        ch   = indicator ? indicator[0] : nil
 376        lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
 377        is_bol = rspace ? true : false
 378        add_text(src, text) if text && !text.empty?
 379        ## * when '<%= %>', do nothing
 380        ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
 381        if ch == ?=              # <%= %>
 382          rspace = nil if tailch && !tailch.empty?
 383          add_text(src, lspace) if lspace
 384          add_expr(src, code, indicator)
 385          add_text(src, rspace) if rspace
 386        elsif ch == ?\#          # <%# %>
 387          n = code.count("\n") + (rspace ? 1 : 0)
 388          if @trim && lspace && rspace
 389            add_stmt(src, "\n" * n)
 390          else
 391            add_text(src, lspace) if lspace
 392            add_stmt(src, "\n" * n)
 393            add_text(src, rspace) if rspace
 394          end
 395        elsif ch == ?%           # <%% %>
 396          s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
 397          add_text(src, s)
 398        else                     # <% %>
 399          if @trim && lspace && rspace
 400            add_stmt(src, "#{lspace}#{code}#{rspace}")
 401          else
 402            add_text(src, lspace) if lspace
 403            add_stmt(src, code)
 404            add_text(src, rspace) if rspace
 405          end
 406        end
 407      end
 408      #rest = $' || input                        # ruby1.8
 409      rest = pos == 0 ? input : input[pos..-1]   # ruby1.9
 410      add_text(src, rest)
 411    end
 412
 413    ## add expression code to src
 414    def add_expr(src, code, indicator)
 415      case indicator
 416      when '='
 417        @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
 418      when '=='
 419        @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
 420      when '==='
 421        add_expr_debug(src, code)
 422      end
 423    end
 424
 425  end
 426
 427
 428  module PI
 429  end
 430
 431  ##
 432  ## Processing Instructions (PI) converter for XML.
 433  ## this class converts '<?rb ... ?>' and '${...}' notation.
 434  ##
 435  module PI::Converter
 436    include Erubis::Converter
 437
 438    def self.desc   # :nodoc:
 439      "use processing instructions (PI) instead of '<% %>'"
 440    end
 441
 442    def self.supported_properties    # :nodoc:
 443      return [
 444              [:trim,      true,   "trim spaces around <% ... %>"],
 445              [:pi,        'rb',   "PI (Processing Instrunctions) name"],
 446              [:embchar,   '@',    "char for embedded expression pattern('@{...}@')"],
 447              [:pattern,  '<% %>', "embed pattern"],
 448             ]
 449    end
 450
 451    attr_accessor :pi, :prefix
 452
 453    def init_converter(properties={})
 454      super(properties)
 455      @trim    = properties.fetch(:trim, true)
 456      @pi      = properties[:pi] if properties[:pi]
 457      @embchar = properties[:embchar] || '@'
 458      @pattern = properties[:pattern]
 459      @pattern = '<% %>' if @pattern.nil?  #|| @pattern == true
 460    end
 461
 462    def convert(input)
 463      code = super(input)
 464      return @header || @footer ? "#{@header}#{code}#{@footer}" : code
 465    end
 466
 467    protected
 468
 469    def convert_input(codebuf, input)
 470      unless @regexp
 471        @pi ||= 'e'
 472        ch = Regexp.escape(@embchar)
 473        if @pattern
 474          left, right = @pattern.split(' ')
 475          @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
 476        else
 477          @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
 478        end
 479      end
 480      #
 481      is_bol = true
 482      pos = 0
 483      input.scan(@regexp) do |pi_arg, stmt, rspace,
 484                              indicator1, expr1, indicator2, expr2|
 485        match = Regexp.last_match
 486        len = match.begin(0) - pos
 487        text = input[pos, len]
 488        pos = match.end(0)
 489        lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
 490        is_bol = stmt && rspace ? true : false
 491        add_text(codebuf, text) # unless text.empty?
 492        #
 493        if stmt
 494          if @trim && lspace && rspace
 495            add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
 496          else
 497            add_text(codebuf, lspace) if lspace
 498            add_pi_stmt(codebuf, stmt, pi_arg)
 499            add_text(codebuf, rspace) if rspace
 500          end
 501        else
 502          add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
 503        end
 504      end
 505      #rest = $' || input                        # ruby1.8
 506      rest = pos == 0 ? input : input[pos..-1]   # ruby1.9
 507      add_text(codebuf, rest)
 508    end
 509
 510    #--
 511    #def convert_input(codebuf, input)
 512    #  parse_stmts(codebuf, input)
 513    #  #parse_stmts2(codebuf, input)
 514    #end
 515    #
 516    #def parse_stmts(codebuf, input)
 517    #  #regexp = pattern_regexp(@pattern)
 518    #  @pi ||= 'e'
 519    #  @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
 520    #  is_bol = true
 521    #  pos = 0
 522    #  input.scan(@stmt_pattern) do |pi_arg, code, rspace|
 523    #    match = Regexp.last_match
 524    #    len  = match.begin(0) - pos
 525    #    text = input[pos, len]
 526    #    pos  = match.end(0)
 527    #    lspace = detect_spaces_at_bol(text, is_bol)
 528    #    is_bol = rspace ? true : false
 529    #    parse_exprs(codebuf, text) # unless text.empty?
 530    #    if @trim && lspace && rspace
 531    #      add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
 532    #    else
 533    #      add_text(codebuf, lspace)
 534    #      add_pi_stmt(codebuf, code, pi_arg)
 535    #      add_text(codebuf, rspace)
 536    #    end
 537    #  end
 538    #  rest = $' || input
 539    #  parse_exprs(codebuf, rest)
 540    #end
 541    #
 542    #def parse_exprs(codebuf, input)
 543    #  unless @expr_pattern
 544    #    ch = Regexp.escape(@embchar)
 545    #    if @pattern
 546    #      left, right = @pattern.split(' ')
 547    #      @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
 548    #    else
 549    #      @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
 550    #    end
 551    #  end
 552    #  pos = 0
 553    #  input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
 554    #    indicator = indicator1 || indicator2
 555    #    code = code1 || code2
 556    #    match = Regexp.last_match
 557    #    len  = match.begin(0) - pos
 558    #    text = input[pos, len]
 559    #    pos  = match.end(0)
 560    #    add_text(codebuf, text) # unless text.empty?
 561    #    add_pi_expr(codebuf, code, indicator)
 562    #  end
 563    #  rest = $' || input
 564    #  add_text(codebuf, rest)
 565    #end
 566    #++
 567
 568    def add_pi_stmt(codebuf, code, pi_arg)  # :nodoc:
 569      case pi_arg
 570      when nil      ;  add_stmt(codebuf, code)
 571      when 'header' ;  @header = code
 572      when 'footer' ;  @footer = code
 573      when 'comment';  add_stmt(codebuf, "\n" * code.count("\n"))
 574      when 'value'  ;  add_expr_literal(codebuf, code)
 575      else          ;  add_stmt(codebuf, code)
 576      end
 577    end
 578
 579    def add_pi_expr(codebuf, code, indicator)  # :nodoc:
 580      case indicator
 581      when nil, '', '=='    # @{...}@ or <%== ... %>
 582        @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
 583      when '!', '='         # @!{...}@ or <%= ... %>
 584        @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
 585      when '!!', '==='      # @!!{...}@ or <%=== ... %>
 586        add_expr_debug(codebuf, code)
 587      else
 588        # ignore
 589      end
 590    end
 591
 592  end
 593
 594
 595end
 596#--end of require 'erubis/converter'
 597#--begin of require 'erubis/evaluator'
 598##
 599## $Release: 2.6.6 $
 600## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 601##
 602
 603#--begin of require 'erubis/error'
 604##
 605## $Release: 2.6.6 $
 606## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 607##
 608
 609module Erubis
 610
 611
 612  ##
 613  ## base error class
 614  ##
 615  class ErubisError < StandardError
 616  end
 617
 618
 619  ##
 620  ## raised when method or function is not supported
 621  ##
 622  class NotSupportedError < ErubisError
 623  end
 624
 625
 626end
 627#--end of require 'erubis/error'
 628#--begin of require 'erubis/context'
 629##
 630## $Release: 2.6.6 $
 631## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 632##
 633
 634
 635module Erubis
 636
 637
 638  ##
 639  ## context object for Engine#evaluate
 640  ##
 641  ## ex.
 642  ##   template = <<'END'
 643  ##   Hello <%= @user %>!
 644  ##   <% for item in @list %>
 645  ##    - <%= item %>
 646  ##   <% end %>
 647  ##   END
 648  ##
 649  ##   context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
 650  ##   # or
 651  ##   # context = Erubis::Context.new
 652  ##   # context[:user] = 'World'
 653  ##   # context[:list] = ['a', 'b', 'c']
 654  ##
 655  ##   eruby = Erubis::Eruby.new(template)
 656  ##   print eruby.evaluate(context)
 657  ##
 658  class Context
 659    include Enumerable
 660
 661    def initialize(hash=nil)
 662      hash.each do |name, value|
 663        self[name] = value
 664      end if hash
 665    end
 666
 667    def [](key)
 668      return instance_variable_get("@#{key}")
 669    end
 670
 671    def []=(key, value)
 672      return instance_variable_set("@#{key}", value)
 673    end
 674
 675    def keys
 676      return instance_variables.collect { |name| name[1..-1] }
 677    end
 678
 679    def each
 680      instance_variables.each do |name|
 681        key = name[1..-1]
 682        value = instance_variable_get(name)
 683        yield(key, value)
 684      end
 685    end
 686
 687    def to_hash
 688      hash = {}
 689      self.keys.each { |key| hash[key] = self[key] }
 690      return hash
 691    end
 692
 693    def update(context_or_hash)
 694      arg = context_or_hash
 695      if arg.is_a?(Hash)
 696        arg.each do |key, val|
 697          self[key] = val
 698        end
 699      else
 700        arg.instance_variables.each do |varname|
 701          key = varname[1..-1]
 702          val = arg.instance_variable_get(varname)
 703          self[key] = val
 704        end
 705      end
 706    end
 707
 708  end
 709
 710
 711end
 712#--end of require 'erubis/context'
 713
 714
 715module Erubis
 716
 717  EMPTY_BINDING = binding()
 718
 719
 720  ##
 721  ## evaluate code
 722  ##
 723  module Evaluator
 724
 725    def self.supported_properties    # :nodoc:
 726      return []
 727    end
 728
 729    attr_accessor :src, :filename
 730
 731    def init_evaluator(properties)
 732      @filename = properties[:filename]
 733    end
 734
 735    def result(*args)
 736      raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
 737    end
 738
 739    def evaluate(*args)
 740      raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
 741    end
 742
 743  end
 744
 745
 746  ##
 747  ## evaluator for Ruby
 748  ##
 749  module RubyEvaluator
 750    include Evaluator
 751
 752    def self.supported_properties    # :nodoc:
 753      list = Evaluator.supported_properties
 754      return list
 755    end
 756
 757    ## eval(@src) with binding object
 758    def result(_binding_or_hash=TOPLEVEL_BINDING)
 759      _arg = _binding_or_hash
 760      if _arg.is_a?(Hash)
 761        _b = binding()
 762        eval _arg.collect{|k,v| "#{k} = _arg[#{k.inspect}]; "}.join, _b
 763      elsif _arg.is_a?(Binding)
 764        _b = _arg
 765      elsif _arg.nil?
 766        _b = binding()
 767      else
 768        raise ArgumentError.new("#{self.class.name}#result(): argument should be Binding or Hash but passed #{_arg.class.name} object.")
 769      end
 770      return eval(@src, _b, (@filename || '(erubis'))
 771    end
 772
 773    ## invoke context.instance_eval(@src)
 774    def evaluate(_context=Context.new)
 775      _context = Context.new(_context) if _context.is_a?(Hash)
 776      #return _context.instance_eval(@src, @filename || '(erubis)')
 777      #@_proc ||= eval("proc { #{@src} }", Erubis::EMPTY_BINDING, @filename || '(erubis)')
 778      @_proc ||= eval("proc { #{@src} }", binding(), @filename || '(erubis)')
 779      return _context.instance_eval(&@_proc)
 780    end
 781
 782    ## if object is an Class or Module then define instance method to it,
 783    ## else define singleton method to it.
 784    def def_method(object, method_name, filename=nil)
 785      m = object.is_a?(Module) ? :module_eval : :instance_eval
 786      object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
 787    end
 788
 789
 790  end
 791
 792
 793end
 794#--end of require 'erubis/evaluator'
 795#--already included require 'erubis/context'
 796
 797
 798module Erubis
 799
 800
 801  ##
 802  ## (abstract) abstract engine class.
 803  ## subclass must include evaluator and converter module.
 804  ##
 805  class Engine
 806    #include Evaluator
 807    #include Converter
 808    #include Generator
 809
 810    def initialize(input=nil, properties={})
 811      #@input = input
 812      init_generator(properties)
 813      init_converter(properties)
 814      init_evaluator(properties)
 815      @src    = convert(input) if input
 816    end
 817
 818
 819    ##
 820    ## convert input string and set it to @src
 821    ##
 822    def convert!(input)
 823      @src = convert(input)
 824    end
 825
 826
 827    ##
 828    ## load file, write cache file, and return engine object.
 829    ## this method create code cache file automatically.
 830    ## cachefile name can be specified with properties[:cachename],
 831    ## or filname + 'cache' is used as default.
 832    ##
 833    def self.load_file(filename, properties={})
 834      cachename = properties[:cachename] || (filename + '.cache')
 835      properties[:filename] = filename
 836      if test(?f, cachename) && File.mtime(filename) <= File.mtime(cachename)
 837        engine = self.new(nil, properties)
 838        engine.src = File.read(cachename)
 839      else
 840        input = File.open(filename, 'rb') {|f| f.read }
 841        engine = self.new(input, properties)
 842        File.open(cachename, 'wb') do |f|
 843          f.flock(File::LOCK_EX)
 844          f.write(engine.src)
 845          f.flush()
 846        end
 847      end
 848      engine.src.untaint   # ok?
 849      return engine
 850    end
 851
 852
 853    ##
 854    ## helper method to convert and evaluate input text with context object.
 855    ## context may be Binding, Hash, or Object.
 856    ##
 857    def process(input, context=nil, filename=nil)
 858      code = convert(input)
 859      filename ||= '(erubis)'
 860      if context.is_a?(Binding)
 861        return eval(code, context, filename)
 862      else
 863        context = Context.new(context) if context.is_a?(Hash)
 864        return context.instance_eval(code, filename)
 865      end
 866    end
 867
 868
 869    ##
 870    ## helper method evaluate Proc object with contect object.
 871    ## context may be Binding, Hash, or Object.
 872    ##
 873    def process_proc(proc_obj, context=nil, filename=nil)
 874      if context.is_a?(Binding)
 875        filename ||= '(erubis)'
 876        return eval(proc_obj, context, filename)
 877      else
 878        context = Context.new(context) if context.is_a?(Hash)
 879        return context.instance_eval(&proc_obj)
 880      end
 881    end
 882
 883
 884  end  # end of class Engine
 885
 886
 887  ##
 888  ## (abstract) base engine class for Eruby, Eperl, Ejava, and so on.
 889  ## subclass must include generator.
 890  ##
 891  class Basic::Engine < Engine
 892    include Evaluator
 893    include Basic::Converter
 894    include Generator
 895  end
 896
 897
 898  class PI::Engine < Engine
 899    include Evaluator
 900    include PI::Converter
 901    include Generator
 902  end
 903
 904
 905end
 906#--end of require 'erubis/engine'
 907#require 'erubis/generator'
 908#require 'erubis/converter'
 909#require 'erubis/evaluator'
 910#require 'erubis/error'
 911#require 'erubis/context'
 912#--begin of require 'erubis/helper'
 913##
 914## $Release: 2.6.6 $
 915## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 916##
 917
 918
 919module Erubis
 920
 921  ##
 922  ## helper for xml
 923  ##
 924  module XmlHelper
 925
 926    module_function
 927
 928    ESCAPE_TABLE = {
 929      '&' => '&amp;',
 930      '<' => '&lt;',
 931      '>' => '&gt;',
 932      '"' => '&quot;',
 933      "'" => '&#039;',
 934    }
 935
 936    def escape_xml(value)
 937      value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] }   # or /[&<>"']/
 938      #value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
 939    end
 940
 941    def escape_xml2(value)
 942      return value.to_s.gsub(/\&/,'&amp;').gsub(/</,'&lt;').gsub(/>/,'&gt;').gsub(/"/,'&quot;')
 943    end
 944
 945    alias h escape_xml
 946    alias html_escape escape_xml
 947
 948    def url_encode(str)
 949      return str.gsub(/[^-_.a-zA-Z0-9]+/) { |s|
 950        s.unpack('C*').collect { |i| "%%%02X" % i }.join
 951      }
 952    end
 953
 954    alias u url_encode
 955
 956  end
 957
 958
 959end
 960#--end of require 'erubis/helper'
 961#--begin of require 'erubis/enhancer'
 962##
 963## $Release: 2.6.6 $
 964## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
 965##
 966
 967
 968module Erubis
 969
 970
 971  ##
 972  ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
 973  ##
 974  ## ex.
 975  ##   class XmlEruby < Eruby
 976  ##     include EscapeEnhancer
 977  ##   end
 978  ##
 979  ## this is language-indenedent.
 980  ##
 981  module EscapeEnhancer
 982
 983    def self.desc   # :nodoc:
 984      "switch '<%= %>' to escaped and '<%== %>' to unescaped"
 985    end
 986
 987    #--
 988    #def self.included(klass)
 989    #  klass.class_eval <<-END
 990    #    alias _add_expr_literal add_expr_literal
 991    #    alias _add_expr_escaped add_expr_escaped
 992    #    alias add_expr_literal _add_expr_escaped
 993    #    alias add_expr_escaped _add_expr_literal
 994    #  END
 995    #end
 996    #++
 997
 998    def add_expr(src, code, indicator)
 999      case indicator
1000      when '='
1001        @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
1002      when '=='
1003        @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
1004      when '==='
1005        add_expr_debug(src, code)
1006      end
1007    end
1008
1009  end
1010
1011
1012  #--
1013  ## (obsolete)
1014  #module FastEnhancer
1015  #end
1016  #++
1017
1018
1019  ##
1020  ## use $stdout instead of string
1021  ##
1022  ## this is only for Eruby.
1023  ##
1024  module StdoutEnhancer
1025
1026    def self.desc   # :nodoc:
1027      "use $stdout instead of array buffer or string buffer"
1028    end
1029
1030    def add_preamble(src)
1031      src << "_buf = $stdout;"
1032    end
1033
1034    def add_postamble(src)
1035      src << "\n''\n"
1036    end
1037
1038  end
1039
1040
1041  ##
1042  ## use print statement instead of '_buf << ...'
1043  ##
1044  ## this is only for Eruby.
1045  ##
1046  module PrintOutEnhancer
1047
1048    def self.desc   # :nodoc:
1049      "use print statement instead of '_buf << ...'"
1050    end
1051
1052    def add_preamble(src)
1053    end
1054
1055    def add_text(src, text)
1056      src << " print '" << escape_text(text) << "';" unless text.empty?
1057    end
1058
1059    def add_expr_literal(src, code)
1060      src << ' print((' << code << ').to_s);'
1061    end
1062
1063    def add_expr_escaped(src, code)
1064      src << ' print ' << escaped_expr(code) << ';'
1065    end
1066
1067    def add_postamble(src)
1068      src << "\n" unless src[-1] == ?\n
1069    end
1070
1071  end
1072
1073
1074  ##
1075  ## enable print function
1076  ##
1077  ## Notice: use Eruby#evaluate() and don't use Eruby#result()
1078  ## to be enable print function.
1079  ##
1080  ## this is only for Eruby.
1081  ##
1082  module PrintEnabledEnhancer
1083
1084    def self.desc   # :nodoc:
1085      "enable to use print function in '<% %>'"
1086    end
1087
1088    def add_preamble(src)
1089      src << "@_buf = "
1090      super
1091    end
1092
1093    def print(*args)
1094      args.each do |arg|
1095        @_buf << arg.to_s
1096      end
1097    end
1098
1099    def evaluate(context=nil)
1100      _src = @src
1101      if context.is_a?(Hash)
1102        context.each do |key, val| instance_variable_set("@#{key}", val) end
1103      elsif context
1104        context.instance_variables.each do |name|
1105          instance_variable_set(name, context.instance_variable_get(name))
1106        end
1107      end
1108      return instance_eval(_src, (@filename || '(erubis)'))
1109    end
1110
1111  end
1112
1113
1114  ##
1115  ## return array instead of string
1116  ##
1117  ## this is only for Eruby.
1118  ##
1119  module ArrayEnhancer
1120
1121    def self.desc   # :nodoc:
1122      "return array instead of string"
1123    end
1124
1125    def add_preamble(src)
1126      src << "_buf = [];"
1127    end
1128
1129    def add_postamble(src)
1130      src << "\n" unless src[-1] == ?\n
1131      src << "_buf\n"
1132    end
1133
1134  end
1135
1136
1137  ##
1138  ## use an Array object as buffer (included in Eruby by default)
1139  ##
1140  ## this is only for Eruby.
1141  ##
1142  module ArrayBufferEnhancer
1143
1144    def self.desc   # :nodoc:
1145      "use an Array object for buffering (included in Eruby class)"
1146    end
1147
1148    def add_preamble(src)
1149      src << "_buf = [];"
1150    end
1151
1152    def add_postamble(src)
1153      src << "\n" unless src[-1] == ?\n
1154      src << "_buf.join\n"
1155    end
1156
1157  end
1158
1159
1160  ##
1161  ## use String class for buffering
1162  ##
1163  ## this is only for Eruby.
1164  ##
1165  module StringBufferEnhancer
1166
1167    def self.desc   # :nodoc:
1168      "use a String object for buffering"
1169    end
1170
1171    def add_preamble(src)
1172      src << "_buf = '';"
1173    end
1174
1175    def add_postamble(src)
1176      src << "\n" unless src[-1] == ?\n
1177      src << "_buf.to_s\n"
1178    end
1179
1180  end
1181
1182
1183  ##
1184  ## use StringIO class for buffering
1185  ##
1186  ## this is only for Eruby.
1187  ##
1188  module StringIOEnhancer  # :nodoc:
1189
1190    def self.desc   # :nodoc:
1191      "use a StringIO object for buffering"
1192    end
1193
1194    def add_preamble(src)
1195      src << "_buf = StringIO.new;"
1196    end
1197
1198    def add_postamble(src)
1199      src << "\n" unless src[-1] == ?\n
1200      src << "_buf.string\n"
1201    end
1202
1203  end
1204
1205
1206  ##
1207  ## set buffer variable name to '_erbout' as well as '_buf'
1208  ##
1209  ## this is only for Eruby.
1210  ##
1211  module ErboutEnhancer
1212
1213    def self.desc   # :nodoc:
1214      "set '_erbout = _buf = \"\";' to be compatible with ERB."
1215    end
1216
1217    def add_preamble(src)
1218      src << "_erbout = _buf = '';"
1219    end
1220
1221    def add_postamble(src)
1222      src << "\n" unless src[-1] == ?\n
1223      src << "_buf.to_s\n"
1224    end
1225
1226  end
1227
1228
1229  ##
1230  ## remove text and leave code, especially useful when debugging.
1231  ##
1232  ## ex.
1233  ##   $ erubis -s -E NoText file.eruby | more
1234  ##
1235  ## this is language independent.
1236  ##
1237  module NoTextEnhancer
1238
1239    def self.desc   # :nodoc:
1240      "remove text and leave code (useful when debugging)"
1241    end
1242
1243    def add_text(src, text)
1244      src << ("\n" * text.count("\n"))
1245      if text[-1] != ?\n
1246        text =~ /^(.*?)\z/
1247        src << (' ' * $1.length)
1248      end
1249    end
1250
1251  end
1252
1253
1254  ##
1255  ## remove code and leave text, especially useful when validating HTML tags.
1256  ##
1257  ## ex.
1258  ##   $ erubis -s -E NoCode file.eruby | tidy -errors
1259  ##
1260  ## this is language independent.
1261  ##
1262  module NoCodeEnhancer
1263
1264    def self.desc   # :nodoc:
1265      "remove code and leave text (useful when validating HTML)"
1266    end
1267
1268    def add_preamble(src)
1269    end
1270
1271    def add_postamble(src)
1272    end
1273
1274    def add_text(src, text)
1275      src << text
1276    end
1277
1278    def add_expr(src, code, indicator)
1279      src << "\n" * code.count("\n")
1280    end
1281
1282    def add_stmt(src, code)
1283      src << "\n" * code.count("\n")
1284    end
1285
1286  end
1287
1288
1289  ##
1290  ## get convert faster, but spaces around '<%...%>' are not trimmed.
1291  ##
1292  ## this is language-independent.
1293  ##
1294  module SimplifyEnhancer
1295
1296    def self.desc   # :nodoc:
1297      "get convert faster but leave spaces around '<% %>'"
1298    end
1299
1300    #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
1301    SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
1302
1303    def convert(input)
1304      src = ""
1305      add_preamble(src)
1306      #regexp = pattern_regexp(@pattern)
1307      pos = 0
1308      input.scan(SIMPLE_REGEXP) do |indicator, code|
1309        match = Regexp.last_match
1310        index = match.begin(0)
1311        text  = input[pos, index - pos]
1312        pos   = match.end(0)
1313        add_text(src, text)
1314        if !indicator              # <% %>
1315          add_stmt(src, code)
1316        elsif indicator[0] == ?\#  # <%# %>
1317          n = code.count("\n")
1318          add_stmt(src, "\n" * n)
1319        else                       # <%= %>
1320          add_expr(src, code, indicator)
1321        end
1322      end
1323      #rest = $' || input                      # ruby1.8
1324      rest = pos == 0 ? input : input[pos..-1]  # ruby1.9
1325      add_text(src, rest)
1326      add_postamble(src)
1327      return src
1328    end
1329
1330  end
1331
1332
1333  ##
1334  ## enable to use other embedded expression pattern (default is '\[= =\]').
1335  ##
1336  ## notice! this is an experimental. spec may change in the future.
1337  ##
1338  ## ex.
1339  ##   input = <<END
1340  ##   <% for item in list %>
1341  ##     <%= item %> : <%== item %>
1342  ##     [= item =] : [== item =]
1343  ##   <% end %>
1344  ##   END
1345  ##
1346  ##   class BiPatternEruby
1347  ##     include BiPatternEnhancer
1348  ##   end
1349  ##   eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
1350  ##   list = ['<a>', 'b&b', '"c"']
1351  ##   print eruby.result(binding())
1352  ##
1353  ##   ## output
1354  ##     <a> : &lt;a&gt;
1355  ##     <a> : &lt;a&gt;
1356  ##     b&b : b&amp;b
1357  ##     b&b : b&amp;b
1358  ##     "c" : &quot;c&quot;
1359  ##     "c" : &quot;c&quot;
1360  ##
1361  ## this is language independent.
1362  ##
1363  module BiPatternEnhancer
1364
1365    def self.desc   # :nodoc:
1366      "another embedded expression pattern (default '\[= =\]')."
1367    end
1368
1369    def initialize(input, properties={})
1370      self.bipattern = properties[:bipattern]    # or '\$\{ \}'
1371      super
1372    end
1373
1374    ## when pat is nil then '\[= =\]' is used
1375    def bipattern=(pat)   # :nodoc:
1376      @bipattern = pat || '\[= =\]'
1377      pre, post = @bipattern.split()
1378      @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
1379    end
1380
1381    def add_text(src, text)
1382      return unless text
1383      m = nil
1384      text.scan(@bipattern_regexp) do |txt, indicator, code|
1385        m = Regexp.last_match
1386        super(src, txt)
1387        add_expr(src, code, '=' + indicator)
1388      end
1389      #rest = $' || text                    # ruby1.8
1390      rest = m ? text[m.end(0)..-1] : text  # ruby1.9
1391      super(src, rest)
1392    end
1393
1394  end
1395
1396
1397  ##
1398  ## regards lines starting with '%' as program code
1399  ##
1400  ## this is for compatibility to eruby and ERB.
1401  ##
1402  ## this is language-independent.
1403  ##
1404  module PercentLineEnhancer
1405
1406    def self.desc   # :nodoc:
1407      "regard lines starting with '%' as program code"
1408    end
1409
1410    def add_text(src, text)
1411      pos = 0
1412      text2 = ''
1413      text.scan(/^\%(.*?\r?\n)/) do
1414        line  = $1
1415        match = Regexp.last_match
1416        len   = match.begin(0) - pos
1417        str   = text[pos, len]
1418        pos   = match.end(0)
1419        if text2.empty?
1420          text2 = str
1421        else
1422          text2 << str
1423        end
1424        if line[0] == ?%
1425          text2 << line
1426        else
1427          super(src, text2)
1428          text2 = ''
1429          add_stmt(src, line)
1430        end
1431      end
1432      #rest = pos == 0 ? text : $'             # ruby1.8
1433      rest = pos == 0 ? text : text[pos..-1]   # ruby1.9
1434      unless text2.empty?
1435        text2 << rest if rest
1436        rest = text2
1437      end
1438      super(src, rest)
1439    end
1440
1441  end
1442
1443
1444  ##
1445  ## [experimental] allow header and footer in eRuby script
1446  ##
1447  ## ex.
1448  ##   ====================
1449  ##   ## without header and footer
1450  ##   $ cat ex1.eruby
1451  ##   <% def list_items(list) %>
1452  ##   <%   for item in list %>
1453  ##   <li><%= item %></li>
1454  ##   <%   end %>
1455  ##   <% end %>
1456  ##
1457  ##   $ erubis -s ex1.eruby
1458  ##   _buf = []; def list_items(list)
1459  ##   ;   for item in list
1460  ##   ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
1461  ##   ';   end
1462  ##   ; end
1463  ##   ;
1464  ##   _buf.join
1465  ##
1466  ##   ## with header and footer
1467  ##   $ cat ex2.eruby
1468  ##   <!--#header:
1469  ##   def list_items(list)
1470  ##    #-->
1471  ##   <%  for item in list %>
1472  ##   <li><%= item %></li>
1473  ##   <%  end %>
1474  ##   <!--#footer:
1475  ##   end
1476  ##    #-->
1477  ##
1478  ##   $ erubis -s -c HeaderFooterEruby ex4.eruby
1479  ##
1480  ##   def list_items(list)
1481  ##    _buf = []; _buf << '
1482  ##   ';  for item in list
1483  ##   ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
1484  ##   ';  end
1485  ##   ; _buf << '
1486  ##   ';
1487  ##   _buf.join
1488  ##   end
1489  ##
1490  ##   ====================
1491  ##
1492  ## this is language-independent.
1493  ##
1494  module HeaderFooterEnhancer
1495
1496    def self.desc   # :nodoc:
1497      "allow header/footer in document (ex. '<!--#header: #-->')"
1498    end
1499
1500    HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
1501
1502    def add_text(src, text)
1503      m = nil
1504      text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
1505        m = Regexp.last_match
1506        flag_trim = @trim && lspace && rspace
1507        super(src, txt)
1508        content = "#{lspace}#{content}#{rspace}" if flag_trim
1509        super(src, lspace) if !flag_trim && lspace
1510        instance_variable_set("@#{word}", content)
1511        super(src, rspace) if !flag_trim && rspace
1512      end
1513      #rest = $' || text                    # ruby1.8
1514      rest = m ? text[m.end(0)..-1] : text  # ruby1.9
1515      super(src, rest)
1516    end
1517
1518    attr_accessor :header, :footer
1519
1520    def convert(input)
1521      source = super
1522      return @src = "#{@header}#{source}#{@footer}"
1523    end
1524
1525  end
1526
1527
1528  ##
1529  ## delete indentation of HTML.
1530  ##
1531  ## this is language-independent.
1532  ##
1533  module DeleteIndentEnhancer
1534
1535    def self.desc   # :nodoc:
1536      "delete indentation of HTML."
1537    end
1538
1539    def convert_input(src, input)
1540      input = input.gsub(/^[ \t]+</, '<')
1541      super(src, input)
1542    end
1543
1544  end
1545
1546
1547  ##
1548  ## convert "<h1><%=title%></h1>" into "_buf << %Q`<h1>#{title}</h1>`"
1549  ##
1550  ## this is only for Eruby.
1551  ##
1552  module InterpolationEnhancer
1553
1554    def self.desc   # :nodoc:
1555      "convert '<p><%=text%></p>' into '_buf << %Q`<p>\#{text}</p>`'"
1556    end
1557
1558    def convert_input(src, input)
1559      pat = @pattern
1560      regexp = pat.nil? || pat == '<% %>' ? Basic::Converter::DEFAULT_REGEXP : pattern_regexp(pat)
1561      pos = 0
1562      is_bol = true     # is beginning of line
1563      str = ''
1564      input.scan(regexp) do |indicator, code, tailch, rspace|
1565        match = Regexp.last_match()
1566        len  = match.begin(0) - pos
1567        text = input[pos, len]
1568        pos  = match.end(0)
1569        ch   = indicator ? indicator[0] : nil
1570        lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
1571        is_bol = rspace ? true : false
1572        _add_text_to_str(str, text)
1573        ## * when '<%= %>', do nothing
1574        ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
1575        if ch == ?=              # <%= %>
1576          rspace = nil if tailch && !tailch.empty?
1577          str << lspace if lspace
1578          add_expr(str, code, indicator)
1579          str << rspace if rspace
1580        elsif ch == ?\#          # <%# %>
1581          n = code.count("\n") + (rspace ? 1 : 0)
1582          if @trim && lspace && rspace
1583            add_text(src, str)
1584            str = ''
1585            add_stmt(src, "\n" * n)
1586          else
1587            str << lspace if lspace
1588            add_text(src, str)
1589            str = ''
1590            add_stmt(src, "\n" * n)
1591            str << rspace if rspace
1592          end
1593        else                     # <% %>
1594          if @trim && lspace && rspace
1595            add_text(src, str)
1596            str = ''
1597            add_stmt(src, "#{lspace}#{code}#{rspace}")
1598          else
1599            str << lspace if lspace
1600            add_text(src, str)
1601            str = ''
1602            add_stmt(src, code)
1603            str << rspace if rspace
1604          end
1605        end
1606      end
1607      #rest = $' || input                       # ruby1.8
1608      rest = pos == 0 ? input : input[pos..-1]  # ruby1.9
1609      _add_text_to_str(str, rest)
1610      add_text(src, str)
1611    end
1612
1613    def add_text(src, text)
1614      return if !text || text.empty?
1615      #src << " _buf << %Q`" << text << "`;"
1616      if text[-1] == ?\n
1617        text[-1] = "\\n"
1618        src << " _buf << %Q`" << text << "`\n"
1619      else
1620        src << " _buf << %Q`" << text << "`;"
1621      end
1622    end
1623
1624    def _add_text_to_str(str, text)
1625      return if !text || text.empty?
1626      text.gsub!(/[`\#\\]/, '\\\\\&')
1627      str << text
1628    end
1629
1630    def add_expr_escaped(str, code)
1631      str << "\#{#{escaped_expr(code)}}"
1632    end
1633
1634    def add_expr_literal(str, code)
1635      str << "\#{#{code}}"
1636    end
1637
1638  end
1639
1640
1641end
1642#--end of require 'erubis/enhancer'
1643#require 'erubis/tiny'
1644#--begin of require 'erubis/engine/eruby'
1645##
1646## $Release: 2.6.6 $
1647## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
1648##
1649
1650#--already included require 'erubis/engine'
1651#--already included require 'erubis/enhancer'
1652
1653
1654module Erubis
1655
1656
1657  ##
1658  ## code generator for Ruby
1659  ##
1660  module RubyGenerator
1661    include Generator
1662    #include ArrayBufferEnhancer
1663    include StringBufferEnhancer
1664
1665    def init_generator(properties={})
1666      super
1667      @escapefunc ||= "Erubis::XmlHelper.escape_xml"
1668    end
1669
1670    def self.supported_properties()  # :nodoc:
1671      return []
1672    end
1673
1674    def escape_text(text)
1675      text.gsub(/['\\]/, '\\\\\&')   # "'" => "\\'",  '\\' => '\\\\'
1676    end
1677
1678    def escaped_expr(code)
1679      return "#{@escapefunc}(#{code})"
1680    end
1681
1682    #--
1683    #def add_preamble(src)
1684    #  src << "_buf = [];"
1685    #end
1686    #++
1687
1688    def add_text(src, text)
1689      src << " _buf << '" << escape_text(text) << "';" unless text.empty?
1690    end
1691
1692    def add_stmt(src, code)
1693      #src << code << ';'
1694      src << code
1695      src << ';' unless code[-1] == ?\n
1696    end
1697
1698    def add_expr_literal(src, code)
1699      src << ' _buf << (' << code << ').to_s;'
1700    end
1701
1702    def add_expr_escaped(src, code)
1703      src << ' _buf << ' << escaped_expr(code) << ';'
1704    end
1705
1706    def add_expr_debug(src, code)
1707      code.strip!
1708      s = (code.dump =~ /\A"(.*)"\z/) && $1
1709      src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
1710    end
1711
1712    #--
1713    #def add_postamble(src)
1714    #  src << "\n_buf.join\n"
1715    #end
1716    #++
1717
1718  end
1719
1720
1721  ##
1722  ## engine for Ruby
1723  ##
1724  class Eruby < Basic::Engine
1725    include RubyEvaluator
1726    include RubyGenerator
1727  end
1728
1729
1730  ##
1731  ## fast engine for Ruby
1732  ##
1733  class FastEruby < Eruby
1734    include InterpolationEnhancer
1735  end
1736
1737
1738  ##
1739  ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
1740  ##
1741  class EscapedEruby < Eruby
1742    include EscapeEnhancer
1743  end
1744
1745
1746  ##
1747  ## sanitize expression (<%= ... %>) by default
1748  ##
1749  ## this is equivalent to EscapedEruby and is prepared only for compatibility.
1750  ##
1751  class XmlEruby < Eruby
1752    include EscapeEnhancer
1753  end
1754
1755
1756  class PI::Eruby < PI::Engine
1757    include RubyEvaluator
1758    include RubyGenerator
1759
1760    def init_converter(properties={})
1761      @pi = 'rb'
1762      super(properties)
1763    end
1764
1765  end
1766
1767
1768end
1769#--end of require 'erubis/engine/eruby'
1770#require 'erubis/engine/enhanced'    # enhanced eruby engines
1771#require 'erubis/engine/optimized'   # generates optimized ruby code
1772#require 'erubis/engine/ephp'
1773#require 'erubis/engine/ec'
1774#require 'erubis/engine/ejava'
1775#require 'erubis/engine/escheme'
1776#require 'erubis/engine/eperl'
1777#require 'erubis/engine/ejavascript'
1778
1779#--begin of require 'erubis/local-setting'
1780##
1781## $Release: 2.6.6 $
1782## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
1783##
1784
1785##
1786## you can add site-local settings here.
1787## this files is required by erubis.rb
1788##
1789#--end of require 'erubis/local-setting'
1790#--end of require 'erubis'
1791#--begin of require 'erubis/tiny'
1792##
1793## $Release: 2.6.6 $
1794## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
1795##
1796
1797module Erubis
1798
1799  ##
1800  ## tiny and the simplest implementation of eRuby
1801  ##
1802  ## ex.
1803  ##   eruby = TinyEruby.new(File.read('example.rhtml'))
1804  ##   print eruby.src                 # print ruby code
1805  ##   print eruby.result(binding())   # eval ruby code with Binding object
1806  ##   print eruby.evalute(context)    # eval ruby code with context object
1807  ##
1808  class TinyEruby
1809
1810    def initialize(input=nil)
1811      @src = convert(input) if input
1812    end
1813    attr_reader :src
1814
1815    EMBEDDED_PATTERN = /<%(=+|\#)?(.*?)-?%>/m
1816
1817    def convert(input)
1818      src = "_buf = '';"           # preamble
1819      pos = 0
1820      input.scan(EMBEDDED_PATTERN) do |indicator, code|
1821        m = Regexp.last_match
1822        text = input[pos...m.begin(0)]
1823        pos  = m.end(0)
1824        #src << " _buf << '" << escape_text(text) << "';"
1825        text.gsub!(/['\\]/, '\\\\\&')
1826        src << " _buf << '" << text << "';" unless text.empty?
1827        if !indicator              # <% %>
1828          src << code << ";"
1829        elsif indicator == '#'     # <%# %>
1830          src << ("\n" * code.count("\n"))
1831        else                       # <%= %>
1832          src << " _buf << (" << code << ").to_s;"
1833        end
1834      end
1835      #rest = $' || input                        # ruby1.8
1836      rest = pos == 0 ? input : input[pos..-1]   # ruby1.9
1837      #src << " _buf << '" << escape_text(rest) << "';"
1838      rest.gsub!(/['\\]/, '\\\\\&')
1839      src << " _buf << '" << rest << "';" unless rest.empty?
1840      src << "\n_buf.to_s\n"       # postamble
1841      return src
1842    end
1843
1844    #def escape_text(text)
1845    #  return text.gsub!(/['\\]/, '\\\\\&') || text
1846    #end
1847
1848    def result(_binding=TOPLEVEL_BINDING)
1849      eval @src, _binding
1850    end
1851
1852    def evaluate(_context=Object.new)
1853      if _context.is_a?(Hash)
1854        _obj = Object.new
1855        _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1856        _context = _obj
1857      end
1858      _context.instance_eval @src
1859    end
1860
1861  end
1862
1863
1864
1865  module PI
1866  end
1867
1868  class PI::TinyEruby
1869
1870    def initialize(input=nil, options={})
1871      @escape  = options[:escape] || 'Erubis::XmlHelper.escape_xml'
1872      @src = convert(input) if input
1873    end
1874
1875    attr_reader :src
1876
1877    EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|@(!+)?\{(.*?)\}@/m
1878
1879    def convert(input)
1880      src = "_buf = '';"           # preamble
1881      pos = 0
1882      input.scan(EMBEDDED_PATTERN) do |lspace, stmt, rspace, indicator, expr|
1883        match = Regexp.last_match
1884        len   = match.begin(0) - pos
1885        text  = input[pos, len]
1886        pos   = match.end(0)
1887        #src << " _buf << '" << escape_text(text) << "';"
1888        text.gsub!(/['\\]/, '\\\\\&')
1889        src << " _buf << '" << text << "';" unless text.empty?
1890        if stmt                # <?rb ... ?>
1891          if lspace && rspace
1892            src << "#{lspace}#{stmt}#{rspace}"
1893          else
1894            src << " _buf << '" << lspace << "';" if lspace
1895            src << stmt << ";"
1896            src << " _buf << '" << rspace << "';" if rspace
1897          end
1898        else                       # ${...}, $!{...}
1899          if !indicator
1900            src << " _buf << " << @escape << "(" << expr << ");"
1901          elsif indicator == '!'
1902            src << " _buf << (" << expr << ").to_s;"
1903          end
1904        end
1905      end
1906      #rest = $' || input                        # ruby1.8
1907      rest = pos == 0 ? input : input[pos..-1]   # ruby1.9
1908      #src << " _buf << '" << escape_text(rest) << "';"
1909      rest.gsub!(/['\\]/, '\\\\\&')
1910      src << " _buf << '" << rest << "';" unless rest.empty?
1911      src << "\n_buf.to_s\n"       # postamble
1912      return src
1913    end
1914
1915    #def escape_text(text)
1916    #  return text.gsub!(/['\\]/, '\\\\\&') || text
1917    #end
1918
1919    def result(_binding=TOPLEVEL_BINDING)
1920      eval @src, _binding
1921    end
1922
1923    def evaluate(_context=Object.new)
1924      if _context.is_a?(Hash)
1925        _obj = Object.new
1926        _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1927        _context = _obj
1928      end
1929      _context.instance_eval @src
1930    end
1931
1932  end
1933
1934
1935end
1936#--end of require 'erubis/tiny'
1937#--begin of require 'erubis/engine/enhanced'
1938##
1939## $Release: 2.6.6 $
1940## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
1941##
1942
1943#--already included require 'erubis/enhancer'
1944#--already included require 'erubis/engine/eruby'
1945
1946
1947module Erubis
1948
1949
1950  #--
1951  ## moved to engine/ruby.rb
1952  #class EscapedEruby < Eruby
1953  #  include EscapeEnhancer
1954  #end
1955  #++
1956
1957
1958  #--
1959  ### (obsolete)
1960  #class FastEruby < Eruby
1961  #  include FastEnhancer
1962  #end
1963  #++
1964
1965
1966  class StdoutEruby < Eruby
1967    include StdoutEnhancer
1968  end
1969
1970
1971  class PrintOutEruby < Eruby
1972    include PrintOutEnhancer
1973  end
1974
1975
1976  class PrintEnabledEruby < Eruby
1977    include PrintEnabledEnhancer
1978  end
1979
1980
1981  class ArrayEruby < Eruby
1982    include ArrayEnhancer
1983  end
1984
1985
1986  class ArrayBufferEruby < Eruby
1987    include ArrayBufferEnhancer
1988  end
1989
1990
1991  class StringBufferEruby < Eruby
1992    include StringBufferEnhancer
1993  end
1994
1995
1996  class StringIOEruby < Eruby
1997    include StringIOEnhancer
1998  end
1999
2000
2001  class ErboutEruby < Eruby
2002    include ErboutEnhancer
2003  end
2004
2005
2006  class NoTextEruby < Eruby
2007    include NoTextEnhancer
2008  end
2009
2010
2011  class NoCodeEruby < Eruby
2012    include NoCodeEnhancer
2013  end
2014
2015
2016  class SimplifiedEruby < Eruby
2017    include SimplifyEnhancer
2018  end
2019
2020
2021  class StdoutSimplifiedEruby < Eruby
2022    include StdoutEnhancer
2023    include SimplifyEnhancer
2024  end
2025
2026
2027  class PrintOutSimplifiedEruby < Eruby
2028    include PrintOutEnhancer
2029    include SimplifyEnhancer
2030  end
2031
2032
2033  class BiPatternEruby < Eruby
2034    include BiPatternEnhancer
2035  end
2036
2037
2038  class PercentLineEruby < Eruby
2039    include PercentLineEnhancer
2040  end
2041
2042
2043  class HeaderFooterEruby < Eruby
2044    include HeaderFooterEnhancer
2045  end
2046
2047
2048  class DeleteIndentEruby < Eruby
2049    include DeleteIndentEnhancer
2050  end
2051
2052
2053  class InterpolationEruby < Eruby
2054    include InterpolationEnhancer
2055  end
2056
2057
2058end
2059#--end of require 'erubis/engine/enhanced'
2060#--begin of require 'erubis/engine/optimized'
2061##
2062## $Release: 2.6.6 $
2063## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
2064##
2065
2066
2067#--already included require 'erubis/engine/eruby'
2068
2069
2070module Erubis
2071
2072
2073  module OptimizedGenerator
2074    include Generator
2075
2076    def self.supported_properties()  # :nodoc:
2077      return []
2078    end
2079
2080    def init_generator(properties={})
2081      super
2082      @escapefunc ||= "Erubis::XmlHelper.escape_xml"
2083      @initialized = false
2084      @prev_is_expr = false
2085    end
2086
2087    protected
2088
2089    def escape_text(text)
2090      text.gsub(/['\\]/, '\\\\\&')   # "'" => "\\'",  '\\' => '\\\\'
2091    end
2092
2093    def escaped_expr(code)
2094      @escapefunc ||= 'Erubis::XmlHelper.escape_xml'
2095      return "#{@escapefunc}(#{code})"
2096    end
2097
2098    def switch_to_expr(src)
2099      return if @prev_is_expr
2100      @prev_is_expr = true
2101      src << ' _buf'
2102    end
2103
2104    def switch_to_stmt(src)
2105      return unless @prev_is_expr
2106      @prev_is_expr = false
2107      src << ';'
2108    end
2109
2110    def add_preamble(src)
2111      #@initialized = false
2112      #@prev_is_expr = false
2113    end
2114
2115    def add_text(src, text)
2116      return if text.empty?
2117      if @initialized
2118        switch_to_expr(src)
2119        src << " << '" << escape_text(text) << "'"
2120      else
2121        src << "_buf = '" << escape_text(text) << "';"
2122        @initialized = true
2123      end
2124    end
2125
2126    def add_stmt(src, code)
2127      switch_to_stmt(src) if @initialized
2128      #super
2129      src << code
2130      src << ';' unless code[-1] == ?\n
2131    end
2132
2133    def add_expr_literal(src, code)
2134      unless @initialized; src << "_buf = ''"; @initialized = true; end
2135      switch_to_expr(src)
2136      src << " << (" << code << ").to_s"
2137    end
2138
2139    def add_expr_escaped(src, code)
2140      unless @initialized; src << "_buf = ''"; @initialized = true; end
2141      switch_to_expr(src)
2142      src << " << " << escaped_expr(code)
2143    end
2144
2145    def add_expr_debug(src, code)
2146      code.strip!
2147      s = (code.dump =~ /\A"(.*)"\z/) && $1
2148      src << ' $stderr.puts("*** deb…

Large files files are truncated, but you can click here to view the full file