PageRenderTime 67ms CodeModel.GetById 22ms 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
Possible License(s): ISC, GPL-2.0
  1. #!/usr/bin/env ruby
  2. ###
  3. ### $Release: 2.6.6 $
  4. ### copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  5. ###
  6. #--begin of require 'erubis/main'
  7. ###
  8. ### $Release: 2.6.6 $
  9. ### copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  10. ###
  11. require 'yaml'
  12. #--begin of require 'erubis'
  13. ##
  14. ## $Release: 2.6.6 $
  15. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  16. ##
  17. ##
  18. ## an implementation of eRuby
  19. ##
  20. ## ex.
  21. ## input = <<'END'
  22. ## <ul>
  23. ## <% for item in @list %>
  24. ## <li><%= item %>
  25. ## <%== item %></li>
  26. ## <% end %>
  27. ## </ul>
  28. ## END
  29. ## list = ['<aaa>', 'b&b', '"ccc"']
  30. ## eruby = Erubis::Eruby.new(input)
  31. ## puts "--- code ---"
  32. ## puts eruby.src
  33. ## puts "--- result ---"
  34. ## context = Erubis::Context.new() # or new(:list=>list)
  35. ## context[:list] = list
  36. ## puts eruby.evaluate(context)
  37. ##
  38. ## result:
  39. ## --- source ---
  40. ## _buf = ''; _buf << '<ul>
  41. ## '; for item in @list
  42. ## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
  43. ## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
  44. ## '; end
  45. ## _buf << '</ul>
  46. ## ';
  47. ## _buf.to_s
  48. ## --- result ---
  49. ## <ul>
  50. ## <li><aaa>
  51. ## &lt;aaa&gt;</li>
  52. ## <li>b&b
  53. ## b&amp;b</li>
  54. ## <li>"ccc"
  55. ## &quot;ccc&quot;</li>
  56. ## </ul>
  57. ##
  58. module Erubis
  59. VERSION = ('$Release: 2.6.6 $' =~ /([.\d]+)/) && $1
  60. end
  61. #--begin of require 'erubis/engine'
  62. ##
  63. ## $Release: 2.6.6 $
  64. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  65. ##
  66. #--begin of require 'erubis/generator'
  67. ##
  68. ## $Release: 2.6.6 $
  69. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  70. ##
  71. #--begin of require 'abstract'
  72. ##
  73. ## $Rev: 1 $
  74. ## $Release: 0.1.0 $
  75. ## copyright(c) 2006 kuwata-lab.com all rights reserved.
  76. ##
  77. ##
  78. ## helper to define abstract method in Ruby.
  79. ##
  80. ##
  81. ## example1. (shorter notation)
  82. ##
  83. ## require 'abstract'
  84. ## class Foo
  85. ## abstract_method 'arg1, arg2=""', :method1, :method2, :method3
  86. ## end
  87. ##
  88. ##
  89. ## example2. (RDoc friendly notation)
  90. ##
  91. ## require 'abstract'
  92. ## class Bar
  93. ## # ... method1 description ...
  94. ## def method1(arg1, arg2="")
  95. ## not_implemented
  96. ## end
  97. ##
  98. ## # ... method2 description ...
  99. ## def method2(arg1, arg2="")
  100. ## not_implemented
  101. ## end
  102. ## end
  103. ##
  104. ##
  105. class Module
  106. ##
  107. ## define abstract methods
  108. ##
  109. def abstract_method args_str, *method_names
  110. method_names.each do |name|
  111. module_eval <<-END
  112. def #{name}(#{args_str})
  113. mesg = "class \#{self.class.name} must implement abstract method `#{self.name}##{name}()'."
  114. #mesg = "\#{self.class.name}##{name}() is not implemented."
  115. err = NotImplementedError.new mesg
  116. err.set_backtrace caller()
  117. raise err
  118. end
  119. END
  120. end
  121. end
  122. end
  123. ##
  124. module Kernel
  125. ##
  126. ## raise NotImplementedError
  127. ##
  128. def not_implemented #:doc:
  129. backtrace = caller()
  130. method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
  131. mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
  132. #mesg = "#{self.class.name}##{method_name}() is not implemented."
  133. err = NotImplementedError.new mesg
  134. err.set_backtrace backtrace
  135. raise err
  136. end
  137. private :not_implemented
  138. end
  139. #--end of require 'abstract'
  140. module Erubis
  141. ##
  142. ## code generator, called by Converter module
  143. ##
  144. module Generator
  145. def self.supported_properties() # :nodoc:
  146. return [
  147. [:escapefunc, nil, "escape function name"],
  148. ]
  149. end
  150. attr_accessor :escapefunc
  151. def init_generator(properties={})
  152. @escapefunc = properties[:escapefunc]
  153. end
  154. ## (abstract) escape text string
  155. ##
  156. ## ex.
  157. ## def escape_text(text)
  158. ## return text.dump
  159. ## # or return "'" + text.gsub(/['\\]/, '\\\\\&') + "'"
  160. ## end
  161. def escape_text(text)
  162. not_implemented
  163. end
  164. ## return escaped expression code (ex. 'h(...)' or 'htmlspecialchars(...)')
  165. def escaped_expr(code)
  166. code.strip!
  167. return "#{@escapefunc}(#{code})"
  168. end
  169. ## (abstract) add @preamble to src
  170. def add_preamble(src)
  171. not_implemented
  172. end
  173. ## (abstract) add text string to src
  174. def add_text(src, text)
  175. not_implemented
  176. end
  177. ## (abstract) add statement code to src
  178. def add_stmt(src, code)
  179. not_implemented
  180. end
  181. ## (abstract) add expression literal code to src. this is called by add_expr().
  182. def add_expr_literal(src, code)
  183. not_implemented
  184. end
  185. ## (abstract) add escaped expression code to src. this is called by add_expr().
  186. def add_expr_escaped(src, code)
  187. not_implemented
  188. end
  189. ## (abstract) add expression code to src for debug. this is called by add_expr().
  190. def add_expr_debug(src, code)
  191. not_implemented
  192. end
  193. ## (abstract) add @postamble to src
  194. def add_postamble(src)
  195. not_implemented
  196. end
  197. end
  198. end
  199. #--end of require 'erubis/generator'
  200. #--begin of require 'erubis/converter'
  201. ##
  202. ## $Release: 2.6.6 $
  203. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  204. ##
  205. #--already included require 'abstract'
  206. module Erubis
  207. ##
  208. ## convert
  209. ##
  210. module Converter
  211. attr_accessor :preamble, :postamble, :escape
  212. def self.supported_properties # :nodoc:
  213. return [
  214. [:preamble, nil, "preamble (no preamble when false)"],
  215. [:postamble, nil, "postamble (no postamble when false)"],
  216. [:escape, nil, "escape expression or not in default"],
  217. ]
  218. end
  219. def init_converter(properties={})
  220. @preamble = properties[:preamble]
  221. @postamble = properties[:postamble]
  222. @escape = properties[:escape]
  223. end
  224. ## convert input string into target language
  225. def convert(input)
  226. codebuf = "" # or []
  227. @preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
  228. convert_input(codebuf, input)
  229. @postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
  230. @_proc = nil # clear cached proc object
  231. return codebuf # or codebuf.join()
  232. end
  233. protected
  234. ##
  235. ## detect spaces at beginning of line
  236. ##
  237. def detect_spaces_at_bol(text, is_bol)
  238. lspace = nil
  239. if text.empty?
  240. lspace = "" if is_bol
  241. elsif text[-1] == ?\n
  242. lspace = ""
  243. else
  244. rindex = text.rindex(?\n)
  245. if rindex
  246. s = text[rindex+1..-1]
  247. if s =~ /\A[ \t]*\z/
  248. lspace = s
  249. #text = text[0..rindex]
  250. text[rindex+1..-1] = ''
  251. end
  252. else
  253. if is_bol && text =~ /\A[ \t]*\z/
  254. #lspace = text
  255. #text = nil
  256. lspace = text.dup
  257. text[0..-1] = ''
  258. end
  259. end
  260. end
  261. return lspace
  262. end
  263. ##
  264. ## (abstract) convert input to code
  265. ##
  266. def convert_input(codebuf, input)
  267. not_implemented
  268. end
  269. end
  270. module Basic
  271. end
  272. ##
  273. ## basic converter which supports '<% ... %>' notation.
  274. ##
  275. module Basic::Converter
  276. include Erubis::Converter
  277. def self.supported_properties # :nodoc:
  278. return [
  279. [:pattern, '<% %>', "embed pattern"],
  280. [:trim, true, "trim spaces around <% ... %>"],
  281. ]
  282. end
  283. attr_accessor :pattern, :trim
  284. def init_converter(properties={})
  285. super(properties)
  286. @pattern = properties[:pattern]
  287. @trim = properties[:trim] != false
  288. end
  289. protected
  290. ## return regexp of pattern to parse eRuby script
  291. def pattern_regexp(pattern)
  292. @prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
  293. #return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
  294. #return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
  295. return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
  296. end
  297. module_function :pattern_regexp
  298. #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  299. #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  300. #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  301. DEFAULT_REGEXP = pattern_regexp('<% %>')
  302. public
  303. def convert_input(src, input)
  304. pat = @pattern
  305. regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
  306. pos = 0
  307. is_bol = true # is beginning of line
  308. input.scan(regexp) do |indicator, code, tailch, rspace|
  309. match = Regexp.last_match()
  310. len = match.begin(0) - pos
  311. text = input[pos, len]
  312. pos = match.end(0)
  313. ch = indicator ? indicator[0] : nil
  314. lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
  315. is_bol = rspace ? true : false
  316. add_text(src, text) if text && !text.empty?
  317. ## * when '<%= %>', do nothing
  318. ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
  319. if ch == ?= # <%= %>
  320. rspace = nil if tailch && !tailch.empty?
  321. add_text(src, lspace) if lspace
  322. add_expr(src, code, indicator)
  323. add_text(src, rspace) if rspace
  324. elsif ch == ?\# # <%# %>
  325. n = code.count("\n") + (rspace ? 1 : 0)
  326. if @trim && lspace && rspace
  327. add_stmt(src, "\n" * n)
  328. else
  329. add_text(src, lspace) if lspace
  330. add_stmt(src, "\n" * n)
  331. add_text(src, rspace) if rspace
  332. end
  333. elsif ch == ?% # <%% %>
  334. s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
  335. add_text(src, s)
  336. else # <% %>
  337. if @trim && lspace && rspace
  338. add_stmt(src, "#{lspace}#{code}#{rspace}")
  339. else
  340. add_text(src, lspace) if lspace
  341. add_stmt(src, code)
  342. add_text(src, rspace) if rspace
  343. end
  344. end
  345. end
  346. #rest = $' || input # ruby1.8
  347. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  348. add_text(src, rest)
  349. end
  350. ## add expression code to src
  351. def add_expr(src, code, indicator)
  352. case indicator
  353. when '='
  354. @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
  355. when '=='
  356. @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
  357. when '==='
  358. add_expr_debug(src, code)
  359. end
  360. end
  361. end
  362. module PI
  363. end
  364. ##
  365. ## Processing Instructions (PI) converter for XML.
  366. ## this class converts '<?rb ... ?>' and '${...}' notation.
  367. ##
  368. module PI::Converter
  369. include Erubis::Converter
  370. def self.desc # :nodoc:
  371. "use processing instructions (PI) instead of '<% %>'"
  372. end
  373. def self.supported_properties # :nodoc:
  374. return [
  375. [:trim, true, "trim spaces around <% ... %>"],
  376. [:pi, 'rb', "PI (Processing Instrunctions) name"],
  377. [:embchar, '@', "char for embedded expression pattern('@{...}@')"],
  378. [:pattern, '<% %>', "embed pattern"],
  379. ]
  380. end
  381. attr_accessor :pi, :prefix
  382. def init_converter(properties={})
  383. super(properties)
  384. @trim = properties.fetch(:trim, true)
  385. @pi = properties[:pi] if properties[:pi]
  386. @embchar = properties[:embchar] || '@'
  387. @pattern = properties[:pattern]
  388. @pattern = '<% %>' if @pattern.nil? #|| @pattern == true
  389. end
  390. def convert(input)
  391. code = super(input)
  392. return @header || @footer ? "#{@header}#{code}#{@footer}" : code
  393. end
  394. protected
  395. def convert_input(codebuf, input)
  396. unless @regexp
  397. @pi ||= 'e'
  398. ch = Regexp.escape(@embchar)
  399. if @pattern
  400. left, right = @pattern.split(' ')
  401. @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
  402. else
  403. @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
  404. end
  405. end
  406. #
  407. is_bol = true
  408. pos = 0
  409. input.scan(@regexp) do |pi_arg, stmt, rspace,
  410. indicator1, expr1, indicator2, expr2|
  411. match = Regexp.last_match
  412. len = match.begin(0) - pos
  413. text = input[pos, len]
  414. pos = match.end(0)
  415. lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
  416. is_bol = stmt && rspace ? true : false
  417. add_text(codebuf, text) # unless text.empty?
  418. #
  419. if stmt
  420. if @trim && lspace && rspace
  421. add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
  422. else
  423. add_text(codebuf, lspace) if lspace
  424. add_pi_stmt(codebuf, stmt, pi_arg)
  425. add_text(codebuf, rspace) if rspace
  426. end
  427. else
  428. add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
  429. end
  430. end
  431. #rest = $' || input # ruby1.8
  432. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  433. add_text(codebuf, rest)
  434. end
  435. #--
  436. #def convert_input(codebuf, input)
  437. # parse_stmts(codebuf, input)
  438. # #parse_stmts2(codebuf, input)
  439. #end
  440. #
  441. #def parse_stmts(codebuf, input)
  442. # #regexp = pattern_regexp(@pattern)
  443. # @pi ||= 'e'
  444. # @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
  445. # is_bol = true
  446. # pos = 0
  447. # input.scan(@stmt_pattern) do |pi_arg, code, rspace|
  448. # match = Regexp.last_match
  449. # len = match.begin(0) - pos
  450. # text = input[pos, len]
  451. # pos = match.end(0)
  452. # lspace = detect_spaces_at_bol(text, is_bol)
  453. # is_bol = rspace ? true : false
  454. # parse_exprs(codebuf, text) # unless text.empty?
  455. # if @trim && lspace && rspace
  456. # add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
  457. # else
  458. # add_text(codebuf, lspace)
  459. # add_pi_stmt(codebuf, code, pi_arg)
  460. # add_text(codebuf, rspace)
  461. # end
  462. # end
  463. # rest = $' || input
  464. # parse_exprs(codebuf, rest)
  465. #end
  466. #
  467. #def parse_exprs(codebuf, input)
  468. # unless @expr_pattern
  469. # ch = Regexp.escape(@embchar)
  470. # if @pattern
  471. # left, right = @pattern.split(' ')
  472. # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
  473. # else
  474. # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
  475. # end
  476. # end
  477. # pos = 0
  478. # input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
  479. # indicator = indicator1 || indicator2
  480. # code = code1 || code2
  481. # match = Regexp.last_match
  482. # len = match.begin(0) - pos
  483. # text = input[pos, len]
  484. # pos = match.end(0)
  485. # add_text(codebuf, text) # unless text.empty?
  486. # add_pi_expr(codebuf, code, indicator)
  487. # end
  488. # rest = $' || input
  489. # add_text(codebuf, rest)
  490. #end
  491. #++
  492. def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
  493. case pi_arg
  494. when nil ; add_stmt(codebuf, code)
  495. when 'header' ; @header = code
  496. when 'footer' ; @footer = code
  497. when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
  498. when 'value' ; add_expr_literal(codebuf, code)
  499. else ; add_stmt(codebuf, code)
  500. end
  501. end
  502. def add_pi_expr(codebuf, code, indicator) # :nodoc:
  503. case indicator
  504. when nil, '', '==' # @{...}@ or <%== ... %>
  505. @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
  506. when '!', '=' # @!{...}@ or <%= ... %>
  507. @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
  508. when '!!', '===' # @!!{...}@ or <%=== ... %>
  509. add_expr_debug(codebuf, code)
  510. else
  511. # ignore
  512. end
  513. end
  514. end
  515. end
  516. #--end of require 'erubis/converter'
  517. #--begin of require 'erubis/evaluator'
  518. ##
  519. ## $Release: 2.6.6 $
  520. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  521. ##
  522. #--begin of require 'erubis/error'
  523. ##
  524. ## $Release: 2.6.6 $
  525. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  526. ##
  527. module Erubis
  528. ##
  529. ## base error class
  530. ##
  531. class ErubisError < StandardError
  532. end
  533. ##
  534. ## raised when method or function is not supported
  535. ##
  536. class NotSupportedError < ErubisError
  537. end
  538. end
  539. #--end of require 'erubis/error'
  540. #--begin of require 'erubis/context'
  541. ##
  542. ## $Release: 2.6.6 $
  543. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  544. ##
  545. module Erubis
  546. ##
  547. ## context object for Engine#evaluate
  548. ##
  549. ## ex.
  550. ## template = <<'END'
  551. ## Hello <%= @user %>!
  552. ## <% for item in @list %>
  553. ## - <%= item %>
  554. ## <% end %>
  555. ## END
  556. ##
  557. ## context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
  558. ## # or
  559. ## # context = Erubis::Context.new
  560. ## # context[:user] = 'World'
  561. ## # context[:list] = ['a', 'b', 'c']
  562. ##
  563. ## eruby = Erubis::Eruby.new(template)
  564. ## print eruby.evaluate(context)
  565. ##
  566. class Context
  567. include Enumerable
  568. def initialize(hash=nil)
  569. hash.each do |name, value|
  570. self[name] = value
  571. end if hash
  572. end
  573. def [](key)
  574. return instance_variable_get("@#{key}")
  575. end
  576. def []=(key, value)
  577. return instance_variable_set("@#{key}", value)
  578. end
  579. def keys
  580. return instance_variables.collect { |name| name[1..-1] }
  581. end
  582. def each
  583. instance_variables.each do |name|
  584. key = name[1..-1]
  585. value = instance_variable_get(name)
  586. yield(key, value)
  587. end
  588. end
  589. def to_hash
  590. hash = {}
  591. self.keys.each { |key| hash[key] = self[key] }
  592. return hash
  593. end
  594. def update(context_or_hash)
  595. arg = context_or_hash
  596. if arg.is_a?(Hash)
  597. arg.each do |key, val|
  598. self[key] = val
  599. end
  600. else
  601. arg.instance_variables.each do |varname|
  602. key = varname[1..-1]
  603. val = arg.instance_variable_get(varname)
  604. self[key] = val
  605. end
  606. end
  607. end
  608. end
  609. end
  610. #--end of require 'erubis/context'
  611. module Erubis
  612. EMPTY_BINDING = binding()
  613. ##
  614. ## evaluate code
  615. ##
  616. module Evaluator
  617. def self.supported_properties # :nodoc:
  618. return []
  619. end
  620. attr_accessor :src, :filename
  621. def init_evaluator(properties)
  622. @filename = properties[:filename]
  623. end
  624. def result(*args)
  625. raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
  626. end
  627. def evaluate(*args)
  628. raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
  629. end
  630. end
  631. ##
  632. ## evaluator for Ruby
  633. ##
  634. module RubyEvaluator
  635. include Evaluator
  636. def self.supported_properties # :nodoc:
  637. list = Evaluator.supported_properties
  638. return list
  639. end
  640. ## eval(@src) with binding object
  641. def result(_binding_or_hash=TOPLEVEL_BINDING)
  642. _arg = _binding_or_hash
  643. if _arg.is_a?(Hash)
  644. _b = binding()
  645. eval _arg.collect{|k,v| "#{k} = _arg[#{k.inspect}]; "}.join, _b
  646. elsif _arg.is_a?(Binding)
  647. _b = _arg
  648. elsif _arg.nil?
  649. _b = binding()
  650. else
  651. raise ArgumentError.new("#{self.class.name}#result(): argument should be Binding or Hash but passed #{_arg.class.name} object.")
  652. end
  653. return eval(@src, _b, (@filename || '(erubis'))
  654. end
  655. ## invoke context.instance_eval(@src)
  656. def evaluate(_context=Context.new)
  657. _context = Context.new(_context) if _context.is_a?(Hash)
  658. #return _context.instance_eval(@src, @filename || '(erubis)')
  659. #@_proc ||= eval("proc { #{@src} }", Erubis::EMPTY_BINDING, @filename || '(erubis)')
  660. @_proc ||= eval("proc { #{@src} }", binding(), @filename || '(erubis)')
  661. return _context.instance_eval(&@_proc)
  662. end
  663. ## if object is an Class or Module then define instance method to it,
  664. ## else define singleton method to it.
  665. def def_method(object, method_name, filename=nil)
  666. m = object.is_a?(Module) ? :module_eval : :instance_eval
  667. object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
  668. end
  669. end
  670. end
  671. #--end of require 'erubis/evaluator'
  672. #--already included require 'erubis/context'
  673. module Erubis
  674. ##
  675. ## (abstract) abstract engine class.
  676. ## subclass must include evaluator and converter module.
  677. ##
  678. class Engine
  679. #include Evaluator
  680. #include Converter
  681. #include Generator
  682. def initialize(input=nil, properties={})
  683. #@input = input
  684. init_generator(properties)
  685. init_converter(properties)
  686. init_evaluator(properties)
  687. @src = convert(input) if input
  688. end
  689. ##
  690. ## convert input string and set it to @src
  691. ##
  692. def convert!(input)
  693. @src = convert(input)
  694. end
  695. ##
  696. ## load file, write cache file, and return engine object.
  697. ## this method create code cache file automatically.
  698. ## cachefile name can be specified with properties[:cachename],
  699. ## or filname + 'cache' is used as default.
  700. ##
  701. def self.load_file(filename, properties={})
  702. cachename = properties[:cachename] || (filename + '.cache')
  703. properties[:filename] = filename
  704. if test(?f, cachename) && File.mtime(filename) <= File.mtime(cachename)
  705. engine = self.new(nil, properties)
  706. engine.src = File.read(cachename)
  707. else
  708. input = File.open(filename, 'rb') {|f| f.read }
  709. engine = self.new(input, properties)
  710. File.open(cachename, 'wb') do |f|
  711. f.flock(File::LOCK_EX)
  712. f.write(engine.src)
  713. f.flush()
  714. end
  715. end
  716. engine.src.untaint # ok?
  717. return engine
  718. end
  719. ##
  720. ## helper method to convert and evaluate input text with context object.
  721. ## context may be Binding, Hash, or Object.
  722. ##
  723. def process(input, context=nil, filename=nil)
  724. code = convert(input)
  725. filename ||= '(erubis)'
  726. if context.is_a?(Binding)
  727. return eval(code, context, filename)
  728. else
  729. context = Context.new(context) if context.is_a?(Hash)
  730. return context.instance_eval(code, filename)
  731. end
  732. end
  733. ##
  734. ## helper method evaluate Proc object with contect object.
  735. ## context may be Binding, Hash, or Object.
  736. ##
  737. def process_proc(proc_obj, context=nil, filename=nil)
  738. if context.is_a?(Binding)
  739. filename ||= '(erubis)'
  740. return eval(proc_obj, context, filename)
  741. else
  742. context = Context.new(context) if context.is_a?(Hash)
  743. return context.instance_eval(&proc_obj)
  744. end
  745. end
  746. end # end of class Engine
  747. ##
  748. ## (abstract) base engine class for Eruby, Eperl, Ejava, and so on.
  749. ## subclass must include generator.
  750. ##
  751. class Basic::Engine < Engine
  752. include Evaluator
  753. include Basic::Converter
  754. include Generator
  755. end
  756. class PI::Engine < Engine
  757. include Evaluator
  758. include PI::Converter
  759. include Generator
  760. end
  761. end
  762. #--end of require 'erubis/engine'
  763. #require 'erubis/generator'
  764. #require 'erubis/converter'
  765. #require 'erubis/evaluator'
  766. #require 'erubis/error'
  767. #require 'erubis/context'
  768. #--begin of require 'erubis/helper'
  769. ##
  770. ## $Release: 2.6.6 $
  771. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  772. ##
  773. module Erubis
  774. ##
  775. ## helper for xml
  776. ##
  777. module XmlHelper
  778. module_function
  779. ESCAPE_TABLE = {
  780. '&' => '&amp;',
  781. '<' => '&lt;',
  782. '>' => '&gt;',
  783. '"' => '&quot;',
  784. "'" => '&#039;',
  785. }
  786. def escape_xml(value)
  787. value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
  788. #value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
  789. end
  790. def escape_xml2(value)
  791. return value.to_s.gsub(/\&/,'&amp;').gsub(/</,'&lt;').gsub(/>/,'&gt;').gsub(/"/,'&quot;')
  792. end
  793. alias h escape_xml
  794. alias html_escape escape_xml
  795. def url_encode(str)
  796. return str.gsub(/[^-_.a-zA-Z0-9]+/) { |s|
  797. s.unpack('C*').collect { |i| "%%%02X" % i }.join
  798. }
  799. end
  800. alias u url_encode
  801. end
  802. end
  803. #--end of require 'erubis/helper'
  804. #--begin of require 'erubis/enhancer'
  805. ##
  806. ## $Release: 2.6.6 $
  807. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  808. ##
  809. module Erubis
  810. ##
  811. ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
  812. ##
  813. ## ex.
  814. ## class XmlEruby < Eruby
  815. ## include EscapeEnhancer
  816. ## end
  817. ##
  818. ## this is language-indenedent.
  819. ##
  820. module EscapeEnhancer
  821. def self.desc # :nodoc:
  822. "switch '<%= %>' to escaped and '<%== %>' to unescaped"
  823. end
  824. #--
  825. #def self.included(klass)
  826. # klass.class_eval <<-END
  827. # alias _add_expr_literal add_expr_literal
  828. # alias _add_expr_escaped add_expr_escaped
  829. # alias add_expr_literal _add_expr_escaped
  830. # alias add_expr_escaped _add_expr_literal
  831. # END
  832. #end
  833. #++
  834. def add_expr(src, code, indicator)
  835. case indicator
  836. when '='
  837. @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
  838. when '=='
  839. @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
  840. when '==='
  841. add_expr_debug(src, code)
  842. end
  843. end
  844. end
  845. #--
  846. ## (obsolete)
  847. #module FastEnhancer
  848. #end
  849. #++
  850. ##
  851. ## use $stdout instead of string
  852. ##
  853. ## this is only for Eruby.
  854. ##
  855. module StdoutEnhancer
  856. def self.desc # :nodoc:
  857. "use $stdout instead of array buffer or string buffer"
  858. end
  859. def add_preamble(src)
  860. src << "_buf = $stdout;"
  861. end
  862. def add_postamble(src)
  863. src << "\n''\n"
  864. end
  865. end
  866. ##
  867. ## use print statement instead of '_buf << ...'
  868. ##
  869. ## this is only for Eruby.
  870. ##
  871. module PrintOutEnhancer
  872. def self.desc # :nodoc:
  873. "use print statement instead of '_buf << ...'"
  874. end
  875. def add_preamble(src)
  876. end
  877. def add_text(src, text)
  878. src << " print '" << escape_text(text) << "';" unless text.empty?
  879. end
  880. def add_expr_literal(src, code)
  881. src << ' print((' << code << ').to_s);'
  882. end
  883. def add_expr_escaped(src, code)
  884. src << ' print ' << escaped_expr(code) << ';'
  885. end
  886. def add_postamble(src)
  887. src << "\n" unless src[-1] == ?\n
  888. end
  889. end
  890. ##
  891. ## enable print function
  892. ##
  893. ## Notice: use Eruby#evaluate() and don't use Eruby#result()
  894. ## to be enable print function.
  895. ##
  896. ## this is only for Eruby.
  897. ##
  898. module PrintEnabledEnhancer
  899. def self.desc # :nodoc:
  900. "enable to use print function in '<% %>'"
  901. end
  902. def add_preamble(src)
  903. src << "@_buf = "
  904. super
  905. end
  906. def print(*args)
  907. args.each do |arg|
  908. @_buf << arg.to_s
  909. end
  910. end
  911. def evaluate(context=nil)
  912. _src = @src
  913. if context.is_a?(Hash)
  914. context.each do |key, val| instance_variable_set("@#{key}", val) end
  915. elsif context
  916. context.instance_variables.each do |name|
  917. instance_variable_set(name, context.instance_variable_get(name))
  918. end
  919. end
  920. return instance_eval(_src, (@filename || '(erubis)'))
  921. end
  922. end
  923. ##
  924. ## return array instead of string
  925. ##
  926. ## this is only for Eruby.
  927. ##
  928. module ArrayEnhancer
  929. def self.desc # :nodoc:
  930. "return array instead of string"
  931. end
  932. def add_preamble(src)
  933. src << "_buf = [];"
  934. end
  935. def add_postamble(src)
  936. src << "\n" unless src[-1] == ?\n
  937. src << "_buf\n"
  938. end
  939. end
  940. ##
  941. ## use an Array object as buffer (included in Eruby by default)
  942. ##
  943. ## this is only for Eruby.
  944. ##
  945. module ArrayBufferEnhancer
  946. def self.desc # :nodoc:
  947. "use an Array object for buffering (included in Eruby class)"
  948. end
  949. def add_preamble(src)
  950. src << "_buf = [];"
  951. end
  952. def add_postamble(src)
  953. src << "\n" unless src[-1] == ?\n
  954. src << "_buf.join\n"
  955. end
  956. end
  957. ##
  958. ## use String class for buffering
  959. ##
  960. ## this is only for Eruby.
  961. ##
  962. module StringBufferEnhancer
  963. def self.desc # :nodoc:
  964. "use a String object for buffering"
  965. end
  966. def add_preamble(src)
  967. src << "_buf = '';"
  968. end
  969. def add_postamble(src)
  970. src << "\n" unless src[-1] == ?\n
  971. src << "_buf.to_s\n"
  972. end
  973. end
  974. ##
  975. ## use StringIO class for buffering
  976. ##
  977. ## this is only for Eruby.
  978. ##
  979. module StringIOEnhancer # :nodoc:
  980. def self.desc # :nodoc:
  981. "use a StringIO object for buffering"
  982. end
  983. def add_preamble(src)
  984. src << "_buf = StringIO.new;"
  985. end
  986. def add_postamble(src)
  987. src << "\n" unless src[-1] == ?\n
  988. src << "_buf.string\n"
  989. end
  990. end
  991. ##
  992. ## set buffer variable name to '_erbout' as well as '_buf'
  993. ##
  994. ## this is only for Eruby.
  995. ##
  996. module ErboutEnhancer
  997. def self.desc # :nodoc:
  998. "set '_erbout = _buf = \"\";' to be compatible with ERB."
  999. end
  1000. def add_preamble(src)
  1001. src << "_erbout = _buf = '';"
  1002. end
  1003. def add_postamble(src)
  1004. src << "\n" unless src[-1] == ?\n
  1005. src << "_buf.to_s\n"
  1006. end
  1007. end
  1008. ##
  1009. ## remove text and leave code, especially useful when debugging.
  1010. ##
  1011. ## ex.
  1012. ## $ erubis -s -E NoText file.eruby | more
  1013. ##
  1014. ## this is language independent.
  1015. ##
  1016. module NoTextEnhancer
  1017. def self.desc # :nodoc:
  1018. "remove text and leave code (useful when debugging)"
  1019. end
  1020. def add_text(src, text)
  1021. src << ("\n" * text.count("\n"))
  1022. if text[-1] != ?\n
  1023. text =~ /^(.*?)\z/
  1024. src << (' ' * $1.length)
  1025. end
  1026. end
  1027. end
  1028. ##
  1029. ## remove code and leave text, especially useful when validating HTML tags.
  1030. ##
  1031. ## ex.
  1032. ## $ erubis -s -E NoCode file.eruby | tidy -errors
  1033. ##
  1034. ## this is language independent.
  1035. ##
  1036. module NoCodeEnhancer
  1037. def self.desc # :nodoc:
  1038. "remove code and leave text (useful when validating HTML)"
  1039. end
  1040. def add_preamble(src)
  1041. end
  1042. def add_postamble(src)
  1043. end
  1044. def add_text(src, text)
  1045. src << text
  1046. end
  1047. def add_expr(src, code, indicator)
  1048. src << "\n" * code.count("\n")
  1049. end
  1050. def add_stmt(src, code)
  1051. src << "\n" * code.count("\n")
  1052. end
  1053. end
  1054. ##
  1055. ## get convert faster, but spaces around '<%...%>' are not trimmed.
  1056. ##
  1057. ## this is language-independent.
  1058. ##
  1059. module SimplifyEnhancer
  1060. def self.desc # :nodoc:
  1061. "get convert faster but leave spaces around '<% %>'"
  1062. end
  1063. #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
  1064. SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
  1065. def convert(input)
  1066. src = ""
  1067. add_preamble(src)
  1068. #regexp = pattern_regexp(@pattern)
  1069. pos = 0
  1070. input.scan(SIMPLE_REGEXP) do |indicator, code|
  1071. match = Regexp.last_match
  1072. index = match.begin(0)
  1073. text = input[pos, index - pos]
  1074. pos = match.end(0)
  1075. add_text(src, text)
  1076. if !indicator # <% %>
  1077. add_stmt(src, code)
  1078. elsif indicator[0] == ?\# # <%# %>
  1079. n = code.count("\n")
  1080. add_stmt(src, "\n" * n)
  1081. else # <%= %>
  1082. add_expr(src, code, indicator)
  1083. end
  1084. end
  1085. #rest = $' || input # ruby1.8
  1086. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1087. add_text(src, rest)
  1088. add_postamble(src)
  1089. return src
  1090. end
  1091. end
  1092. ##
  1093. ## enable to use other embedded expression pattern (default is '\[= =\]').
  1094. ##
  1095. ## notice! this is an experimental. spec may change in the future.
  1096. ##
  1097. ## ex.
  1098. ## input = <<END
  1099. ## <% for item in list %>
  1100. ## <%= item %> : <%== item %>
  1101. ## [= item =] : [== item =]
  1102. ## <% end %>
  1103. ## END
  1104. ##
  1105. ## class BiPatternEruby
  1106. ## include BiPatternEnhancer
  1107. ## end
  1108. ## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
  1109. ## list = ['<a>', 'b&b', '"c"']
  1110. ## print eruby.result(binding())
  1111. ##
  1112. ## ## output
  1113. ## <a> : &lt;a&gt;
  1114. ## <a> : &lt;a&gt;
  1115. ## b&b : b&amp;b
  1116. ## b&b : b&amp;b
  1117. ## "c" : &quot;c&quot;
  1118. ## "c" : &quot;c&quot;
  1119. ##
  1120. ## this is language independent.
  1121. ##
  1122. module BiPatternEnhancer
  1123. def self.desc # :nodoc:
  1124. "another embedded expression pattern (default '\[= =\]')."
  1125. end
  1126. def initialize(input, properties={})
  1127. self.bipattern = properties[:bipattern] # or '\$\{ \}'
  1128. super
  1129. end
  1130. ## when pat is nil then '\[= =\]' is used
  1131. def bipattern=(pat) # :nodoc:
  1132. @bipattern = pat || '\[= =\]'
  1133. pre, post = @bipattern.split()
  1134. @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
  1135. end
  1136. def add_text(src, text)
  1137. return unless text
  1138. m = nil
  1139. text.scan(@bipattern_regexp) do |txt, indicator, code|
  1140. m = Regexp.last_match
  1141. super(src, txt)
  1142. add_expr(src, code, '=' + indicator)
  1143. end
  1144. #rest = $' || text # ruby1.8
  1145. rest = m ? text[m.end(0)..-1] : text # ruby1.9
  1146. super(src, rest)
  1147. end
  1148. end
  1149. ##
  1150. ## regards lines starting with '%' as program code
  1151. ##
  1152. ## this is for compatibility to eruby and ERB.
  1153. ##
  1154. ## this is language-independent.
  1155. ##
  1156. module PercentLineEnhancer
  1157. def self.desc # :nodoc:
  1158. "regard lines starting with '%' as program code"
  1159. end
  1160. def add_text(src, text)
  1161. pos = 0
  1162. text2 = ''
  1163. text.scan(/^\%(.*?\r?\n)/) do
  1164. line = $1
  1165. match = Regexp.last_match
  1166. len = match.begin(0) - pos
  1167. str = text[pos, len]
  1168. pos = match.end(0)
  1169. if text2.empty?
  1170. text2 = str
  1171. else
  1172. text2 << str
  1173. end
  1174. if line[0] == ?%
  1175. text2 << line
  1176. else
  1177. super(src, text2)
  1178. text2 = ''
  1179. add_stmt(src, line)
  1180. end
  1181. end
  1182. #rest = pos == 0 ? text : $' # ruby1.8
  1183. rest = pos == 0 ? text : text[pos..-1] # ruby1.9
  1184. unless text2.empty?
  1185. text2 << rest if rest
  1186. rest = text2
  1187. end
  1188. super(src, rest)
  1189. end
  1190. end
  1191. ##
  1192. ## [experimental] allow header and footer in eRuby script
  1193. ##
  1194. ## ex.
  1195. ## ====================
  1196. ## ## without header and footer
  1197. ## $ cat ex1.eruby
  1198. ## <% def list_items(list) %>
  1199. ## <% for item in list %>
  1200. ## <li><%= item %></li>
  1201. ## <% end %>
  1202. ## <% end %>
  1203. ##
  1204. ## $ erubis -s ex1.eruby
  1205. ## _buf = []; def list_items(list)
  1206. ## ; for item in list
  1207. ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
  1208. ## '; end
  1209. ## ; end
  1210. ## ;
  1211. ## _buf.join
  1212. ##
  1213. ## ## with header and footer
  1214. ## $ cat ex2.eruby
  1215. ## <!--#header:
  1216. ## def list_items(list)
  1217. ## #-->
  1218. ## <% for item in list %>
  1219. ## <li><%= item %></li>
  1220. ## <% end %>
  1221. ## <!--#footer:
  1222. ## end
  1223. ## #-->
  1224. ##
  1225. ## $ erubis -s -c HeaderFooterEruby ex4.eruby
  1226. ##
  1227. ## def list_items(list)
  1228. ## _buf = []; _buf << '
  1229. ## '; for item in list
  1230. ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
  1231. ## '; end
  1232. ## ; _buf << '
  1233. ## ';
  1234. ## _buf.join
  1235. ## end
  1236. ##
  1237. ## ====================
  1238. ##
  1239. ## this is language-independent.
  1240. ##
  1241. module HeaderFooterEnhancer
  1242. def self.desc # :nodoc:
  1243. "allow header/footer in document (ex. '<!--#header: #-->')"
  1244. end
  1245. HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
  1246. def add_text(src, text)
  1247. m = nil
  1248. text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
  1249. m = Regexp.last_match
  1250. flag_trim = @trim && lspace && rspace
  1251. super(src, txt)
  1252. content = "#{lspace}#{content}#{rspace}" if flag_trim
  1253. super(src, lspace) if !flag_trim && lspace
  1254. instance_variable_set("@#{word}", content)
  1255. super(src, rspace) if !flag_trim && rspace
  1256. end
  1257. #rest = $' || text # ruby1.8
  1258. rest = m ? text[m.end(0)..-1] : text # ruby1.9
  1259. super(src, rest)
  1260. end
  1261. attr_accessor :header, :footer
  1262. def convert(input)
  1263. source = super
  1264. return @src = "#{@header}#{source}#{@footer}"
  1265. end
  1266. end
  1267. ##
  1268. ## delete indentation of HTML.
  1269. ##
  1270. ## this is language-independent.
  1271. ##
  1272. module DeleteIndentEnhancer
  1273. def self.desc # :nodoc:
  1274. "delete indentation of HTML."
  1275. end
  1276. def convert_input(src, input)
  1277. input = input.gsub(/^[ \t]+</, '<')
  1278. super(src, input)
  1279. end
  1280. end
  1281. ##
  1282. ## convert "<h1><%=title%></h1>" into "_buf << %Q`<h1>#{title}</h1>`"
  1283. ##
  1284. ## this is only for Eruby.
  1285. ##
  1286. module InterpolationEnhancer
  1287. def self.desc # :nodoc:
  1288. "convert '<p><%=text%></p>' into '_buf << %Q`<p>\#{text}</p>`'"
  1289. end
  1290. def convert_input(src, input)
  1291. pat = @pattern
  1292. regexp = pat.nil? || pat == '<% %>' ? Basic::Converter::DEFAULT_REGEXP : pattern_regexp(pat)
  1293. pos = 0
  1294. is_bol = true # is beginning of line
  1295. str = ''
  1296. input.scan(regexp) do |indicator, code, tailch, rspace|
  1297. match = Regexp.last_match()
  1298. len = match.begin(0) - pos
  1299. text = input[pos, len]
  1300. pos = match.end(0)
  1301. ch = indicator ? indicator[0] : nil
  1302. lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
  1303. is_bol = rspace ? true : false
  1304. _add_text_to_str(str, text)
  1305. ## * when '<%= %>', do nothing
  1306. ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
  1307. if ch == ?= # <%= %>
  1308. rspace = nil if tailch && !tailch.empty?
  1309. str << lspace if lspace
  1310. add_expr(str, code, indicator)
  1311. str << rspace if rspace
  1312. elsif ch == ?\# # <%# %>
  1313. n = code.count("\n") + (rspace ? 1 : 0)
  1314. if @trim && lspace && rspace
  1315. add_text(src, str)
  1316. str = ''
  1317. add_stmt(src, "\n" * n)
  1318. else
  1319. str << lspace if lspace
  1320. add_text(src, str)
  1321. str = ''
  1322. add_stmt(src, "\n" * n)
  1323. str << rspace if rspace
  1324. end
  1325. else # <% %>
  1326. if @trim && lspace && rspace
  1327. add_text(src, str)
  1328. str = ''
  1329. add_stmt(src, "#{lspace}#{code}#{rspace}")
  1330. else
  1331. str << lspace if lspace
  1332. add_text(src, str)
  1333. str = ''
  1334. add_stmt(src, code)
  1335. str << rspace if rspace
  1336. end
  1337. end
  1338. end
  1339. #rest = $' || input # ruby1.8
  1340. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1341. _add_text_to_str(str, rest)
  1342. add_text(src, str)
  1343. end
  1344. def add_text(src, text)
  1345. return if !text || text.empty?
  1346. #src << " _buf << %Q`" << text << "`;"
  1347. if text[-1] == ?\n
  1348. text[-1] = "\\n"
  1349. src << " _buf << %Q`" << text << "`\n"
  1350. else
  1351. src << " _buf << %Q`" << text << "`;"
  1352. end
  1353. end
  1354. def _add_text_to_str(str, text)
  1355. return if !text || text.empty?
  1356. text.gsub!(/[`\#\\]/, '\\\\\&')
  1357. str << text
  1358. end
  1359. def add_expr_escaped(str, code)
  1360. str << "\#{#{escaped_expr(code)}}"
  1361. end
  1362. def add_expr_literal(str, code)
  1363. str << "\#{#{code}}"
  1364. end
  1365. end
  1366. end
  1367. #--end of require 'erubis/enhancer'
  1368. #require 'erubis/tiny'
  1369. #--begin of require 'erubis/engine/eruby'
  1370. ##
  1371. ## $Release: 2.6.6 $
  1372. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1373. ##
  1374. #--already included require 'erubis/engine'
  1375. #--already included require 'erubis/enhancer'
  1376. module Erubis
  1377. ##
  1378. ## code generator for Ruby
  1379. ##
  1380. module RubyGenerator
  1381. include Generator
  1382. #include ArrayBufferEnhancer
  1383. include StringBufferEnhancer
  1384. def init_generator(properties={})
  1385. super
  1386. @escapefunc ||= "Erubis::XmlHelper.escape_xml"
  1387. end
  1388. def self.supported_properties() # :nodoc:
  1389. return []
  1390. end
  1391. def escape_text(text)
  1392. text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
  1393. end
  1394. def escaped_expr(code)
  1395. return "#{@escapefunc}(#{code})"
  1396. end
  1397. #--
  1398. #def add_preamble(src)
  1399. # src << "_buf = [];"
  1400. #end
  1401. #++
  1402. def add_text(src, text)
  1403. src << " _buf << '" << escape_text(text) << "';" unless text.empty?
  1404. end
  1405. def add_stmt(src, code)
  1406. #src << code << ';'
  1407. src << code
  1408. src << ';' unless code[-1] == ?\n
  1409. end
  1410. def add_expr_literal(src, code)
  1411. src << ' _buf << (' << code << ').to_s;'
  1412. end
  1413. def add_expr_escaped(src, code)
  1414. src << ' _buf << ' << escaped_expr(code) << ';'
  1415. end
  1416. def add_expr_debug(src, code)
  1417. code.strip!
  1418. s = (code.dump =~ /\A"(.*)"\z/) && $1
  1419. src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
  1420. end
  1421. #--
  1422. #def add_postamble(src)
  1423. # src << "\n_buf.join\n"
  1424. #end
  1425. #++
  1426. end
  1427. ##
  1428. ## engine for Ruby
  1429. ##
  1430. class Eruby < Basic::Engine
  1431. include RubyEvaluator
  1432. include RubyGenerator
  1433. end
  1434. ##
  1435. ## fast engine for Ruby
  1436. ##
  1437. class FastEruby < Eruby
  1438. include InterpolationEnhancer
  1439. end
  1440. ##
  1441. ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
  1442. ##
  1443. class EscapedEruby < Eruby
  1444. include EscapeEnhancer
  1445. end
  1446. ##
  1447. ## sanitize expression (<%= ... %>) by default
  1448. ##
  1449. ## this is equivalent to EscapedEruby and is prepared only for compatibility.
  1450. ##
  1451. class XmlEruby < Eruby
  1452. include EscapeEnhancer
  1453. end
  1454. class PI::Eruby < PI::Engine
  1455. include RubyEvaluator
  1456. include RubyGenerator
  1457. def init_converter(properties={})
  1458. @pi = 'rb'
  1459. super(properties)
  1460. end
  1461. end
  1462. end
  1463. #--end of require 'erubis/engine/eruby'
  1464. #require 'erubis/engine/enhanced' # enhanced eruby engines
  1465. #require 'erubis/engine/optimized' # generates optimized ruby code
  1466. #require 'erubis/engine/ephp'
  1467. #require 'erubis/engine/ec'
  1468. #require 'erubis/engine/ejava'
  1469. #require 'erubis/engine/escheme'
  1470. #require 'erubis/engine/eperl'
  1471. #require 'erubis/engine/ejavascript'
  1472. #--begin of require 'erubis/local-setting'
  1473. ##
  1474. ## $Release: 2.6.6 $
  1475. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1476. ##
  1477. ##
  1478. ## you can add site-local settings here.
  1479. ## this files is required by erubis.rb
  1480. ##
  1481. #--end of require 'erubis/local-setting'
  1482. #--end of require 'erubis'
  1483. #--begin of require 'erubis/tiny'
  1484. ##
  1485. ## $Release: 2.6.6 $
  1486. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1487. ##
  1488. module Erubis
  1489. ##
  1490. ## tiny and the simplest implementation of eRuby
  1491. ##
  1492. ## ex.
  1493. ## eruby = TinyEruby.new(File.read('example.rhtml'))
  1494. ## print eruby.src # print ruby code
  1495. ## print eruby.result(binding()) # eval ruby code with Binding object
  1496. ## print eruby.evalute(context) # eval ruby code with context object
  1497. ##
  1498. class TinyEruby
  1499. def initialize(input=nil)
  1500. @src = convert(input) if input
  1501. end
  1502. attr_reader :src
  1503. EMBEDDED_PATTERN = /<%(=+|\#)?(.*?)-?%>/m
  1504. def convert(input)
  1505. src = "_buf = '';" # preamble
  1506. pos = 0
  1507. input.scan(EMBEDDED_PATTERN) do |indicator, code|
  1508. m = Regexp.last_match
  1509. text = input[pos...m.begin(0)]
  1510. pos = m.end(0)
  1511. #src << " _buf << '" << escape_text(text) << "';"
  1512. text.gsub!(/['\\]/, '\\\\\&')
  1513. src << " _buf << '" << text << "';" unless text.empty?
  1514. if !indicator # <% %>
  1515. src << code << ";"
  1516. elsif indicator == '#' # <%# %>
  1517. src << ("\n" * code.count("\n"))
  1518. else # <%= %>
  1519. src << " _buf << (" << code << ").to_s;"
  1520. end
  1521. end
  1522. #rest = $' || input # ruby1.8
  1523. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1524. #src << " _buf << '" << escape_text(rest) << "';"
  1525. rest.gsub!(/['\\]/, '\\\\\&')
  1526. src << " _buf << '" << rest << "';" unless rest.empty?
  1527. src << "\n_buf.to_s\n" # postamble
  1528. return src
  1529. end
  1530. #def escape_text(text)
  1531. # return text.gsub!(/['\\]/, '\\\\\&') || text
  1532. #end
  1533. def result(_binding=TOPLEVEL_BINDING)
  1534. eval @src, _binding
  1535. end
  1536. def evaluate(_context=Object.new)
  1537. if _context.is_a?(Hash)
  1538. _obj = Object.new
  1539. _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
  1540. _context = _obj
  1541. end
  1542. _context.instance_eval @src
  1543. end
  1544. end
  1545. module PI
  1546. end
  1547. class PI::TinyEruby
  1548. def initialize(input=nil, options={})
  1549. @escape = options[:escape] || 'Erubis::XmlHelper.escape_xml'
  1550. @src = convert(input) if input
  1551. end
  1552. attr_reader :src
  1553. EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|@(!+)?\{(.*?)\}@/m
  1554. def convert(input)
  1555. src = "_buf = '';" # preamble
  1556. pos = 0
  1557. input.scan(EMBEDDED_PATTERN) do |lspace, stmt, rspace, indicator, expr|
  1558. match = Regexp.last_match
  1559. len = match.begin(0) - pos
  1560. text = input[pos, len]
  1561. pos = match.end(0)
  1562. #src << " _buf << '" << escape_text(text) << "';"
  1563. text.gsub!(/['\\]/, '\\\\\&')
  1564. src << " _buf << '" << text << "';" unless text.empty?
  1565. if stmt # <?rb ... ?>
  1566. if lspace && rspace
  1567. src << "#{lspace}#{stmt}#{rspace}"
  1568. else
  1569. src << " _buf << '" << lspace << "';" if lspace
  1570. src << stmt << ";"
  1571. src << " _buf << '" << rspace << "';" if rspace
  1572. end
  1573. else # ${...}, $!{...}
  1574. if !indicator
  1575. src << " _buf << " << @escape << "(" << expr << ");"
  1576. elsif indicator == '!'
  1577. src << " _buf << (" << expr << ").to_s;"
  1578. end
  1579. end
  1580. end
  1581. #rest = $' || input # ruby1.8
  1582. rest = pos == 0 ? input : input[pos..-1] # ruby1.9
  1583. #src << " _buf << '" << escape_text(rest) << "';"
  1584. rest.gsub!(/['\\]/, '\\\\\&')
  1585. src << " _buf << '" << rest << "';" unless rest.empty?
  1586. src << "\n_buf.to_s\n" # postamble
  1587. return src
  1588. end
  1589. #def escape_text(text)
  1590. # return text.gsub!(/['\\]/, '\\\\\&') || text
  1591. #end
  1592. def result(_binding=TOPLEVEL_BINDING)
  1593. eval @src, _binding
  1594. end
  1595. def evaluate(_context=Object.new)
  1596. if _context.is_a?(Hash)
  1597. _obj = Object.new
  1598. _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
  1599. _context = _obj
  1600. end
  1601. _context.instance_eval @src
  1602. end
  1603. end
  1604. end
  1605. #--end of require 'erubis/tiny'
  1606. #--begin of require 'erubis/engine/enhanced'
  1607. ##
  1608. ## $Release: 2.6.6 $
  1609. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1610. ##
  1611. #--already included require 'erubis/enhancer'
  1612. #--already included require 'erubis/engine/eruby'
  1613. module Erubis
  1614. #--
  1615. ## moved to engine/ruby.rb
  1616. #class EscapedEruby < Eruby
  1617. # include EscapeEnhancer
  1618. #end
  1619. #++
  1620. #--
  1621. ### (obsolete)
  1622. #class FastEruby < Eruby
  1623. # include FastEnhancer
  1624. #end
  1625. #++
  1626. class StdoutEruby < Eruby
  1627. include StdoutEnhancer
  1628. end
  1629. class PrintOutEruby < Eruby
  1630. include PrintOutEnhancer
  1631. end
  1632. class PrintEnabledEruby < Eruby
  1633. include PrintEnabledEnhancer
  1634. end
  1635. class ArrayEruby < Eruby
  1636. include ArrayEnhancer
  1637. end
  1638. class ArrayBufferEruby < Eruby
  1639. include ArrayBufferEnhancer
  1640. end
  1641. class StringBufferEruby < Eruby
  1642. include StringBufferEnhancer
  1643. end
  1644. class StringIOEruby < Eruby
  1645. include StringIOEnhancer
  1646. end
  1647. class ErboutEruby < Eruby
  1648. include ErboutEnhancer
  1649. end
  1650. class NoTextEruby < Eruby
  1651. include NoTextEnhancer
  1652. end
  1653. class NoCodeEruby < Eruby
  1654. include NoCodeEnhancer
  1655. end
  1656. class SimplifiedEruby < Eruby
  1657. include SimplifyEnhancer
  1658. end
  1659. class StdoutSimplifiedEruby < Eruby
  1660. include StdoutEnhancer
  1661. include SimplifyEnhancer
  1662. end
  1663. class PrintOutSimplifiedEruby < Eruby
  1664. include PrintOutEnhancer
  1665. include SimplifyEnhancer
  1666. end
  1667. class BiPatternEruby < Eruby
  1668. include BiPatternEnhancer
  1669. end
  1670. class PercentLineEruby < Eruby
  1671. include PercentLineEnhancer
  1672. end
  1673. class HeaderFooterEruby < Eruby
  1674. include HeaderFooterEnhancer
  1675. end
  1676. class DeleteIndentEruby < Eruby
  1677. include DeleteIndentEnhancer
  1678. end
  1679. class InterpolationEruby < Eruby
  1680. include InterpolationEnhancer
  1681. end
  1682. end
  1683. #--end of require 'erubis/engine/enhanced'
  1684. #--begin of require 'erubis/engine/optimized'
  1685. ##
  1686. ## $Release: 2.6.6 $
  1687. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1688. ##
  1689. #--already included require 'erubis/engine/eruby'
  1690. module Erubis
  1691. module OptimizedGenerator
  1692. include Generator
  1693. def self.supported_properties() # :nodoc:
  1694. return []
  1695. end
  1696. def init_generator(properties={})
  1697. super
  1698. @escapefunc ||= "Erubis::XmlHelper.escape_xml"
  1699. @initialized = false
  1700. @prev_is_expr = false
  1701. end
  1702. protected
  1703. def escape_text(text)
  1704. text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
  1705. end
  1706. def escaped_expr(code)
  1707. @escapefunc ||= 'Erubis::XmlHelper.escape_xml'
  1708. return "#{@escapefunc}(#{code})"
  1709. end
  1710. def switch_to_expr(src)
  1711. return if @prev_is_expr
  1712. @prev_is_expr = true
  1713. src << ' _buf'
  1714. end
  1715. def switch_to_stmt(src)
  1716. return unless @prev_is_expr
  1717. @prev_is_expr = false
  1718. src << ';'
  1719. end
  1720. def add_preamble(src)
  1721. #@initialized = false
  1722. #@prev_is_expr = false
  1723. end
  1724. def add_text(src, text)
  1725. return if text.empty?
  1726. if @initialized
  1727. switch_to_expr(src)
  1728. src << " << '" << escape_text(text) << "'"
  1729. else
  1730. src << "_buf = '" << escape_text(text) << "';"
  1731. @initialized = true
  1732. end
  1733. end
  1734. def add_stmt(src, code)
  1735. switch_to_stmt(src) if @initialized
  1736. #super
  1737. src << code
  1738. src << ';' unless code[-1] == ?\n
  1739. end
  1740. def add_expr_literal(src, code)
  1741. unless @initialized; src << "_buf = ''"; @initialized = true; end
  1742. switch_to_expr(src)
  1743. src << " << (" << code << ").to_s"
  1744. end
  1745. def add_expr_escaped(src, code)
  1746. unless @initialized; src << "_buf = ''"; @initialized = true; end
  1747. switch_to_expr(src)
  1748. src << " << " << escaped_expr(code)
  1749. end
  1750. def add_expr_debug(src, code)
  1751. code.strip!
  1752. s = (code.dump =~ /\A"(.*)"\z/) && $1
  1753. src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
  1754. end
  1755. def add_postamble(src)
  1756. #super if @initialized
  1757. src << "\n_buf\n" if @initialized
  1758. end
  1759. end # end of class OptimizedEruby
  1760. ##
  1761. ## Eruby class which generates optimized ruby code
  1762. ##
  1763. class OptimizedEruby < Basic::Engine # Eruby
  1764. include RubyEvaluator
  1765. include OptimizedGenerator
  1766. def init_converter(properties={})
  1767. @pi = 'rb'
  1768. super(properties)
  1769. end
  1770. end
  1771. ##
  1772. ## XmlEruby class which generates optimized ruby code
  1773. ##
  1774. class OptimizedXmlEruby < OptimizedEruby
  1775. include EscapeEnhancer
  1776. def add_expr_debug(src, code)
  1777. switch_to_stmt(src) if indicator == '===' && !@initialized
  1778. super
  1779. end
  1780. end # end of class OptimizedXmlEruby
  1781. end
  1782. #--end of require 'erubis/engine/optimized'
  1783. #--already included require 'erubis/engine/eruby'
  1784. #--begin of require 'erubis/engine/ephp'
  1785. ##
  1786. ## $Release: 2.6.6 $
  1787. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1788. ##
  1789. #--already included require 'erubis/engine'
  1790. #--already included require 'erubis/enhancer'
  1791. module Erubis
  1792. module PhpGenerator
  1793. include Generator
  1794. def self.supported_properties() # :nodoc:
  1795. return []
  1796. end
  1797. def init_generator(properties={})
  1798. super
  1799. @escapefunc ||= 'htmlspecialchars'
  1800. end
  1801. def add_preamble(src)
  1802. # empty
  1803. end
  1804. def escape_text(text)
  1805. return text.gsub!(/<\?xml\b/, '<<?php ?>?xml') || text
  1806. end
  1807. def add_text(src, text)
  1808. src << escape_text(text)
  1809. end
  1810. def add_expr_literal(src, code)
  1811. code.strip!
  1812. src << "<?php echo #{code}; ?>"
  1813. end
  1814. def add_expr_escaped(src, code)
  1815. add_expr_literal(src, escaped_expr(code))
  1816. end
  1817. def add_expr_debug(src, code)
  1818. code.strip!
  1819. s = code.gsub(/\'/, "\\'")
  1820. src << "<?php error_log('*** debug: #{s}='.(#{code}), 0); ?>"
  1821. end
  1822. def add_stmt(src, code)
  1823. src << "<?php"
  1824. src << " " if code[0] != ?\ #
  1825. if code[-1] == ?\n
  1826. code.chomp!
  1827. src << code << "?>\n"
  1828. else
  1829. src << code << "?>"
  1830. end
  1831. end
  1832. def add_postamble(src)
  1833. # empty
  1834. end
  1835. end
  1836. ##
  1837. ## engine for PHP
  1838. ##
  1839. class Ephp < Basic::Engine
  1840. include PhpGenerator
  1841. end
  1842. class EscapedEphp < Ephp
  1843. include EscapeEnhancer
  1844. end
  1845. #class XmlEphp < Ephp
  1846. # include EscapeEnhancer
  1847. #end
  1848. class PI::Ephp < PI::Engine
  1849. include PhpGenerator
  1850. def init_converter(properties={})
  1851. @pi = 'php'
  1852. super(properties)
  1853. end
  1854. end
  1855. end
  1856. #--end of require 'erubis/engine/ephp'
  1857. #--begin of require 'erubis/engine/ec'
  1858. ##
  1859. ## $Release: 2.6.6 $
  1860. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1861. ##
  1862. #--already included require 'erubis/engine'
  1863. #--already included require 'erubis/enhancer'
  1864. module Erubis
  1865. module CGenerator
  1866. include Generator
  1867. def self.supported_properties() # :nodoc:
  1868. return [
  1869. [:indent, '', "indent spaces (ex. ' ')"],
  1870. [:out, 'stdout', "output file pointer name"],
  1871. ]
  1872. end
  1873. def init_generator(properties={})
  1874. super
  1875. @escapefunc ||= "escape"
  1876. @indent = properties[:indent] || ''
  1877. @out = properties[:out] || 'stdout'
  1878. end
  1879. def add_preamble(src)
  1880. src << "#line 1 \"#{self.filename}\"\n" if self.filename
  1881. end
  1882. def escape_text(text)
  1883. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  1884. text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] }
  1885. return text
  1886. end
  1887. def escaped_expr(code)
  1888. return "#{@escapefunc}(#{code.strip}, #{@out})"
  1889. end
  1890. def add_text(src, text)
  1891. return if text.empty?
  1892. src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
  1893. src << "fputs("
  1894. i = 0
  1895. text.each_line do |line|
  1896. src << "\n" << @indent << ' ' if i > 0
  1897. i += 1
  1898. src << '"' << escape_text(line) << '"'
  1899. end
  1900. src << ", #{@out});" #<< (text[-1] == ?\n ? "\n" : "")
  1901. src << "\n" if text[-1] == ?\n
  1902. end
  1903. def add_stmt(src, code)
  1904. src << code
  1905. end
  1906. def add_expr_literal(src, code)
  1907. src << @indent if src.empty? || src[-1] == ?\n
  1908. src << " fprintf(#{@out}, " << code.strip << ');'
  1909. end
  1910. def add_expr_escaped(src, code)
  1911. src << @indent if src.empty? || src[-1] == ?\n
  1912. src << ' ' << escaped_expr(code) << ';'
  1913. end
  1914. def add_expr_debug(src, code)
  1915. code.strip!
  1916. s = nil
  1917. if code =~ /\A\".*?\"\s*,\s*(.*)/
  1918. s = $1.gsub(/[%"]/, '\\\1') + '='
  1919. end
  1920. src << @indent if src.empty? || src[-1] == ?\n
  1921. src << " fprintf(stderr, \"*** debug: #{s}\" #{code});"
  1922. end
  1923. def add_postamble(src)
  1924. # empty
  1925. end
  1926. end
  1927. ##
  1928. ## engine for C
  1929. ##
  1930. class Ec < Basic::Engine
  1931. include CGenerator
  1932. end
  1933. class EscapedEc < Ec
  1934. include EscapeEnhancer
  1935. end
  1936. #class XmlEc < Ec
  1937. # include EscapeEnhancer
  1938. #end
  1939. class PI::Ec < PI::Engine
  1940. include CGenerator
  1941. def init_converter(properties={})
  1942. @pi = 'c'
  1943. super(properties)
  1944. end
  1945. end
  1946. end
  1947. #--end of require 'erubis/engine/ec'
  1948. #--begin of require 'erubis/engine/ejava'
  1949. ##
  1950. ## $Release: 2.6.6 $
  1951. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  1952. ##
  1953. #--already included require 'erubis/engine'
  1954. #--already included require 'erubis/enhancer'
  1955. module Erubis
  1956. module JavaGenerator
  1957. include Generator
  1958. def self.supported_properties() # :nodoc:
  1959. return [
  1960. [:indent, '', "indent spaces (ex. ' ')"],
  1961. [:buf, '_buf', "output buffer name"],
  1962. [:bufclass, 'StringBuffer', "output buffer class (ex. 'StringBuilder')"],
  1963. ]
  1964. end
  1965. def init_generator(properties={})
  1966. super
  1967. @escapefunc ||= 'escape'
  1968. @indent = properties[:indent] || ''
  1969. @buf = properties[:buf] || '_buf'
  1970. @bufclass = properties[:bufclass] || 'StringBuffer'
  1971. end
  1972. def add_preamble(src)
  1973. src << "#{@indent}#{@bufclass} #{@buf} = new #{@bufclass}();"
  1974. end
  1975. def escape_text(text)
  1976. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  1977. return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
  1978. end
  1979. def add_text(src, text)
  1980. return if text.empty?
  1981. src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
  1982. src << @buf << ".append("
  1983. i = 0
  1984. text.each_line do |line|
  1985. src << "\n" << @indent << ' + ' if i > 0
  1986. i += 1
  1987. src << '"' << escape_text(line) << '"'
  1988. end
  1989. src << ");" << (text[-1] == ?\n ? "\n" : "")
  1990. end
  1991. def add_stmt(src, code)
  1992. src << code
  1993. end
  1994. def add_expr_literal(src, code)
  1995. src << @indent if src.empty? || src[-1] == ?\n
  1996. code.strip!
  1997. src << " #{@buf}.append(#{code});"
  1998. end
  1999. def add_expr_escaped(src, code)
  2000. add_expr_literal(src, escaped_expr(code))
  2001. end
  2002. def add_expr_debug(src, code)
  2003. code.strip!
  2004. src << @indent if src.empty? || src[-1] == ?\n
  2005. src << " System.err.println(\"*** debug: #{code}=\"+(#{code}));"
  2006. end
  2007. def add_postamble(src)
  2008. src << "\n" if src[-1] == ?;
  2009. src << @indent << "return " << @buf << ".toString();\n"
  2010. #src << @indent << "System.out.print(" << @buf << ".toString());\n"
  2011. end
  2012. end
  2013. ##
  2014. ## engine for Java
  2015. ##
  2016. class Ejava < Basic::Engine
  2017. include JavaGenerator
  2018. end
  2019. class EscapedEjava < Ejava
  2020. include EscapeEnhancer
  2021. end
  2022. #class XmlEjava < Ejava
  2023. # include EscapeEnhancer
  2024. #end
  2025. class PI::Ejava < PI::Engine
  2026. include JavaGenerator
  2027. def init_converter(properties={})
  2028. @pi = 'java'
  2029. super(properties)
  2030. end
  2031. end
  2032. end
  2033. #--end of require 'erubis/engine/ejava'
  2034. #--begin of require 'erubis/engine/escheme'
  2035. ##
  2036. ## $Release: 2.6.6 $
  2037. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  2038. ##
  2039. #--already included require 'erubis/engine'
  2040. #--already included require 'erubis/enhancer'
  2041. module Erubis
  2042. module SchemeGenerator
  2043. include Generator
  2044. def self.supported_properties() # :nodoc:
  2045. return [
  2046. [:func, '_add', "function name (ex. 'display')"],
  2047. ]
  2048. end
  2049. def init_generator(properties={})
  2050. super
  2051. @escapefunc ||= 'escape'
  2052. @func = properties[:func] || '_add' # or 'display'
  2053. end
  2054. def add_preamble(src)
  2055. return unless @func == '_add'
  2056. src << "(let ((_buf '())) " + \
  2057. "(define (_add x) (set! _buf (cons x _buf))) "
  2058. #src << "(let* ((_buf '())" + \
  2059. # " (_add (lambda (x) (set! _buf (cons x _buf))))) "
  2060. end
  2061. def escape_text(text)
  2062. @table_ ||= { '"'=>'\\"', '\\'=>'\\\\' }
  2063. text.gsub!(/["\\]/) { |m| @table_[m] }
  2064. return text
  2065. end
  2066. def escaped_expr(code)
  2067. code.strip!
  2068. return "(#{@escapefunc} #{code})"
  2069. end
  2070. def add_text(src, text)
  2071. return if text.empty?
  2072. t = escape_text(text)
  2073. if t[-1] == ?\n
  2074. t[-1, 1] = ''
  2075. src << "(#{@func} \"" << t << "\\n\")\n"
  2076. else
  2077. src << "(#{@func} \"" << t << '")'
  2078. end
  2079. end
  2080. def add_stmt(src, code)
  2081. src << code
  2082. end
  2083. def add_expr_literal(src, code)
  2084. code.strip!
  2085. src << "(#{@func} #{code})"
  2086. end
  2087. def add_expr_escaped(src, code)
  2088. add_expr_literal(src, escaped_expr(code))
  2089. end
  2090. def add_expr_debug(src, code)
  2091. s = (code.strip! || code).gsub(/\"/, '\\"')
  2092. src << "(display \"*** debug: #{s}=\")(display #{code.strip})(display \"\\n\")"
  2093. end
  2094. def add_postamble(src)
  2095. return unless @func == '_add'
  2096. src << "\n" unless src[-1] == ?\n
  2097. src << " (reverse _buf))\n"
  2098. end
  2099. end
  2100. ##
  2101. ## engine for Scheme
  2102. ##
  2103. class Escheme < Basic::Engine
  2104. include SchemeGenerator
  2105. end
  2106. class EscapedEscheme < Escheme
  2107. include EscapeEnhancer
  2108. end
  2109. #class XmlEscheme < Escheme
  2110. # include EscapeEnhancer
  2111. #end
  2112. class PI::Escheme < PI::Engine
  2113. include SchemeGenerator
  2114. def init_converter(properties={})
  2115. @pi = 'scheme'
  2116. super(properties)
  2117. end
  2118. end
  2119. end
  2120. #--end of require 'erubis/engine/escheme'
  2121. #--begin of require 'erubis/engine/eperl'
  2122. ##
  2123. ## $Release: 2.6.6 $
  2124. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  2125. ##
  2126. #--already included require 'erubis/engine'
  2127. #--already included require 'erubis/enhancer'
  2128. module Erubis
  2129. module PerlGenerator
  2130. include Generator
  2131. def self.supported_properties() # :nodoc:
  2132. return [
  2133. [:func, 'print', "function name"],
  2134. ]
  2135. end
  2136. def init_generator(properties={})
  2137. super
  2138. @escapefunc ||= 'encode_entities'
  2139. @func = properties[:func] || 'print'
  2140. end
  2141. def add_preamble(src)
  2142. src << "use HTML::Entities; ";
  2143. end
  2144. def escape_text(text)
  2145. return text.gsub!(/['\\]/, '\\\\\&') || text
  2146. end
  2147. def add_text(src, text)
  2148. src << @func << "('" << escape_text(text) << "'); " unless text.empty?
  2149. end
  2150. def add_expr_literal(src, code)
  2151. code.strip!
  2152. src << @func << "(" << code << "); "
  2153. end
  2154. def add_expr_escaped(src, code)
  2155. add_expr_literal(src, escaped_expr(code))
  2156. end
  2157. def add_expr_debug(src, code)
  2158. code.strip!
  2159. s = code.gsub(/\'/, "\\'")
  2160. src << @func << "('*** debug: #{code}=', #{code}, \"\\n\");"
  2161. end
  2162. def add_stmt(src, code)
  2163. src << code
  2164. end
  2165. def add_postamble(src)
  2166. src << "\n" unless src[-1] == ?\n
  2167. end
  2168. end
  2169. ##
  2170. ## engine for Perl
  2171. ##
  2172. class Eperl < Basic::Engine
  2173. include PerlGenerator
  2174. end
  2175. class EscapedEperl < Eperl
  2176. include EscapeEnhancer
  2177. end
  2178. #class XmlEperl < Eperl
  2179. # include EscapeEnhancer
  2180. #end
  2181. class PI::Eperl < PI::Engine
  2182. include PerlGenerator
  2183. def init_converter(properties={})
  2184. @pi = 'perl'
  2185. super(properties)
  2186. end
  2187. end
  2188. end
  2189. #--end of require 'erubis/engine/eperl'
  2190. #--begin of require 'erubis/engine/ejavascript'
  2191. ##
  2192. ## $Release: 2.6.6 $
  2193. ## copyright(c) 2006-2010 kuwata-lab.com all rights reserved.
  2194. ##
  2195. #--already included require 'erubis/engine'
  2196. #--already included require 'erubis/enhancer'
  2197. module Erubis
  2198. module JavascriptGenerator
  2199. include Generator
  2200. def self.supported_properties() # :nodoc:
  2201. list = []
  2202. #list << [:indent, '', "indent spaces (ex. ' ')"]
  2203. #list << [:buf, '_buf', "output buffer name"]
  2204. list << [:docwrite, true, "use 'document.write()' when true"]
  2205. return list
  2206. end
  2207. def init_generator(properties={})
  2208. super
  2209. @escapefunc ||= 'escape'
  2210. @indent = properties[:indent] || ''
  2211. @buf = properties[:out] || '_buf'
  2212. @docwrite = properties[:docwrite] != false # '!= false' will be removed in the next release
  2213. end
  2214. def add_preamble(src)
  2215. src << "#{@indent}var #{@buf} = [];"
  2216. end
  2217. def escape_text(text)
  2218. @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n\\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
  2219. return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
  2220. end
  2221. def add_indent(src, indent)
  2222. src << (src.empty? || src[-1] == ?\n ? indent : ' ')
  2223. end
  2224. def add_text(src, text)
  2225. return if text.empty?
  2226. add_indent(src, @indent)
  2227. src << @buf << '.push("'
  2228. s = escape_text(text)
  2229. if s[-1] == ?\n
  2230. s[-2, 2] = ''
  2231. src << s << "\");\n"
  2232. else
  2233. src << s << "\");"
  2234. end
  2235. end
  2236. def add_stmt(src, code)
  2237. src << code
  2238. end
  2239. def add_expr_literal(src, code)
  2240. add_indent(src, @indent)
  2241. code.strip!
  2242. src << "#{@buf}.push(#{code});"
  2243. end
  2244. def add_expr_escaped(src, code)
  2245. add_expr_literal(src, escaped_expr(code))
  2246. end
  2247. def add_expr_debug(src, code)
  2248. add_indent(src, @indent)
  2249. code.strip!
  2250. src << "alert(\"*** debug: #{code}=\"+(#{code}));"
  2251. end
  2252. def add_postamble(src)
  2253. src << "\n" if src[-1] == ?;
  2254. if @docwrite
  2255. src << @indent << 'document.write(' << @buf << ".join(\"\"));\n"
  2256. else
  2257. src << @indent << @buf << ".join(\"\");\n"
  2258. end
  2259. end
  2260. end
  2261. ##
  2262. ## engine for JavaScript
  2263. ##
  2264. class Ejavascript < Basic::Engine
  2265. include JavascriptGenerator
  2266. end
  2267. class EscapedEjavascript < Ejavascript
  2268. include EscapeEnhancer
  2269. end
  2270. #class XmlEjavascript < Ejavascript
  2271. # include EscapeEnhancer
  2272. #end
  2273. class PI::Ejavascript < PI::Engine
  2274. include JavascriptGenerator
  2275. def init_converter(properties={})
  2276. @pi = 'js'
  2277. super(properties)
  2278. end
  2279. end
  2280. end
  2281. #--end of require 'erubis/engine/ejavascript'
  2282. module Erubis
  2283. Ejs = Ejavascript
  2284. EscapedEjs = EscapedEjavascript
  2285. class CommandOptionError < ErubisError
  2286. end
  2287. ##
  2288. ## main class of command
  2289. ##
  2290. ## ex.
  2291. ## Main.main(ARGV)
  2292. ##
  2293. class Main
  2294. def self.main(argv=ARGV)
  2295. status = 0
  2296. begin
  2297. Main.new.execute(ARGV)
  2298. rescue CommandOptionError => ex
  2299. $stderr.puts ex.message
  2300. status = 1
  2301. end
  2302. exit(status)
  2303. end
  2304. def initialize
  2305. @single_options = "hvxztTSbeBXNUC"
  2306. @arg_options = "pcrfKIlaE" #C
  2307. @option_names = {
  2308. 'h' => :help,
  2309. 'v' => :version,
  2310. 'x' => :source,
  2311. 'z' => :syntax,
  2312. 'T' => :unexpand,
  2313. 't' => :untabify, # obsolete
  2314. 'S' => :intern,
  2315. 'b' => :bodyonly,
  2316. 'B' => :binding,
  2317. 'p' => :pattern,
  2318. 'c' => :context,
  2319. #'C' => :class,
  2320. 'e' => :escape,
  2321. 'r' => :requires,
  2322. 'f' => :datafiles,
  2323. 'K' => :kanji,
  2324. 'I' => :includes,
  2325. 'l' => :lang,
  2326. 'a' => :action,
  2327. 'E' => :enhancers,
  2328. 'X' => :notext,
  2329. 'N' => :linenum,
  2330. 'U' => :unique,
  2331. 'C' => :compact,
  2332. }
  2333. assert unless @single_options.length + @arg_options.length == @option_names.length
  2334. (@single_options + @arg_options).each_byte do |ch|
  2335. assert unless @option_names.key?(ch.chr)
  2336. end
  2337. end
  2338. def execute(argv=ARGV)
  2339. ## parse command-line options
  2340. options, properties = parse_argv(argv, @single_options, @arg_options)
  2341. filenames = argv
  2342. options['h'] = true if properties[:help]
  2343. opts = Object.new
  2344. arr = @option_names.collect {|ch, name| "def #{name}; @#{name}; end\n" }
  2345. opts.instance_eval arr.join
  2346. options.each do |ch, val|
  2347. name = @option_names[ch]
  2348. opts.instance_variable_set("@#{name}", val)
  2349. end
  2350. ## help, version, enhancer list
  2351. if opts.help || opts.version
  2352. puts version() if opts.version
  2353. puts usage() if opts.help
  2354. puts show_properties() if opts.help
  2355. puts show_enhancers() if opts.help
  2356. return
  2357. end
  2358. ## include path
  2359. opts.includes.split(/,/).each do |path|
  2360. $: << path
  2361. end if opts.includes
  2362. ## require library
  2363. opts.requires.split(/,/).each do |library|
  2364. require library
  2365. end if opts.requires
  2366. ## action
  2367. action = opts.action
  2368. action ||= 'syntax' if opts.syntax
  2369. action ||= 'convert' if opts.source || opts.notext
  2370. ## lang
  2371. lang = opts.lang || 'ruby'
  2372. action ||= 'convert' if opts.lang
  2373. ## class name of Eruby
  2374. #classname = opts.class
  2375. classname = nil
  2376. klass = get_classobj(classname, lang, properties[:pi])
  2377. ## kanji code
  2378. $KCODE = opts.kanji if opts.kanji
  2379. ## read context values from yaml file
  2380. datafiles = opts.datafiles
  2381. context = load_datafiles(datafiles, opts)
  2382. ## parse context data
  2383. if opts.context
  2384. context = parse_context_data(opts.context, opts)
  2385. end
  2386. ## properties for engine
  2387. properties[:escape] = true if opts.escape && !properties.key?(:escape)
  2388. properties[:pattern] = opts.pattern if opts.pattern
  2389. #properties[:trim] = false if opts.notrim
  2390. properties[:preamble] = properties[:postamble] = false if opts.bodyonly
  2391. properties[:pi] = nil if properties[:pi] == true
  2392. ## create engine and extend enhancers
  2393. engine = klass.new(nil, properties)
  2394. enhancers = get_enhancers(opts.enhancers)
  2395. #enhancers.push(Erubis::EscapeEnhancer) if opts.escape
  2396. enhancers.each do |enhancer|
  2397. engine.extend(enhancer)
  2398. engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
  2399. end
  2400. ## no-text
  2401. engine.extend(Erubis::NoTextEnhancer) if opts.notext
  2402. ## convert and execute
  2403. val = nil
  2404. msg = "Syntax OK\n"
  2405. if filenames && !filenames.empty?
  2406. filenames.each do |filename|
  2407. File.file?(filename) or
  2408. raise CommandOptionError.new("#{filename}: file not found.")
  2409. engine.filename = filename
  2410. engine.convert!(File.read(filename))
  2411. val = do_action(action, engine, context, filename, opts)
  2412. msg = nil if val
  2413. end
  2414. else
  2415. engine.filename = filename = '(stdin)'
  2416. engine.convert!($stdin.read())
  2417. val = do_action(action, engine, context, filename, opts)
  2418. msg = nil if val
  2419. end
  2420. print msg if action == 'syntax' && msg
  2421. end
  2422. private
  2423. def do_action(action, engine, context, filename, opts)
  2424. case action
  2425. when 'convert'
  2426. s = manipulate_src(engine.src, opts)
  2427. when nil, 'exec', 'execute'
  2428. s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
  2429. when 'syntax'
  2430. s = check_syntax(filename, engine.src)
  2431. else
  2432. raise "*** internal error"
  2433. end
  2434. print s if s
  2435. return s
  2436. end
  2437. def manipulate_src(source, opts)
  2438. flag_linenum = opts.linenum
  2439. flag_unique = opts.unique
  2440. flag_compact = opts.compact
  2441. if flag_linenum
  2442. n = 0
  2443. source.gsub!(/^/) { n += 1; "%5d: " % n }
  2444. source.gsub!(/^ *\d+:\s+?\n/, '') if flag_compact
  2445. source.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
  2446. else
  2447. source.gsub!(/^\s*?\n/, '') if flag_compact
  2448. source.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
  2449. end
  2450. return source
  2451. end
  2452. def usage(command=nil)
  2453. command ||= File.basename($0)
  2454. buf = []
  2455. buf << "erubis - embedded program converter for multi-language"
  2456. buf << "Usage: #{command} [..options..] [file ...]"
  2457. buf << " -h, --help : help"
  2458. buf << " -v : version"
  2459. buf << " -x : show converted code"
  2460. buf << " -X : show converted code, only ruby code and no text part"
  2461. buf << " -N : numbering: add line numbers (for '-x/-X')"
  2462. buf << " -U : unique: compress empty lines to a line (for '-x/-X')"
  2463. buf << " -C : compact: remove empty lines (for '-x/-X')"
  2464. buf << " -b : body only: no preamble nor postamble (for '-x/-X')"
  2465. buf << " -z : syntax checking"
  2466. buf << " -e : escape (equal to '--E Escape')"
  2467. buf << " -p pattern : embedded pattern (default '<% %>')"
  2468. buf << " -l lang : convert but no execute (ruby/php/c/java/scheme/perl/js)"
  2469. buf << " -E e1,e2,... : enhancer names (Escape, PercentLine, BiPattern, ...)"
  2470. buf << " -I path : library include path"
  2471. buf << " -K kanji : kanji code (euc/sjis/utf8) (default none)"
  2472. buf << " -c context : context data string (yaml inline style or ruby code)"
  2473. buf << " -f datafile : context data file ('*.yaml', '*.yml', or '*.rb')"
  2474. #buf << " -t : expand tab characters in YAML file"
  2475. buf << " -T : don't expand tab characters in YAML file"
  2476. buf << " -S : convert mapping key from string to symbol in YAML file"
  2477. buf << " -B : invoke 'result(binding)' instead of 'evaluate(context)'"
  2478. buf << " --pi=name : parse '<?name ... ?>' instead of '<% ... %>'"
  2479. #'
  2480. # -T : don't trim spaces around '<% %>'
  2481. # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
  2482. # -r library : require library
  2483. # -a : action (convert/execute)
  2484. return buf.join("\n")
  2485. end
  2486. def collect_supported_properties(erubis_klass)
  2487. list = []
  2488. erubis_klass.ancestors.each do |klass|
  2489. if klass.respond_to?(:supported_properties)
  2490. list.concat(klass.supported_properties)
  2491. end
  2492. end
  2493. return list
  2494. end
  2495. def show_properties
  2496. s = "supported properties:\n"
  2497. basic_props = collect_supported_properties(Erubis::Basic::Engine)
  2498. pi_props = collect_supported_properties(Erubis::PI::Engine)
  2499. list = []
  2500. common_props = basic_props & pi_props
  2501. list << ['(common)', common_props]
  2502. list << ['(basic)', basic_props - common_props]
  2503. list << ['(pi)', pi_props - common_props]
  2504. %w[ruby php c java scheme perl javascript].each do |lang|
  2505. klass = Erubis.const_get("E#{lang}")
  2506. list << [lang, collect_supported_properties(klass) - basic_props]
  2507. end
  2508. list.each do |lang, props|
  2509. s << " * #{lang}\n"
  2510. props.each do |name, default_val, desc|
  2511. s << (" --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
  2512. end
  2513. end
  2514. s << "\n"
  2515. return s
  2516. end
  2517. def show_enhancers
  2518. dict = {}
  2519. ObjectSpace.each_object(Module) do |mod|
  2520. dict[$1] = mod if mod.name =~ /\AErubis::(.*)Enhancer\z/
  2521. end
  2522. s = "enhancers:\n"
  2523. dict.sort_by {|name, mod| name }.each do |name, mod|
  2524. s << (" %-13s : %s\n" % [name, mod.desc])
  2525. end
  2526. return s
  2527. end
  2528. def version
  2529. return Erubis::VERSION
  2530. end
  2531. def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
  2532. options = {}
  2533. context = {}
  2534. while argv[0] && argv[0][0] == ?-
  2535. optstr = argv.shift
  2536. optstr = optstr[1, optstr.length-1]
  2537. #
  2538. if optstr[0] == ?- # context
  2539. optstr =~ /\A\-([-\w]+)(?:=(.*))?/ or
  2540. raise CommandOptionError.new("-#{optstr}: invalid context value.")
  2541. name, value = $1, $2
  2542. name = name.gsub(/-/, '_').intern
  2543. #value = value.nil? ? true : YAML.load(value) # error, why?
  2544. value = value.nil? ? true : YAML.load("---\n#{value}\n")
  2545. context[name] = value
  2546. #
  2547. else # options
  2548. while optstr && !optstr.empty?
  2549. optchar = optstr[0].chr
  2550. optstr = optstr[1..-1]
  2551. if arg_none.include?(optchar)
  2552. options[optchar] = true
  2553. elsif arg_required.include?(optchar)
  2554. arg = optstr.empty? ? argv.shift : optstr or
  2555. raise CommandOptionError.new("-#{optchar}: #{@option_names[optchar]} required.")
  2556. options[optchar] = arg
  2557. optstr = nil
  2558. elsif arg_optional.include?(optchar)
  2559. arg = optstr.empty? ? true : optstr
  2560. options[optchar] = arg
  2561. optstr = nil
  2562. else
  2563. raise CommandOptionError.new("-#{optchar}: unknown option.")
  2564. end
  2565. end
  2566. end
  2567. #
  2568. end # end of while
  2569. return options, context
  2570. end
  2571. def untabify(str, width=8)
  2572. list = str.split(/\t/)
  2573. last = list.pop
  2574. sb = ''
  2575. list.each do |s|
  2576. column = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
  2577. n = width - (column % width)
  2578. sb << s << (' ' * n)
  2579. end
  2580. sb << last
  2581. return sb
  2582. end
  2583. #--
  2584. #def untabify(str, width=8)
  2585. # sb = ''
  2586. # str.scan(/(.*?)\t/m) do |s, |
  2587. # len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
  2588. # sb << s << (" " * (width - len % width))
  2589. # end
  2590. # return $' ? (sb << $') : str
  2591. #end
  2592. #++
  2593. def get_classobj(classname, lang, pi)
  2594. classname ||= "E#{lang}"
  2595. base_module = pi ? Erubis::PI : Erubis
  2596. begin
  2597. klass = base_module.const_get(classname)
  2598. rescue NameError
  2599. klass = nil
  2600. end
  2601. unless klass
  2602. if lang
  2603. msg = "-l #{lang}: invalid language name (class #{base_module.name}::#{classname} not found)."
  2604. else
  2605. msg = "-c #{classname}: invalid class name."
  2606. end
  2607. raise CommandOptionError.new(msg)
  2608. end
  2609. return klass
  2610. end
  2611. def get_enhancers(enhancer_names)
  2612. return [] unless enhancer_names
  2613. enhancers = []
  2614. shortname = nil
  2615. begin
  2616. enhancer_names.split(/,/).each do |name|
  2617. shortname = name
  2618. enhancers << Erubis.const_get("#{shortname}Enhancer")
  2619. end
  2620. rescue NameError
  2621. raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-h' to show all enhancers).")
  2622. end
  2623. return enhancers
  2624. end
  2625. def load_datafiles(filenames, opts)
  2626. context = Erubis::Context.new
  2627. return context unless filenames
  2628. filenames.split(/,/).each do |filename|
  2629. filename.strip!
  2630. test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
  2631. if filename =~ /\.ya?ml$/
  2632. if opts.unexpand
  2633. ydoc = YAML.load_file(filename)
  2634. else
  2635. ydoc = YAML.load(untabify(File.read(filename)))
  2636. end
  2637. ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
  2638. intern_hash_keys(ydoc) if opts.intern
  2639. context.update(ydoc)
  2640. elsif filename =~ /\.rb$/
  2641. str = File.read(filename)
  2642. context2 = Erubis::Context.new
  2643. _instance_eval(context2, str)
  2644. context.update(context2)
  2645. else
  2646. CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
  2647. end
  2648. end
  2649. return context
  2650. end
  2651. def _instance_eval(_context, _str)
  2652. _context.instance_eval(_str)
  2653. end
  2654. def parse_context_data(context_str, opts)
  2655. if context_str[0] == ?{
  2656. require 'yaml'
  2657. ydoc = YAML.load(context_str)
  2658. unless ydoc.is_a?(Hash)
  2659. raise CommandOptionError.new("-c: root object is not a mapping.")
  2660. end
  2661. intern_hash_keys(ydoc) if opts.intern
  2662. return ydoc
  2663. else
  2664. context = Erubis::Context.new
  2665. context.instance_eval(context_str, '-c')
  2666. return context
  2667. end
  2668. end
  2669. def intern_hash_keys(obj, done={})
  2670. return if done.key?(obj.__id__)
  2671. case obj
  2672. when Hash
  2673. done[obj.__id__] = obj
  2674. obj.keys.each do |key|
  2675. obj[key.intern] = obj.delete(key) if key.is_a?(String)
  2676. end
  2677. obj.values.each do |val|
  2678. intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
  2679. end
  2680. when Array
  2681. done[obj.__id__] = obj
  2682. obj.each do |val|
  2683. intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
  2684. end
  2685. end
  2686. end
  2687. def check_syntax(filename, src)
  2688. require 'open3'
  2689. #command = (ENV['_'] || 'ruby') + ' -wc' # ENV['_'] stores command name
  2690. bin = ENV['_'] && File.basename(ENV['_']) =~ /^ruby/ ? ENV['_'] : 'ruby'
  2691. command = bin + ' -wc'
  2692. stdin, stdout, stderr = Open3.popen3(command)
  2693. stdin.write(src)
  2694. stdin.close
  2695. result = stdout.read()
  2696. stdout.close()
  2697. errmsg = stderr.read()
  2698. stderr.close()
  2699. return nil unless errmsg && !errmsg.empty?
  2700. errmsg =~ /\A-:(\d+): /
  2701. linenum, message = $1, $'
  2702. return "#{filename}:#{linenum}: #{message}"
  2703. end
  2704. end
  2705. end
  2706. #--end of require 'erubis/main'
  2707. Erubis::Main.main(ARGV)