erubis 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/ChangeLog +45 -18
  2. data/README.txt +80 -0
  3. data/benchmark/erubybench-lib.rb +189 -0
  4. data/benchmark/erubybench.rb +364 -0
  5. data/benchmark/erubybench.rhtml +61 -0
  6. data/benchmark/erubybench.yaml +61 -0
  7. data/bin/erubis +4 -180
  8. data/contrib/erubis +2297 -0
  9. data/contrib/inline-require +151 -0
  10. data/doc-api/classes/Erubis.html +236 -0
  11. data/doc-api/classes/Erubis/ArrayBufferEnhancer.html +175 -0
  12. data/doc-api/classes/Erubis/ArrayBufferEruby.html +120 -0
  13. data/doc-api/classes/Erubis/ArrayEnhancer.html +174 -0
  14. data/doc-api/classes/Erubis/ArrayEruby.html +120 -0
  15. data/doc-api/classes/Erubis/BiPatternEnhancer.html +212 -0
  16. data/doc-api/classes/Erubis/BiPatternEruby.html +120 -0
  17. data/doc-api/classes/Erubis/CommandOptionError.html +113 -0
  18. data/doc-api/classes/Erubis/Context.html +249 -0
  19. data/doc-api/classes/Erubis/Ec.html +399 -0
  20. data/doc-api/classes/Erubis/Ejava.html +366 -0
  21. data/doc-api/classes/Erubis/Ejavascript.html +390 -0
  22. data/doc-api/classes/Erubis/Engine.html +711 -0
  23. data/doc-api/classes/Erubis/Eperl.html +350 -0
  24. data/doc-api/classes/Erubis/Ephp.html +308 -0
  25. data/doc-api/classes/Erubis/ErubisError.html +117 -0
  26. data/doc-api/classes/Erubis/Eruby.html +310 -0
  27. data/doc-api/classes/Erubis/EscapeEnhancer.html +167 -0
  28. data/doc-api/classes/Erubis/EscapedEc.html +120 -0
  29. data/doc-api/classes/Erubis/EscapedEjava.html +120 -0
  30. data/doc-api/classes/Erubis/EscapedEjavascript.html +120 -0
  31. data/doc-api/classes/Erubis/EscapedEperl.html +120 -0
  32. data/doc-api/classes/Erubis/EscapedEphp.html +120 -0
  33. data/doc-api/classes/Erubis/EscapedEruby.html +127 -0
  34. data/doc-api/classes/Erubis/EscapedEscheme.html +120 -0
  35. data/doc-api/classes/Erubis/Escheme.html +389 -0
  36. data/doc-api/classes/Erubis/HeaderFooterEnhancer.html +264 -0
  37. data/doc-api/classes/Erubis/HeaderFooterEruby.html +120 -0
  38. data/doc-api/classes/Erubis/Main.html +318 -0
  39. data/doc-api/classes/Erubis/NoTextEnhancer.html +159 -0
  40. data/doc-api/classes/Erubis/NoTextEruby.html +120 -0
  41. data/doc-api/classes/Erubis/OptimizedEruby.html +445 -0
  42. data/doc-api/classes/Erubis/OptimizedXmlEruby.html +163 -0
  43. data/doc-api/classes/Erubis/PercentLineEnhancer.html +174 -0
  44. data/doc-api/classes/Erubis/PercentLineEruby.html +120 -0
  45. data/doc-api/classes/Erubis/PrintEnabledEnhancer.html +212 -0
  46. data/doc-api/classes/Erubis/PrintEnabledEruby.html +120 -0
  47. data/doc-api/classes/Erubis/PrintOutEnhancer.html +244 -0
  48. data/doc-api/classes/Erubis/PrintOutEruby.html +120 -0
  49. data/doc-api/classes/Erubis/PrintOutSimplifiedEruby.html +121 -0
  50. data/doc-api/classes/Erubis/SimplifiedEruby.html +120 -0
  51. data/doc-api/classes/Erubis/SimplifyEnhancer.html +185 -0
  52. data/doc-api/classes/Erubis/StdoutEnhancer.html +173 -0
  53. data/doc-api/classes/Erubis/StdoutEruby.html +120 -0
  54. data/doc-api/classes/Erubis/StdoutSimplifiedEruby.html +121 -0
  55. data/doc-api/classes/Erubis/StringBufferEnhancer.html +174 -0
  56. data/doc-api/classes/Erubis/StringBufferEruby.html +120 -0
  57. data/doc-api/classes/Erubis/StringIOEruby.html +120 -0
  58. data/doc-api/classes/Erubis/TinyEruby.html +305 -0
  59. data/doc-api/classes/Erubis/XmlEruby.html +130 -0
  60. data/doc-api/classes/Erubis/XmlHelper.html +193 -0
  61. data/doc-api/created.rid +1 -0
  62. data/doc-api/files/__/README_txt.html +214 -0
  63. data/doc-api/files/erubis/engine/ec_rb.html +115 -0
  64. data/doc-api/files/erubis/engine/ejava_rb.html +115 -0
  65. data/doc-api/files/erubis/engine/ejavascript_rb.html +115 -0
  66. data/doc-api/files/erubis/engine/enhanced_rb.html +115 -0
  67. data/doc-api/files/erubis/engine/eperl_rb.html +115 -0
  68. data/doc-api/files/erubis/engine/ephp_rb.html +115 -0
  69. data/doc-api/files/erubis/engine/eruby_rb.html +115 -0
  70. data/doc-api/files/erubis/engine/escheme_rb.html +115 -0
  71. data/doc-api/files/erubis/engine/optimized_rb.html +114 -0
  72. data/doc-api/files/erubis/engine_rb.html +114 -0
  73. data/doc-api/files/erubis/enhancer_rb.html +114 -0
  74. data/doc-api/files/erubis/helper_rb.html +107 -0
  75. data/doc-api/files/erubis/local-setting_rb.html +107 -0
  76. data/doc-api/files/erubis/main_rb.html +125 -0
  77. data/doc-api/files/erubis/tiny_rb.html +107 -0
  78. data/doc-api/files/erubis_rb.html +118 -0
  79. data/doc-api/fr_class_index.html +77 -0
  80. data/doc-api/fr_file_index.html +43 -0
  81. data/doc-api/fr_method_index.html +157 -0
  82. data/doc-api/index.html +24 -0
  83. data/doc-api/rdoc-style.css +208 -0
  84. data/doc/users-guide.html +1507 -375
  85. data/examples/Makefile +53 -0
  86. data/examples/example.ec +24 -0
  87. data/examples/example.ejava +41 -0
  88. data/examples/example.ejavascript +16 -0
  89. data/examples/example.eperl +16 -0
  90. data/examples/example.ephp +17 -0
  91. data/examples/example.eruby +15 -0
  92. data/examples/example.escheme +26 -0
  93. data/lib/erubis.rb +37 -269
  94. data/lib/erubis/engine.rb +260 -0
  95. data/lib/erubis/engine/ec.rb +106 -0
  96. data/lib/erubis/engine/ejava.rb +101 -0
  97. data/lib/erubis/engine/ejavascript.rb +104 -0
  98. data/lib/erubis/engine/enhanced.rb +102 -0
  99. data/lib/erubis/engine/eperl.rb +83 -0
  100. data/lib/erubis/engine/ephp.rb +84 -0
  101. data/lib/erubis/engine/eruby.rb +91 -0
  102. data/lib/erubis/engine/escheme.rb +96 -0
  103. data/lib/erubis/engine/optimized.rb +114 -0
  104. data/lib/erubis/enhancer.rb +487 -0
  105. data/lib/erubis/helper.rb +53 -0
  106. data/lib/erubis/local-setting.rb +10 -0
  107. data/lib/erubis/main.rb +368 -0
  108. data/lib/erubis/tiny.rb +65 -0
  109. data/test/assert-text-equal.rb +45 -0
  110. data/test/test-bin.rb +222 -45
  111. data/test/test-engines.rb +343 -0
  112. data/test/test-erubis.rb +836 -501
  113. data/test/test.rb +27 -0
  114. data/test/testutil.rb +86 -0
  115. metadata +131 -8
  116. data/README +0 -50
@@ -0,0 +1,61 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
+ "http://www.w3.org/TR/html4/loose.dtd">
3
+ <html>
4
+ <head>
5
+ <title>benchmark example</title>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
+ <style type="text/css">
8
+ <!--
9
+
10
+ body {
11
+ color: #333333;
12
+ line-height: 150%;
13
+ }
14
+
15
+ thead {
16
+ font-weight: bold;
17
+ background-color: #CCCCCC;
18
+ }
19
+
20
+ .odd {
21
+ background-color: #FFCCCC;
22
+ }
23
+
24
+ .even {
25
+ background-color: #CCCCFF;
26
+ }
27
+ -->
28
+ </style>
29
+
30
+ </head>
31
+
32
+ <body>
33
+
34
+ <h1>Companies</h1>
35
+
36
+ <table>
37
+ <thead>
38
+ <tr>
39
+ <th>index</th><th>code</th><th>name</th>
40
+ </tr>
41
+ </thead>
42
+ <tbody>
43
+ <% data.each_with_index do |h, i| %>
44
+ <% n = i + 1 %>
45
+ <tr class="<%= n % 2 == 0 ? 'even' : 'odd' %>">
46
+ <td style="text-align: center">
47
+ <span><%= n %></span>
48
+ </td>
49
+ <td>
50
+ <a href="/stock/<%= h[:code] %>"><%= h[:code] %></a>
51
+ </td>
52
+ <td>
53
+ <a href="<%= h[:url] %>"><%= h[:name] %></a>
54
+ </td>
55
+ </tr>
56
+ <% end %>
57
+ </tbody>
58
+ </table>
59
+
60
+ </body>
61
+ </html>
@@ -0,0 +1,61 @@
1
+ data:
2
+ - name: Apple Computer Inc.
3
+ url: http://www.apple.com
4
+ code: AAPL
5
+ - name: Amazon.com Inc
6
+ url: http://www.amazon.com
7
+ code: AMZN
8
+ - name: Sun Microsystems Inc.
9
+ url: http://www.sun.com
10
+ code: SUNW
11
+ - name: Microsoft Corp
12
+ url: http://www.microsoft.com
13
+ code: MSFT
14
+ - name: Adobe Systems Inc.
15
+ url: http://www.adobe.com
16
+ code: ADBE
17
+ - name: Intel Corp.
18
+ url: http://www.intel.com
19
+ code: INTC
20
+ - name: Oracle Corp.
21
+ url: http://www.oracle.com
22
+ code: ORCL
23
+ - name: International Business Machines Corp.
24
+ url: http://www.ibm.com
25
+ code: IBM
26
+ - name: BEA Systems Inc.
27
+ url: http://www.bea.com
28
+ code: BEAS
29
+ - name: eBay Inc.
30
+ url: http://www.ebay.com
31
+ code: EBAY
32
+ - name: Yahoo! Inc.
33
+ url: http://www.yahoo.com
34
+ code: YHOO
35
+ - name: Google Inc.
36
+ url: http://www.google.com
37
+ code: GOOG
38
+ - name: Hewlett-Packard Co.
39
+ url: http://www.hp.com
40
+ code: HPQ
41
+ - name: SAP AG
42
+ url: http://www.sap.com
43
+ code: SAP
44
+ - name: Cisco Systems Inc.
45
+ url: http://www.cisco.com
46
+ code: CSCO
47
+ - name: Juniper Networks, Inc
48
+ url: http://www.juniper.net/
49
+ code: JNPR
50
+ - name: Advanced Micro Devices Inc.
51
+ url: http://www.amd.com
52
+ code: AMD
53
+ - name: Red Hat Inc.
54
+ url: http://www.redhat.com
55
+ code: RHAT
56
+ - name: CA, Inc.
57
+ url: http://www.ca.com
58
+ code: CA
59
+ - name: Seagate Technology
60
+ url: http://www.seagate.com/
61
+ code: STX
data/bin/erubis CHANGED
@@ -1,187 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
3
  ###
4
- ### $Rev: 4 $
5
- ### $Release: 1.1.0 $
4
+ ### $Rev: 10 $
5
+ ### $Release: 2.0.0 $
6
6
  ### copyright(c) 2006 kuwata-lab all rights reserved.
7
7
  ###
8
8
 
9
- require 'yaml'
10
- require 'erubis'
9
+ require 'erubis/main'
11
10
 
12
-
13
- class CommandOptionError < StandardError
14
- def initialize(message)
15
- super(message)
16
- end
17
- end
18
-
19
-
20
- class Main
21
-
22
- def execute(argv=ARGV)
23
- ## parse command-line options
24
- options, context = parse_argv(argv, "hvsT", "pcrfKI")
25
- filenames = argv
26
- options[?h] = true if context[:help]
27
-
28
- ## help, version
29
- if options[?h] || options[?v]
30
- puts version() if options[?v]
31
- puts usage() if options[?h]
32
- return
33
- end
34
-
35
- ## include path
36
- options[?I].split(/,/).each do |path|
37
- $: << path
38
- end if options[?I]
39
-
40
- ## require library
41
- options[?r].split(/,/).each do |library|
42
- require library
43
- end if options[?r]
44
-
45
- ## class name of Eruby
46
- classname = options[?c] || 'Eruby'
47
- begin
48
- klass = Erubis.const_get(classname)
49
- rescue NameError
50
- klass = nil
51
- end
52
- unless klass && classname =~ /Eruby\z/
53
- raise CommandOptionError.new("-c #{classname}: invalid class name.")
54
- end
55
-
56
- ## kanji code
57
- $KCODE = options[?K] if options[?K]
58
-
59
- ## read context values from yaml file
60
- yamlfiles = options[?f]
61
- if yamlfiles
62
- hash = {}
63
- yamlfiles.split(/,/).each do |yamlfile|
64
- ydoc = yamlfile == '-' ? YAML.load($stdin.read()) : YAML.load_file(yamlfile)
65
- unless ydoc.is_a?(Hash)
66
- raise CommandOptionError.new("#{yamlfile}: root object is not a mapping.")
67
- end
68
- hash.update(ydoc)
69
- end
70
- hash.update(context)
71
- context = hash
72
- end
73
-
74
- ## options for Eruby
75
- eruby_options = {}
76
- eruby_options[:pattern] = options[?p] if options[?p]
77
- eruby_options[:trim] = false if options[?T]
78
-
79
- ## execute Eruby
80
- flag_src = options[?s]
81
- if filenames && !filenames.empty?
82
- filenames.each do |filename|
83
- eruby = klass.load_file(filename, eruby_options)
84
- print flag_src ? eruby.src : eruby.evaluate(context)
85
- end
86
- else
87
- input = ARGF.read()
88
- eruby = klass.new(input, eruby_options)
89
- print flag_src ? eruby.src : eruby.evaluate(context)
90
- end
91
-
92
- end
93
-
94
- private
95
-
96
- def usage
97
- command = File.basename($0)
98
- s = <<END
99
- Usage: #{command} [..options..] [file ...]
100
- -h, --help : help
101
- -v : version
102
- -s : script source
103
- -T : no trimming
104
- -p pattern : embedded pattern (default '<% %>')
105
- -c class : class name (Eruby, XmlEruby, FastEruby, ...) (default Eruby)
106
- -I path : library include path
107
- -K kanji : kanji code (euc, sjis, utf8, none) (default none)
108
- -f file.yaml : YAML file for context values (read stdin if filename is '-')
109
- --name=value : context name and value
110
- END
111
- # -r library : require library
112
- return s
113
- end
114
-
115
- def version
116
- release = ('$Release: 1.1.0 $' =~ /([.\d]+)/) && $1
117
- return release
118
- end
119
-
120
- def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
121
- options = {}
122
- context = {}
123
- while argv[0] && argv[0][0] == ?-
124
- optstr = argv.shift
125
- optstr = optstr[1, optstr.length-1]
126
- #
127
- if optstr[0] == ?- # context
128
- unless optstr =~ /\A\-([-\w]+)(?:=(.*))?/
129
- raise CommandOptionError.new("-#{optstr}: invalid context value.")
130
- end
131
- name = $1; value = $2
132
- name = name.gsub(/-/, '_').intern
133
- value = value == nil ? true : to_value(value)
134
- context[name] = value
135
- #
136
- else # options
137
- while optstr && !optstr.empty?
138
- optchar = optstr[0]
139
- optstr[0,1] = ""
140
- if arg_none.include?(optchar)
141
- options[optchar] = true
142
- elsif arg_required.include?(optchar)
143
- arg = optstr.empty? ? argv.shift : optstr
144
- raise CommandOptionError.new("-#{optchar.chr}: argument required.") unless arg
145
- options[optchar] = arg
146
- optstr = nil
147
- elsif arg_optional.include?(optchar)
148
- arg = optstr.empty? ? true : optstr
149
- options[optchar] = arg
150
- optstr = nil
151
- else
152
- raise CommandOptionError.new("-#{optchar.chr}: unknown option.")
153
- end
154
- end
155
- end
156
- #
157
- end # end of while
158
-
159
- return options, context
160
- end
161
-
162
- def to_value(str)
163
- case str
164
- when nil, "null", "nil" ; return nil
165
- when "true", "yes" ; return true
166
- when "false", "no" ; return false
167
- when /\A\d+\z/ ; return str.to_i
168
- when /\A\d+\.\d+\z/ ; return str.to_f
169
- when /\/(.*)\// ; return Regexp.new($1)
170
- when /\A'.*'\z/, /\A".*"\z/ ; return eval(str)
171
- else ; return str
172
- end
173
- end
174
-
175
- end
176
-
177
-
178
- #if __FILE__ == $0
179
- status = 0
180
- begin
181
- Main.new.execute(ARGV)
182
- rescue CommandOptionError => ex
183
- $stderr.puts ex.message
184
- status = 1
185
- end
186
- exit(status)
187
- #end
11
+ Erubis::Main.main(ARGV)
@@ -0,0 +1,2297 @@
1
+ #!/usr/bin/ruby
2
+
3
+ ###
4
+ ### $Rev: 10 $
5
+ ### $Release: 2.0.0 $
6
+ ### copyright(c) 2006 kuwata-lab all rights reserved.
7
+ ###
8
+
9
+ #--begin of require 'erubis/main'
10
+ ###
11
+ ### $Rev: 21 $
12
+ ### $Release: 2.0.0 $
13
+ ### copyright(c) 2006 kuwata-lab all rights reserved.
14
+ ###
15
+
16
+ require 'yaml'
17
+ #--begin of require 'erubis'
18
+ ##
19
+ ## $Rev: 21 $
20
+ ## $Release: 2.0.0 $
21
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
22
+ ##
23
+
24
+ ##
25
+ ## an implementation of eRuby
26
+ ##
27
+ ## * class Eruby - normal eRuby class
28
+ ## * class XmlEruby - eRuby class which escape '&<>"' into '&amp;&lt;&gt;&quot;'
29
+ ## * module StdoutEnhancer - use $stdout instead of String as output
30
+ ## * module PrintEnhancer - enable to write print statement in <% ... %>
31
+ ## * class OptimizedEruby - optimized Eruby class faster than FastEruby
32
+ ## * class OptimizedXmlEruby - optimized XmlEruby class faster than FastXmlEruby
33
+ ##
34
+ ## example:
35
+ ## input = <<'END'
36
+ ## <ul>
37
+ ## <% for item in @list %>
38
+ ## <li><%= item %>
39
+ ## <%== item %></li>
40
+ ## <% end %>
41
+ ## </ul>
42
+ ## END
43
+ ## list = ['<aaa>', 'b&b', '"ccc"']
44
+ ## eruby = Erubis::Eruby.new(input)
45
+ ## puts "--- source ---"
46
+ ## puts eruby.src
47
+ ## puts "--- result ---"
48
+ ## puts eruby.evaluate(:list=>list)
49
+ ## # or puts eruby.result(binding())
50
+ ##
51
+ ## result:
52
+ ## --- source ---
53
+ ## _buf = ""; _buf << " <ul>\n"
54
+ ## for item in list
55
+ ## _buf << " <li>"; _buf << ( item ).to_s; _buf << "\n"
56
+ ## _buf << " "; _buf << Erubis::XmlEruby.escape( item ); _buf << "</li>\n"
57
+ ## end
58
+ ## _buf << " </ul>\n"
59
+ ## _buf
60
+ ## --- result ---
61
+ ## <ul>
62
+ ## <li><aaa>
63
+ ## &lt;aaa&gt;</li>
64
+ ## <li>b&b
65
+ ## b&amp;b</li>
66
+ ## <li>"ccc"
67
+ ## &quot;ccc&quot;</li>
68
+ ## </ul>
69
+ ##
70
+
71
+
72
+ #--begin of require 'erubis/engine'
73
+ ##
74
+ ## $Rev: 21 $
75
+ ## $Release: 2.0.0 $
76
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
77
+ ##
78
+
79
+ #--begin of require 'abstract'
80
+ ##
81
+ ## $Rev: 1 $
82
+ ## $Release$
83
+ ## $Copyright$
84
+ ##
85
+ ##
86
+ ## helper to define abstract method in Ruby.
87
+ ##
88
+ ##
89
+ ## example1. (shorter notation)
90
+ ##
91
+ ## require 'abstract'
92
+ ## class Foo
93
+ ## abstract_method 'arg1, arg2=""', :method1, :method2, :method3
94
+ ## end
95
+ ##
96
+ ##
97
+ ## example2. (RDoc friendly notation)
98
+ ##
99
+ ## require 'abstract'
100
+ ## class Bar
101
+ ## # ... method1 description ...
102
+ ## def method1(arg1, arg2="")
103
+ ## not_implemented
104
+ ## end
105
+ ##
106
+ ## # ... method2 description ...
107
+ ## def method2(arg1, arg2="")
108
+ ## not_implemented
109
+ ## end
110
+ ## end
111
+ ##
112
+
113
+
114
+ ##
115
+ class Module
116
+
117
+ ##
118
+ ## define abstract methods
119
+ ##
120
+ def abstract_method args_str, *method_names
121
+ method_names.each do |name|
122
+ module_eval <<-END
123
+ def #{name}(#{args_str})
124
+ mesg = "class \#{self.class.name} must implement abstract method `#{self.name}##{name}()'."
125
+ #mesg = "\#{self.class.name}##{name}() is not implemented."
126
+ err = NotImplementedError.new mesg
127
+ err.set_backtrace caller()
128
+ raise err
129
+ end
130
+ END
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+
137
+ ##
138
+ module Kernel
139
+
140
+ ##
141
+ ## raise NotImplementedError
142
+ ##
143
+ def not_implemented #:doc:
144
+ backtrace = caller()
145
+ method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
146
+ mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
147
+ #mesg = "#{self.class.name}##{method_name}() is not implemented."
148
+ err = NotImplementedError.new mesg
149
+ err.set_backtrace backtrace
150
+ raise err
151
+ end
152
+ private :not_implemented
153
+
154
+ end
155
+ #--end of require 'abstract'
156
+
157
+
158
+ module Erubis
159
+
160
+
161
+ ##
162
+ ## base error class
163
+ ##
164
+ class ErubisError < StandardError
165
+ end
166
+
167
+
168
+ ##
169
+ ## .[abstract] context object for Engine#evaluate
170
+ ##
171
+ ## ex.
172
+ ## template = <<'END'
173
+ ## Hello <%= @user %>!
174
+ ## <% for item in @list %>
175
+ ## - <%= item %>
176
+ ## <% end %>
177
+ ## END
178
+ ##
179
+ ## context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
180
+ ## # or
181
+ ## # context = Erubis::Context.new
182
+ ## # context[:user] = 'World'
183
+ ## # context[:list] = ['a', 'b', 'c']
184
+ ##
185
+ ## eruby = Erubis::Eruby.new(template)
186
+ ## print eruby.evaluate(context)
187
+ ##
188
+ class Context
189
+
190
+ def initialize(hash=nil)
191
+ hash.each do |name, value|
192
+ self[name] = value
193
+ end if hash
194
+ end
195
+
196
+ def [](key)
197
+ return instance_variable_get("@#{key}")
198
+ end
199
+
200
+ def []=(key, value)
201
+ return instance_variable_set("@#{key}", value)
202
+ end
203
+
204
+ def keys
205
+ return instance_variables.collect { |name| name[1,name.length-1] }
206
+ end
207
+
208
+ end
209
+
210
+
211
+ ##
212
+ ## [abstract] base engine class
213
+ ##
214
+ class Engine
215
+
216
+ def self.supported_properties # :nodoc:
217
+ return [
218
+ [:pattern, '<% %>', "embed pattern"],
219
+ #[:filename, nil, "filename"],
220
+ [:trim, true, "trim spaces around <% ... %>"],
221
+ [:preamble, nil, "preamble (no preamble when false)"],
222
+ [:postamble, nil, "postamble (no postamble when false)"],
223
+ [:escape, nil, "escape function name"],
224
+ ]
225
+ end
226
+
227
+ def initialize(input, properties={})
228
+ #@input = input
229
+ @pattern = properties[:pattern] || '<% %>'
230
+ @filename = properties[:filename]
231
+ @trim = properties[:trim] != false
232
+ @preamble = properties[:preamble]
233
+ @postamble = properties[:postamble]
234
+ @escape = properties[:escape]
235
+ @src = compile(input) if input
236
+ end
237
+ attr_reader :src
238
+ attr_accessor :filename
239
+
240
+ ## load file and create engine object
241
+ def self.load_file(filename, properties={})
242
+ input = File.open(filename, 'rb') { |f| f.read }
243
+ input.untaint # is it ok?
244
+ properties[:filename] = filename
245
+ engine = self.new(input, properties)
246
+ return engine
247
+ end
248
+
249
+ ## eval(@src) with binding
250
+ def result(_binding_or_hash=TOPLEVEL_BINDING)
251
+ _arg = _binding_or_hash
252
+ if _arg.is_a?(Hash)
253
+ ## load _context data as local variables by eval
254
+ eval _arg.keys.inject("") { |s, k| s << "#{k.to_s} = _arg[#{k.inspect}];" }
255
+ _arg = binding()
256
+ end
257
+ return eval(@src, _arg, (@filename || '(erubis)'))
258
+ end
259
+
260
+ ## call context.instance_eval(@src)
261
+ def evaluate(context=Context.new)
262
+ context = Context.new(context) if context.is_a?(Hash)
263
+ return context.instance_eval(@src, (@filename || '(erubis)'))
264
+ end
265
+
266
+ DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
267
+
268
+ ## return regexp of pattern to parse eRuby script
269
+ def pattern_regexp(pattern=@pattern)
270
+ if pattern == '<% %>'
271
+ return DEFAULT_REGEXP
272
+ else
273
+ prefix, postfix = pattern.split()
274
+ return /(.*?)(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
275
+ end
276
+ end
277
+ protected :pattern_regexp
278
+
279
+ ## compile input string into target language
280
+ def compile(input)
281
+ src = ""
282
+ @preamble.nil? ? add_preamble(src) : (@preamble && (src << @preamble))
283
+ regexp = pattern_regexp(@pattern)
284
+ input.scan(regexp) do |text, lspace, indicator, code, rspace|
285
+ add_text(src, text)
286
+ ## * when '<%= %>', do nothing
287
+ ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
288
+ if !indicator # <% %>
289
+ if @trim && lspace && rspace
290
+ add_stmt(src, "#{lspace}#{code}#{rspace}")
291
+ else
292
+ add_text(src, lspace) if lspace
293
+ add_stmt(src, code)
294
+ add_text(src, rspace) if rspace
295
+ end
296
+ elsif indicator[0] == ?\# # <%# %>
297
+ n = code.count("\n") + (rspace ? 1 : 0)
298
+ if @trim && lspace && rspace
299
+ add_stmt(src, "\n" * n)
300
+ else
301
+ add_text(src, lspace) if lspace
302
+ add_stmt(src, "\n" * n)
303
+ add_text(src, rspace) if lspace
304
+ end
305
+ #flag_trim = @trim && lspace && rspace
306
+ #add_text(src, lspace) if !flag_trim && lspace
307
+ #n = code.count("\n") + (rspace ? 1 : 0)
308
+ #add_stmt(src, "\n" * n)
309
+ #add_text(src, rspace) if !flag_trim && rspace
310
+ else # <%= %>
311
+ add_text(src, lspace) if lspace
312
+ add_expr(src, code, indicator)
313
+ add_text(src, rspace) if rspace
314
+ end
315
+ #if indicator && indicator[0] == ?=
316
+ # flag_trim = false
317
+ #else
318
+ # flag_trim = @trim && lspace && rspace
319
+ #end
320
+ ##flag_trim = @trim && !(indicator && indicator[0]==?=) && lspace && rspace
321
+ #add_text(src, text)
322
+ #add_text(src, lspace) if !flag_trim && lspace
323
+ #if !indicator # <% %>
324
+ # code = "#{lspace}#{code}#{rspace}" if flag_trim
325
+ # add_stmt(src, code)
326
+ #elsif indicator[0] == ?\# # <%# %>
327
+ # n = code.count("\n") + (rspace ? 1 : 0)
328
+ # add_stmt(src, "\n" * n)
329
+ #else # <%= %>
330
+ # add_expr(src, code, indicator)
331
+ #end
332
+ #add_text(src, rspace) if !flag_trim && rspace
333
+ end
334
+ rest = $' || input # add input when no matched
335
+ add_text(src, rest)
336
+ @postamble.nil? ? add_postamble(src) : (@postamble && (src << @postamble))
337
+ return src
338
+ end
339
+
340
+ ## compile input string and set it to @src
341
+ def compile!(input)
342
+ @src = compile(input)
343
+ end
344
+
345
+ protected
346
+
347
+ ## escape text string
348
+ def escape_text(text)
349
+ return text
350
+ end
351
+
352
+ ## return escaped expression code
353
+ def escaped_expr(code)
354
+ @escape ||= 'escape'
355
+ return "#{@escape}(#{code.strip})"
356
+ end
357
+
358
+ ## .[empty] add @preamble to src
359
+ def add_preamble(src)
360
+ # empty
361
+ end
362
+
363
+ ## .[abstract] add text string to src
364
+ def add_text(src, text)
365
+ not_implemented
366
+ end
367
+
368
+ ## .[abstract] add statement code to src
369
+ def add_stmt(src, code)
370
+ not_implemented
371
+ end
372
+
373
+ ## add expression code to src
374
+ def add_expr(src, code, indicator)
375
+ case indicator
376
+ when '='
377
+ add_expr_literal(src, code)
378
+ when '=='
379
+ add_expr_escaped(src, code)
380
+ when '==='
381
+ add_expr_debug(src, code)
382
+ end
383
+ end
384
+
385
+ ## .[abstract] add expression literal code to src. this is called by add_expr().
386
+ def add_expr_literal(src, code)
387
+ not_implemented
388
+ end
389
+
390
+ ## .[abstract] add escaped expression code to src. this is called by add_expr().
391
+ def add_expr_escaped(src, code)
392
+ not_implemented
393
+ end
394
+
395
+ ## .[empty] add expression code to src for debug. this is called by add_expr().
396
+ def add_expr_debug(src, code)
397
+ # empty
398
+ end
399
+
400
+ ## .[empty] add @postamble to src
401
+ def add_postamble(src)
402
+ # empty
403
+ end
404
+
405
+ end # end of class Engine
406
+
407
+
408
+ end
409
+ #--end of require 'erubis/engine'
410
+ #--begin of require 'erubis/helper'
411
+ ##
412
+ ## $Rev: 21 $
413
+ ## $Release: 2.0.0 $
414
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
415
+ ##
416
+
417
+
418
+ module Erubis
419
+
420
+ ##
421
+ ## helper for xml
422
+ ##
423
+ module XmlHelper
424
+
425
+ module_function
426
+
427
+ ESCAPE_TABLE = {
428
+ '&' => '&amp;',
429
+ '<' => '&lt;',
430
+ '>' => '&gt;',
431
+ '"' => '&quot;',
432
+ "'" => '&#039;',
433
+ }
434
+
435
+ def escape_xml(obj)
436
+ #table = ESCAPE_TABLE
437
+ #obj.to_s.gsub(/[&<>"]/) { |s| table[s] } # or /[&<>"']/
438
+ obj.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
439
+ #obj.to_s.gsub(SCAN_REGEXP) { |s| ESCAPE_TABLE[s] }
440
+ #obj.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
441
+ end
442
+
443
+ #--
444
+ #def escape_xml(obj)
445
+ # str = obj.to_s.dup
446
+ # #str = obj.to_s
447
+ # #str = str.dup if obj.__id__ == str.__id__
448
+ # str.gsub!(/&/, '&amp;')
449
+ # str.gsub!(/</, '&lt;')
450
+ # str.gsub!(/>/, '&gt;')
451
+ # str.gsub!(/"/, '&quot;')
452
+ # str.gsub!(/'/, '&#039;')
453
+ # return str
454
+ #end
455
+ #++
456
+
457
+ alias h escape_xml
458
+ alias html_escape escape_xml
459
+
460
+ end
461
+
462
+
463
+ end
464
+ #--end of require 'erubis/helper'
465
+ #--begin of require 'erubis/enhancer'
466
+ ##
467
+ ## $Rev: 21 $
468
+ ## $Release: 2.0.0 $
469
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
470
+ ##
471
+
472
+
473
+ #--already included require 'erubis/engine'
474
+
475
+
476
+ module Erubis
477
+
478
+
479
+ ##
480
+ ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
481
+ ##
482
+ ## ex.
483
+ ## class XmlEruby < Eruby
484
+ ## include EscapeEnhancer
485
+ ## end
486
+ ##
487
+ ## this is language-indenedent.
488
+ ##
489
+ module EscapeEnhancer
490
+
491
+ def self.desc # :nodoc:
492
+ "switch '<%= %>' to escaped and '<%== %>' to unescaped"
493
+ end
494
+
495
+ #--
496
+ #def self.included(klass)
497
+ # klass.class_eval <<-END
498
+ # alias _add_expr_literal add_expr_literal
499
+ # alias _add_expr_escaped add_expr_escaped
500
+ # alias add_expr_literal _add_expr_escaped
501
+ # alias add_expr_escaped _add_expr_literal
502
+ # END
503
+ #end
504
+ #++
505
+
506
+ def add_expr(src, code, indicator)
507
+ case indicator
508
+ when '='
509
+ add_expr_escaped(src, code)
510
+ #add_expr_literal(src, code)
511
+ when '=='
512
+ add_expr_literal(src, code)
513
+ #add_expr_escaped(src, code)
514
+ when '==='
515
+ add_expr_debug(src, code)
516
+ end
517
+ end
518
+
519
+ end
520
+
521
+
522
+ #--
523
+ ## (obsolete)
524
+ #module FastEnhancer
525
+ #end
526
+ #++
527
+
528
+
529
+ ##
530
+ ## use $stdout instead of string
531
+ ##
532
+ ## this is only for Eruby.
533
+ ##
534
+ module StdoutEnhancer
535
+
536
+ def self.desc # :nodoc:
537
+ "use $stdout instead of array buffer or string buffer"
538
+ end
539
+
540
+ def add_preamble(src)
541
+ src << "_buf = $stdout;"
542
+ end
543
+
544
+ def add_postamble(src)
545
+ src << "\n''\n"
546
+ end
547
+
548
+ end
549
+
550
+
551
+ ##
552
+ ## use print statement instead of '_buf << ...'
553
+ ##
554
+ ## this is only for Eruby.
555
+ ##
556
+ module PrintOutEnhancer
557
+
558
+ def self.desc # :nodoc:
559
+ "use print statement instead of '_buf << ...'"
560
+ end
561
+
562
+ def add_preamble(src)
563
+ end
564
+
565
+ def add_text(src, text)
566
+ src << " print '" << escape_text(text) << "';" unless text.empty?
567
+ end
568
+
569
+ def add_expr_literal(src, code)
570
+ src << ' print((' << code << ').to_s);'
571
+ end
572
+
573
+ def add_expr_escaped(src, code)
574
+ src << ' print ' << escaped_expr(code) << ';'
575
+ end
576
+
577
+ def add_postamble(src)
578
+ src << "\n" unless src[-1] == ?\n
579
+ end
580
+
581
+ end
582
+
583
+
584
+ ##
585
+ ## enable print function
586
+ ##
587
+ ## Notice: use Eruby#evaluate() and don't use Eruby#result()
588
+ ## to be enable print function.
589
+ ##
590
+ ## this is only for Eruby.
591
+ ##
592
+ module PrintEnabledEnhancer
593
+
594
+ def self.desc # :nodoc:
595
+ "enable to use print function in '<% %>'"
596
+ end
597
+
598
+ def add_preamble(src)
599
+ src << "@_buf = "
600
+ super
601
+ end
602
+
603
+ def print(*args)
604
+ args.each do |arg|
605
+ @_buf << arg.to_s
606
+ end
607
+ end
608
+
609
+ def evaluate(context=Context.new)
610
+ _src = @src
611
+ if context.is_a?(Hash)
612
+ context.each do |key, val| instance_variable_set("@#{key}", val) end
613
+ else
614
+ context.instance_variables.each do |name|
615
+ instance_variable_set(name, context.instance_variable_get(name))
616
+ end
617
+ end
618
+ return instance_eval(_src, (@filename || '(erubis)'))
619
+ end
620
+
621
+ end
622
+
623
+
624
+ ##
625
+ ## return array instead of string
626
+ ##
627
+ ## this is only for Eruby.
628
+ ##
629
+ module ArrayEnhancer
630
+
631
+ def self.desc # :nodoc:
632
+ "return array instead of string"
633
+ end
634
+
635
+ def add_preamble(src)
636
+ src << "_buf = [];"
637
+ end
638
+
639
+ def add_postamble(src)
640
+ src << "\n" unless src[-1] == ?\n
641
+ src << "_buf\n"
642
+ end
643
+
644
+ end
645
+
646
+
647
+ ##
648
+ ## use an Array object as buffer (included in Eruby by default)
649
+ ##
650
+ ## this is only for Eruby.
651
+ ##
652
+ module ArrayBufferEnhancer
653
+
654
+ def self.desc # :nodoc:
655
+ "use an Array object for buffering (included in Eruby class)"
656
+ end
657
+
658
+ def add_preamble(src)
659
+ src << "_buf = [];"
660
+ end
661
+
662
+ def add_postamble(src)
663
+ src << "\n" unless src[-1] == ?\n
664
+ src << "_buf.join\n"
665
+ end
666
+
667
+ end
668
+
669
+
670
+ ##
671
+ ## use String class for buffering
672
+ ##
673
+ ## this is only for Eruby.
674
+ ##
675
+ module StringBufferEnhancer
676
+
677
+ def self.desc # :nodoc:
678
+ "use a String object for buffering"
679
+ end
680
+
681
+ def add_preamble(src)
682
+ src << "_buf = '';"
683
+ end
684
+
685
+ def add_postamble(src)
686
+ src << "\n" unless src[-1] == ?\n
687
+ src << "_buf\n"
688
+ end
689
+
690
+ end
691
+
692
+
693
+ ##
694
+ ## use StringIO class for buffering
695
+ ##
696
+ ## this is only for Eruby.
697
+ ##
698
+ module StringIOEnhancer # :nodoc:
699
+
700
+ def self.desc # :nodoc:
701
+ "use a StringIO object for buffering"
702
+ end
703
+
704
+ def add_preamble(src)
705
+ src << "_buf = StringIO.new;"
706
+ end
707
+
708
+ def add_postamble(src)
709
+ src << "\n" unless src[-1] == ?\n
710
+ src << "_buf.string\n"
711
+ end
712
+
713
+ end
714
+
715
+
716
+ ##
717
+ ## remove text and leave code, especially useful when debugging.
718
+ ##
719
+ ## ex.
720
+ ## $ erubis -s -e NoText file.eruby | more
721
+ ##
722
+ ## this is language independent.
723
+ ##
724
+ module NoTextEnhancer
725
+
726
+ def self.desc # :nodoc:
727
+ "remove text and leave code (useful when debugging)"
728
+ end
729
+
730
+ def add_text(src, text)
731
+ src << ("\n" * text.count("\n"))
732
+ if text[-1] != ?\n
733
+ text =~ /^(.*?)\z/
734
+ src << (' ' * $1.length)
735
+ end
736
+ end
737
+
738
+ end
739
+
740
+
741
+ ##
742
+ ## get compile faster, but spaces around '<%...%>' are not trimmed.
743
+ ##
744
+ ## this is language-independent.
745
+ ##
746
+ module SimplifyEnhancer
747
+
748
+ def self.desc # :nodoc:
749
+ "get compile faster but leave spaces around '<% %>'"
750
+ end
751
+
752
+ #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
753
+ SIMPLE_REGEXP = /(.*?)<%(=+|\#)?(.*?)-?%>/m
754
+
755
+ def compile(input)
756
+ src = ""
757
+ add_preamble(src)
758
+ #regexp = pattern_regexp(@pattern)
759
+ input.scan(SIMPLE_REGEXP) do |text, indicator, code|
760
+ add_text(src, text)
761
+ if !indicator # <% %>
762
+ add_stmt(src, code)
763
+ elsif indicator[0] == ?\# # <%# %>
764
+ n = code.count("\n")
765
+ add_stmt(src, "\n" * n)
766
+ else # <%= %>
767
+ add_expr(src, code, indicator)
768
+ end
769
+ end
770
+ rest = $' || input
771
+ add_text(src, rest)
772
+ add_postamble(src)
773
+ return src
774
+ end
775
+
776
+ end
777
+
778
+
779
+ ##
780
+ ## enable to use other embedded expression pattern (default is '\[= =\]').
781
+ ##
782
+ ## notice! this is an experimental. spec may change in the future.
783
+ ##
784
+ ## ex.
785
+ ## input = <<END
786
+ ## <% for item in list %>
787
+ ## <%= item %> : <%== item %>
788
+ ## [= item =] : [== item =]
789
+ ## <% end %>
790
+ ## END
791
+ ##
792
+ ## class BiPatternEruby
793
+ ## include BiPatternEnhancer
794
+ ## end
795
+ ## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
796
+ ## list = ['<a>', 'b&b', '"c"']
797
+ ## print eruby.result(binding())
798
+ ##
799
+ ## ## output
800
+ ## <a> : &lt;a&gt;
801
+ ## <a> : &lt;a&gt;
802
+ ## b&b : b&amp;b
803
+ ## b&b : b&amp;b
804
+ ## "c" : &quot;c&quot;
805
+ ## "c" : &quot;c&quot;
806
+ ##
807
+ ## this is language independent.
808
+ ##
809
+ module BiPatternEnhancer
810
+
811
+ def self.desc # :nodoc:
812
+ "another embedded expression pattern (default '\[= =\]')."
813
+ end
814
+
815
+ def initialize(input, properties={})
816
+ self.bipattern = properties[:bipattern] # or '\$\{ \}'
817
+ super
818
+ end
819
+
820
+ ## when pat is nil then '\[= =\]' is used
821
+ def bipattern=(pat) # :nodoc:
822
+ @bipattern = pat || '\[= =\]'
823
+ pre, post = @bipattern.split()
824
+ @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
825
+ end
826
+
827
+ def add_text(src, text)
828
+ return unless text
829
+ text.scan(@bipattern_regexp) do |txt, indicator, code|
830
+ super(src, txt)
831
+ add_expr(src, code, '=' + indicator)
832
+ end
833
+ rest = $' || text
834
+ super(src, rest)
835
+ end
836
+
837
+ end
838
+
839
+
840
+ ##
841
+ ## regards lines starting with '%' as program code
842
+ ##
843
+ ## this is for compatibility to eruby and ERB.
844
+ ##
845
+ ## this is language-independent.
846
+ ##
847
+ module PercentLineEnhancer
848
+
849
+ def self.desc # :nodoc:
850
+ "regard lines starting with '%' as program code"
851
+ end
852
+
853
+ PERCENT_LINE_PATTERN = /(.*?)^\%(.*?\r?\n)/m
854
+
855
+ def add_text(src, text)
856
+ text.scan(PERCENT_LINE_PATTERN) do |txt, line|
857
+ super(src, txt)
858
+ if line[0] == ?%
859
+ super(src, line)
860
+ else
861
+ add_stmt(src, line)
862
+ end
863
+ end
864
+ rest = $' || text
865
+ super(src, rest)
866
+ end
867
+
868
+ end
869
+
870
+
871
+ ##
872
+ ## [experimental] allow header and footer in eRuby script
873
+ ##
874
+ ## ex.
875
+ ## ====================
876
+ ## ## without header and footer
877
+ ## $ cat ex1.eruby
878
+ ## <% def list_items(list) %>
879
+ ## <% for item in list %>
880
+ ## <li><%= item %></li>
881
+ ## <% end %>
882
+ ## <% end %>
883
+ ##
884
+ ## $ erubis -s ex1.eruby
885
+ ## _buf = []; def list_items(list)
886
+ ## ; for item in list
887
+ ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
888
+ ## '; end
889
+ ## ; end
890
+ ## ;
891
+ ## _buf.join
892
+ ##
893
+ ## ## with header and footer
894
+ ## $ cat ex2.eruby
895
+ ## <!--#header:
896
+ ## def list_items(list)
897
+ ## #-->
898
+ ## <% for item in list %>
899
+ ## <li><%= item %></li>
900
+ ## <% end %>
901
+ ## <!--#footer:
902
+ ## end
903
+ ## #-->
904
+ ##
905
+ ## $ erubis -s -c HeaderFooterEruby ex4.eruby
906
+ ##
907
+ ## def list_items(list)
908
+ ## _buf = []; _buf << '
909
+ ## '; for item in list
910
+ ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
911
+ ## '; end
912
+ ## ; _buf << '
913
+ ## ';
914
+ ## _buf.join
915
+ ## end
916
+ ##
917
+ ## ====================
918
+ ##
919
+ ## this is language-independent.
920
+ ##
921
+ module HeaderFooterEnhancer
922
+
923
+ def self.desc # :nodoc:
924
+ "allow header/footer in document (ex. '<!--#header: #-->')"
925
+ end
926
+
927
+ HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
928
+
929
+ def add_text(src, text)
930
+ text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
931
+ flag_trim = @trim && lspace && rspace
932
+ super(src, txt)
933
+ content = "#{lspace}#{content}#{rspace}" if flag_trim
934
+ super(src, lspace) if !flag_trim && lspace
935
+ instance_variable_set("@#{word}", content)
936
+ super(src, rspace) if !flag_trim && rspace
937
+ end
938
+ rest = $' || text
939
+ super(src, rest)
940
+ end
941
+
942
+ attr_accessor :header, :footer
943
+
944
+ def compile(input)
945
+ source = super
946
+ return @src = "#{@header}#{source}#{@footer}"
947
+ end
948
+
949
+ end
950
+
951
+
952
+ end
953
+ #--end of require 'erubis/enhancer'
954
+ #require 'erubis/tiny'
955
+ #--begin of require 'erubis/engine/eruby'
956
+ ##
957
+ ## $Rev: 21 $
958
+ ## $Release: 2.0.0 $
959
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
960
+ ##
961
+
962
+ #--already included require 'erubis/engine'
963
+ #--already included require 'erubis/enhancer'
964
+
965
+
966
+ module Erubis
967
+
968
+
969
+ ##
970
+ ## engine for Ruby
971
+ ##
972
+ class Eruby < Engine
973
+ #include StringBufferEnhancer
974
+ include ArrayBufferEnhancer
975
+
976
+ def self.supported_properties() # :nodoc:
977
+ return super
978
+ end
979
+
980
+ def escape_text(text)
981
+ text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
982
+ end
983
+
984
+ def escaped_expr(code)
985
+ @escape ||= "Erubis::XmlHelper.escape_xml"
986
+ return "#{@escape}(#{code})"
987
+ end
988
+
989
+ #--
990
+ #def add_preamble(src)
991
+ # src << "_buf = [];"
992
+ #end
993
+ #++
994
+
995
+ def add_text(src, text)
996
+ src << " _buf << '" << escape_text(text) << "';" unless text.empty?
997
+ end
998
+
999
+ def add_stmt(src, code)
1000
+ #src << code << ';'
1001
+ src << code
1002
+ src << ';' unless code[-1] == ?\n
1003
+ end
1004
+
1005
+ def add_expr_literal(src, code)
1006
+ src << ' _buf << (' << code << ').to_s;'
1007
+ end
1008
+
1009
+ def add_expr_escaped(src, code)
1010
+ src << ' _buf << ' << escaped_expr(code) << ';'
1011
+ end
1012
+
1013
+ def add_expr_debug(src, code)
1014
+ code.strip!
1015
+ s = (code.dump =~ /\A"(.*)"\z/) && $1
1016
+ src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
1017
+ end
1018
+
1019
+ #--
1020
+ #def add_postamble(src)
1021
+ # src << "\n_buf.join\n"
1022
+ #end
1023
+ #++
1024
+
1025
+ end
1026
+
1027
+
1028
+ ##
1029
+ ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
1030
+ ##
1031
+ class EscapedEruby < Eruby
1032
+ include EscapeEnhancer
1033
+ end
1034
+
1035
+
1036
+ ##
1037
+ ## sanitize expression (<%= ... %>) by default
1038
+ ##
1039
+ ## this is equivalent to EscapedEruby and is prepared only for compatibility.
1040
+ ##
1041
+ class XmlEruby < Eruby
1042
+ include EscapeEnhancer
1043
+ end
1044
+
1045
+
1046
+ end
1047
+ #--end of require 'erubis/engine/eruby'
1048
+ #require 'erubis/engine/enhanced' # enhanced eruby engines
1049
+ #require 'erubis/engine/optimized' # generates optimized ruby code
1050
+ #require 'erubis/engine/ephp'
1051
+ #require 'erubis/engine/ec'
1052
+ #require 'erubis/engine/ejava'
1053
+ #require 'erubis/engine/escheme'
1054
+ #require 'erubis/engine/eperl'
1055
+ #require 'erubis/engine/ejavascript'
1056
+
1057
+
1058
+ #--begin of require 'erubis/local-setting'
1059
+ ##
1060
+ ## $Rev: 13 $
1061
+ ## $Release: 2.0.0 $
1062
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1063
+ ##
1064
+
1065
+ ##
1066
+ ## you can add site-local settings here.
1067
+ ## this files is 'require'd by erubis.rb
1068
+ ##
1069
+ #--end of require 'erubis/local-setting'
1070
+ #--end of require 'erubis'
1071
+ #--begin of require 'erubis/tiny'
1072
+ ##
1073
+ ## $Rev: 21 $
1074
+ ## $Release: 2.0.0 $
1075
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1076
+ ##
1077
+
1078
+ module Erubis
1079
+
1080
+ ##
1081
+ ## tiny and the simplest implementation of eRuby
1082
+ ##
1083
+ ## ex.
1084
+ ## eruby = TinyEruby.new(File.read('example.rhtml'))
1085
+ ## print eruby.src # print ruby code
1086
+ ## print eruby.result(binding()) # eval ruby code with Binding object
1087
+ ## print eruby.evalute(context) # eval ruby code with context object
1088
+ ##
1089
+ class TinyEruby
1090
+
1091
+ def initialize(input)
1092
+ @src = compile(input)
1093
+ end
1094
+ attr_reader :src
1095
+
1096
+ EMBEDDED_PATTERN = /(.*?)<%(=+|\#)?(.*?)-?%>/m
1097
+
1098
+ def compile(input)
1099
+ src = "_buf = [];" # preamble
1100
+ input.scan(EMBEDDED_PATTERN) do |text, indicator, code|
1101
+ src << " _buf << '" << escape_text(text) << "';"
1102
+ if !indicator # <% %>
1103
+ src << code << ";"
1104
+ elsif indicator[0] == ?\# # <%# %>
1105
+ n = code.count("\n")
1106
+ add_stmt(src, "\n" * n)
1107
+ else # <%= %>
1108
+ src << " _buf << (" << code << ").to_s;"
1109
+ end
1110
+ end
1111
+ rest = $' || input
1112
+ src << " _buf << '" << escape_text(rest) << "';"
1113
+ src << "\n_buf.join\n" # postamble
1114
+ return src
1115
+ end
1116
+
1117
+ def escape_text(text)
1118
+ return text.gsub!(/['\\]/, '\\\\\&') || text
1119
+ end
1120
+
1121
+ def result(binding=TOPLEVEL_BINDING)
1122
+ eval @src, binding
1123
+ end
1124
+
1125
+ def evaluate(context=Object.new)
1126
+ if context.is_a?(Hash)
1127
+ obj = Object.new
1128
+ context.each do |k, v| obj.instance_variable_set("@#{k}", v) end
1129
+ context = obj
1130
+ end
1131
+ context.instance_eval @src
1132
+ end
1133
+
1134
+ end
1135
+
1136
+ end
1137
+ #--end of require 'erubis/tiny'
1138
+ #--begin of require 'erubis/engine/enhanced'
1139
+ ##
1140
+ ## $Rev: 19 $
1141
+ ## $Release: 2.0.0 $
1142
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1143
+ ##
1144
+
1145
+ #--already included require 'erubis/enhancer'
1146
+ #--already included require 'erubis/engine/eruby'
1147
+
1148
+
1149
+ module Erubis
1150
+
1151
+
1152
+ #--
1153
+ ## moved to engine/ruby.rb
1154
+ #class EscapedEruby < Eruby
1155
+ # include EscapeEnhancer
1156
+ #end
1157
+ #++
1158
+
1159
+
1160
+ #--
1161
+ ### (obsolete)
1162
+ #class FastEruby < Eruby
1163
+ # include FastEnhancer
1164
+ #end
1165
+ #++
1166
+
1167
+
1168
+ class StdoutEruby < Eruby
1169
+ include StdoutEnhancer
1170
+ end
1171
+
1172
+
1173
+ class PrintOutEruby < Eruby
1174
+ include PrintOutEnhancer
1175
+ end
1176
+
1177
+
1178
+ class PrintEnabledEruby < Eruby
1179
+ include PrintEnabledEnhancer
1180
+ end
1181
+
1182
+
1183
+ class ArrayEruby < Eruby
1184
+ include ArrayEnhancer
1185
+ end
1186
+
1187
+
1188
+ class ArrayBufferEruby < Eruby
1189
+ include ArrayBufferEnhancer
1190
+ end
1191
+
1192
+
1193
+ class StringBufferEruby < Eruby
1194
+ include StringBufferEnhancer
1195
+ end
1196
+
1197
+
1198
+ class StringIOEruby < Eruby
1199
+ include StringIOEnhancer
1200
+ end
1201
+
1202
+
1203
+ class NoTextEruby < Eruby
1204
+ include NoTextEnhancer
1205
+ end
1206
+
1207
+
1208
+ class SimplifiedEruby < Eruby
1209
+ include SimplifyEnhancer
1210
+ end
1211
+
1212
+
1213
+ class StdoutSimplifiedEruby < Eruby
1214
+ include StdoutEnhancer
1215
+ include SimplifyEnhancer
1216
+ end
1217
+
1218
+
1219
+ class PrintOutSimplifiedEruby < Eruby
1220
+ include PrintOutEnhancer
1221
+ include SimplifyEnhancer
1222
+ end
1223
+
1224
+
1225
+ class BiPatternEruby < Eruby
1226
+ include BiPatternEnhancer
1227
+ end
1228
+
1229
+
1230
+ class PercentLineEruby < Eruby
1231
+ include PercentLineEnhancer
1232
+ end
1233
+
1234
+
1235
+ class HeaderFooterEruby < Eruby
1236
+ include HeaderFooterEnhancer
1237
+ end
1238
+
1239
+
1240
+ end
1241
+ #--end of require 'erubis/engine/enhanced'
1242
+ #--begin of require 'erubis/engine/optimized'
1243
+ ##
1244
+ ## $Rev: 21 $
1245
+ ## $Release: 2.0.0 $
1246
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1247
+ ##
1248
+
1249
+
1250
+ #--already included require 'erubis/engine/eruby'
1251
+
1252
+
1253
+ module Erubis
1254
+
1255
+
1256
+ ##
1257
+ ## Eruby class which generates optimized ruby code
1258
+ ##
1259
+ class OptimizedEruby < Engine # Eruby
1260
+
1261
+ def self.supported_properties() # :nodoc:
1262
+ return super
1263
+ end
1264
+
1265
+ def initialize(input, properties={})
1266
+ @initialized = false
1267
+ @prev_is_expr = false
1268
+ super
1269
+ end
1270
+
1271
+ protected
1272
+
1273
+ def escape_text(text)
1274
+ text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
1275
+ end
1276
+
1277
+ def escaped_expr(code)
1278
+ @escape ||= 'Erubis::XmlHelper.escape_xml'
1279
+ return "#{@escape}(#{code})"
1280
+ end
1281
+
1282
+ def switch_to_expr(src)
1283
+ return if @prev_is_expr
1284
+ @prev_is_expr = true
1285
+ src << ' _buf'
1286
+ end
1287
+
1288
+ def switch_to_stmt(src)
1289
+ return unless @prev_is_expr
1290
+ @prev_is_expr = false
1291
+ src << ';'
1292
+ end
1293
+
1294
+ def add_preamble(src)
1295
+ #@initialized = false
1296
+ #@prev_is_expr = false
1297
+ end
1298
+
1299
+ def add_text(src, text)
1300
+ return if text.empty?
1301
+ if @initialized
1302
+ switch_to_expr(src)
1303
+ src << " << '" << escape_text(text) << "'"
1304
+ else
1305
+ src << "_buf = '" << escape_text(text) << "';"
1306
+ @initialized = true
1307
+ end
1308
+ end
1309
+
1310
+ def add_stmt(src, code)
1311
+ switch_to_stmt(src) if @initialized
1312
+ #super
1313
+ src << code
1314
+ src << ';' unless code[-1] == ?\n
1315
+ end
1316
+
1317
+ def add_expr_literal(src, code)
1318
+ unless @initialized; src << "_buf = ''"; @initialized = true; end
1319
+ switch_to_expr(src)
1320
+ src << " << (" << code << ").to_s"
1321
+ end
1322
+
1323
+ def add_expr_escaped(src, code)
1324
+ unless @initialized; src << "_buf = ''"; @initialized = true; end
1325
+ switch_to_expr(src)
1326
+ src << " << " << escaped_expr(code)
1327
+ end
1328
+
1329
+ def add_expr_debug(src, code)
1330
+ code.strip!
1331
+ s = (code.dump =~ /\A"(.*)"\z/) && $1
1332
+ src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
1333
+ end
1334
+
1335
+ def add_postamble(src)
1336
+ #super if @initialized
1337
+ src << "\n_buf\n" if @initialized
1338
+ end
1339
+
1340
+ end # end of class OptimizedEruby
1341
+
1342
+
1343
+ ##
1344
+ ## XmlEruby class which generates optimized ruby code
1345
+ ##
1346
+ class OptimizedXmlEruby < OptimizedEruby
1347
+ include EscapeEnhancer
1348
+
1349
+ def add_expr_debug(src, code)
1350
+ switch_to_stmt(src) if indicator == '===' && !@initialized
1351
+ super
1352
+ end
1353
+
1354
+ end # end of class OptimizedXmlEruby
1355
+
1356
+ end
1357
+ #--end of require 'erubis/engine/optimized'
1358
+ #--already included require 'erubis/engine/eruby'
1359
+ #--begin of require 'erubis/engine/ephp'
1360
+ ##
1361
+ ## $Rev: 19 $
1362
+ ## $Release: 2.0.0 $
1363
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1364
+ ##
1365
+
1366
+ #--already included require 'erubis/engine'
1367
+ #--already included require 'erubis/enhancer'
1368
+
1369
+
1370
+ module Erubis
1371
+
1372
+
1373
+ ##
1374
+ ## engine for PHP
1375
+ ##
1376
+ class Ephp < Engine
1377
+
1378
+ def self.supported_properties() # :nodoc:
1379
+ return super
1380
+ end
1381
+
1382
+ #--
1383
+ #def add_preamble(src)
1384
+ #end
1385
+ #++
1386
+
1387
+ def escape_text(text)
1388
+ return text.gsub!(/<\?xml\b/, '<<?php ?>?xml') || text
1389
+ end
1390
+
1391
+ def add_text(src, text)
1392
+ src << escape_text(text)
1393
+ end
1394
+
1395
+ def escaped_expr(code)
1396
+ @escape ||= 'htmlspecialchars'
1397
+ return "#{@escape}(#{code.strip})"
1398
+ end
1399
+
1400
+ def add_expr_literal(src, code)
1401
+ src << "<?php echo #{code.strip}; ?>"
1402
+ end
1403
+
1404
+ def add_expr_escaped(src, code)
1405
+ src << "<?php echo #{escaped_expr(code)}; ?>"
1406
+ end
1407
+
1408
+ def add_expr_debug(src, code)
1409
+ code.strip!
1410
+ s = code.gsub(/\'/, "\\'")
1411
+ src << "<?php error_log('*** debug: #{s}='.(#{code}), 0); ?>"
1412
+ end
1413
+
1414
+ def add_stmt(src, code)
1415
+ src << "<?php"
1416
+ src << " " if code[0] != ?\ #
1417
+ if code[-1] == ?\n
1418
+ code.chomp!
1419
+ src << code << "?>\n"
1420
+ else
1421
+ src << code << "?>"
1422
+ end
1423
+ end
1424
+
1425
+ #--
1426
+ #def add_postamble(src)
1427
+ #end
1428
+ #++
1429
+
1430
+ end
1431
+
1432
+
1433
+ class EscapedEphp < Ephp
1434
+ include EscapeEnhancer
1435
+ end
1436
+
1437
+
1438
+ #class XmlEphp < Ephp
1439
+ # include EscapeEnhancer
1440
+ #end
1441
+
1442
+
1443
+ end
1444
+ #--end of require 'erubis/engine/ephp'
1445
+ #--begin of require 'erubis/engine/ec'
1446
+ ##
1447
+ ## $Rev: 21 $
1448
+ ## $Release: 2.0.0 $
1449
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1450
+ ##
1451
+
1452
+ #--already included require 'erubis/engine'
1453
+ #--already included require 'erubis/enhancer'
1454
+
1455
+
1456
+ module Erubis
1457
+
1458
+
1459
+ ##
1460
+ ## engine for C
1461
+ ##
1462
+ class Ec < Engine
1463
+
1464
+ def self.supported_properties() # :nodoc:
1465
+ list = super
1466
+ list << [:indent, '', "indent spaces (ex. ' ')"]
1467
+ list << [:out, 'stdout', "output file pointer name"]
1468
+ return list
1469
+ end
1470
+
1471
+ def initialize(input, properties={})
1472
+ @indent = properties[:indent] || ''
1473
+ @out = properties[:out] || 'stdout'
1474
+ super
1475
+ end
1476
+
1477
+ def add_preamble(src)
1478
+ src << "#line 1 \"#{self.filename}\"\n" if self.filename
1479
+ end
1480
+
1481
+ def escape_text(text)
1482
+ @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
1483
+ text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] }
1484
+ return text
1485
+ end
1486
+
1487
+ def escaped_expr(code)
1488
+ @escape ||= "escape"
1489
+ code.strip!
1490
+ if code =~ /\A(\".*?\")\s*,\s*(.*)/
1491
+ return "#{$1}, #{@escape}(#{$2})"
1492
+ else
1493
+ return "#{@escape}(#{code})"
1494
+ end
1495
+ end
1496
+
1497
+ def add_text(src, text)
1498
+ return if text.empty?
1499
+ src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
1500
+ src << "fputs("
1501
+ i = 0
1502
+ text.each_line do |line|
1503
+ src << "\n" << @indent << ' ' if i > 0
1504
+ i += 1
1505
+ src << '"' << escape_text(line) << '"'
1506
+ end
1507
+ src << ", #{@out});" #<< (text[-1] == ?\n ? "\n" : "")
1508
+ src << "\n" if text[-1] == ?\n
1509
+ end
1510
+
1511
+ def add_stmt(src, code)
1512
+ src << code
1513
+ end
1514
+
1515
+ def add_expr_literal(src, code)
1516
+ src << @indent if src.empty? || src[-1] == ?\n
1517
+ src << " fprintf(#{@out}, " << code.strip << ');'
1518
+ end
1519
+
1520
+ def add_expr_escaped(src, code)
1521
+ src << @indent if src.empty? || src[-1] == ?\n
1522
+ src << " fprintf(#{@out}, " << escaped_expr(code) << ');'
1523
+ end
1524
+
1525
+ def add_expr_debug(src, code)
1526
+ code.strip!
1527
+ s = nil
1528
+ if code =~ /\A\".*?\"\s*,\s*(.*)/
1529
+ s = $1.gsub(/[%"]/, '\\\1') + '='
1530
+ end
1531
+ src << @indent if src.empty? || src[-1] == ?\n
1532
+ src << " fprintf(stderr, \"*** debug: #{s}\" #{code});"
1533
+ end
1534
+
1535
+ def add_postamble(src)
1536
+ end
1537
+
1538
+ end
1539
+
1540
+
1541
+ class EscapedEc < Ec
1542
+ include EscapeEnhancer
1543
+ end
1544
+
1545
+
1546
+ #class XmlEc < Ec
1547
+ # include EscapeEnhancer
1548
+ #end
1549
+
1550
+
1551
+ end
1552
+ #--end of require 'erubis/engine/ec'
1553
+ #--begin of require 'erubis/engine/ejava'
1554
+ ##
1555
+ ## $Rev: 21 $
1556
+ ## $Release: 2.0.0 $
1557
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1558
+ ##
1559
+
1560
+ #--already included require 'erubis/engine'
1561
+ #--already included require 'erubis/enhancer'
1562
+
1563
+
1564
+ module Erubis
1565
+
1566
+
1567
+ ##
1568
+ ## engine for Java
1569
+ ##
1570
+ class Ejava < Engine
1571
+
1572
+ def self.supported_properties() # :nodoc:
1573
+ list = super
1574
+ list << [:indent, '', "indent spaces (ex. ' ')"]
1575
+ list << [:buf, '_buf', "output buffer name"]
1576
+ list << [:bufclass, 'StringBuffer', "output buffer class (ex. 'StringBuilder')"]
1577
+ return list
1578
+ end
1579
+
1580
+ def initialize(input, properties={})
1581
+ @indent = properties[:indent] || ''
1582
+ @buf = properties[:buf] || '_buf'
1583
+ @bufclass = properties[:bufclass] || 'StringBuffer'
1584
+ super
1585
+ end
1586
+
1587
+ def add_preamble(src)
1588
+ src << "#{@indent}#{@bufclass} #{@buf} = new #{@bufclass}();"
1589
+ end
1590
+
1591
+ def escape_text(text)
1592
+ @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
1593
+ return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
1594
+ end
1595
+
1596
+ #--
1597
+ #def escaped_expr(code)
1598
+ # @escape ||= 'escape'
1599
+ # return "#{@escape}(#{code.strip})"
1600
+ #end
1601
+ #++
1602
+
1603
+ def add_text(src, text)
1604
+ return if text.empty?
1605
+ src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
1606
+ src << @buf << ".append("
1607
+ i = 0
1608
+ text.each_line do |line|
1609
+ src << "\n" << @indent << ' + ' if i > 0
1610
+ i += 1
1611
+ src << '"' << escape_text(line) << '"'
1612
+ end
1613
+ src << ");" << (text[-1] == ?\n ? "\n" : "")
1614
+ end
1615
+
1616
+ def add_stmt(src, code)
1617
+ src << code
1618
+ end
1619
+
1620
+ def add_expr_literal(src, code)
1621
+ src << @indent if src.empty? || src[-1] == ?\n
1622
+ src << ' ' << @buf << '.append(' << code.strip << ');'
1623
+ end
1624
+
1625
+ def add_expr_escaped(src, code)
1626
+ src << @indent if src.empty? || src[-1] == ?\n
1627
+ src << ' ' << @buf << '.append(' << escaped_expr(code) << ');'
1628
+ end
1629
+
1630
+ def add_expr_debug(src, code)
1631
+ code.strip!
1632
+ src << @indent if src.empty? || src[-1] == ?\n
1633
+ src << " System.err.println(\"*** debug: #{code}=\"+(#{code}));"
1634
+ end
1635
+
1636
+ def add_postamble(src)
1637
+ src << "\n" if src[-1] == ?;
1638
+ src << @indent << "return " << @buf << ".toString();\n"
1639
+ end
1640
+
1641
+ end
1642
+
1643
+
1644
+ class EscapedEjava < Ejava
1645
+ include EscapeEnhancer
1646
+ end
1647
+
1648
+
1649
+ #class XmlEjava < Ejava
1650
+ # include EscapeEnhancer
1651
+ #end
1652
+
1653
+
1654
+ end
1655
+ #--end of require 'erubis/engine/ejava'
1656
+ #--begin of require 'erubis/engine/escheme'
1657
+ ##
1658
+ ## $Rev: 21 $
1659
+ ## $Release: 2.0.0 $
1660
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1661
+ ##
1662
+
1663
+ #--already included require 'erubis/engine'
1664
+ #--already included require 'erubis/enhancer'
1665
+
1666
+
1667
+ module Erubis
1668
+
1669
+
1670
+ ##
1671
+ ## engine for Scheme
1672
+ ##
1673
+ class Escheme < Engine
1674
+
1675
+ def self.supported_properties() # :nodoc:
1676
+ list = super
1677
+ list << [:func, '_add', "function name (ex. 'display')"]
1678
+ return list
1679
+ end
1680
+
1681
+ def initialize(input, properties={})
1682
+ @func = properties[:func] || '_add' # or 'display'
1683
+ super
1684
+ end
1685
+
1686
+ def add_preamble(src)
1687
+ return unless @func == '_add'
1688
+ src << "(let ((_buf '())) " + \
1689
+ "(define (_add x) (set! _buf (cons x _buf))) "
1690
+ #src << "(let* ((_buf '())" + \
1691
+ # " (_add (lambda (x) (set! _buf (cons x _buf))))) "
1692
+ end
1693
+
1694
+ def escape_text(text)
1695
+ @table_ ||= { '"'=>'\\"', '\\'=>'\\\\' }
1696
+ text.gsub!(/["\\]/) { |m| @table_[m] }
1697
+ return text
1698
+ end
1699
+
1700
+ def escaped_expr(code)
1701
+ @escape ||= 'escape'
1702
+ return "(#{@escape} #{code.strip})"
1703
+ end
1704
+
1705
+ def add_text(src, text)
1706
+ return if text.empty?
1707
+ t = escape_text(text)
1708
+ if t[-1] == ?\n
1709
+ t[-1, 1] = ''
1710
+ src << "(#{@func} \"" << t << "\\n\")\n"
1711
+ else
1712
+ src << "(#{@func} \"" << t << '")'
1713
+ end
1714
+ end
1715
+
1716
+ def add_stmt(src, code)
1717
+ src << code
1718
+ end
1719
+
1720
+ def add_expr_literal(src, code)
1721
+ src << "(#{@func} " << code.strip << ')'
1722
+ end
1723
+
1724
+ def add_expr_escaped(src, code)
1725
+ src << "(#{@func} " << escaped_expr(code) << ')'
1726
+ end
1727
+
1728
+ def add_expr_debug(src, code)
1729
+ s = (code.strip! || code).gsub(/\"/, '\\"')
1730
+ src << "(display \"*** debug: #{s}=\")(display #{code.strip})(display \"\\n\")"
1731
+ end
1732
+
1733
+ def add_postamble(src)
1734
+ return unless @func == '_add'
1735
+ src << "\n" unless src[-1] == ?\n
1736
+ src << " (reverse _buf))\n"
1737
+ end
1738
+
1739
+ end
1740
+
1741
+
1742
+ class EscapedEscheme < Escheme
1743
+ include EscapeEnhancer
1744
+ end
1745
+
1746
+
1747
+ #class XmlEscheme < Escheme
1748
+ # include EscapeEnhancer
1749
+ #end
1750
+
1751
+
1752
+ end
1753
+ #--end of require 'erubis/engine/escheme'
1754
+ #--begin of require 'erubis/engine/eperl'
1755
+ ##
1756
+ ## $Rev: 19 $
1757
+ ## $Release: 2.0.0 $
1758
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1759
+ ##
1760
+
1761
+ #--already included require 'erubis/engine'
1762
+ #--already included require 'erubis/enhancer'
1763
+
1764
+
1765
+ module Erubis
1766
+
1767
+
1768
+ ##
1769
+ ## engine for Perl
1770
+ ##
1771
+ class Eperl < Engine
1772
+
1773
+ def self.supported_properties() # :nodoc:
1774
+ list = super
1775
+ list << [:func, 'print', "function name"]
1776
+ return list
1777
+ end
1778
+
1779
+ def initialize(input, properties={})
1780
+ @func = properties[:func] || 'print'
1781
+ super
1782
+ end
1783
+
1784
+ def add_preamble(src)
1785
+ end
1786
+
1787
+ def escape_text(text)
1788
+ return text.gsub!(/['\\]/, '\\\\\&') || text
1789
+ end
1790
+
1791
+ def add_text(src, text)
1792
+ src << @func << "('" << escape_text(text) << "'); " unless text.empty?
1793
+ end
1794
+
1795
+ #--
1796
+ #def escaped_expr(code)
1797
+ # @escape ||= 'escape'
1798
+ # return "escape(#{code.strip})"
1799
+ #end
1800
+ #++
1801
+
1802
+ def add_expr_literal(src, code)
1803
+ src << @func << "(" << code.strip << "); "
1804
+ end
1805
+
1806
+ def add_expr_escaped(src, code)
1807
+ src << @func << "(" << escaped_expr(code) << "); "
1808
+ end
1809
+
1810
+ def add_expr_debug(src, code)
1811
+ code.strip!
1812
+ s = code.gsub(/\'/, "\\'")
1813
+ src << @func << "('*** debug: #{code}=', #{code}, \"\\n\");"
1814
+ end
1815
+
1816
+ def add_stmt(src, code)
1817
+ src << code
1818
+ end
1819
+
1820
+ def add_postamble(src)
1821
+ src << "\n" unless src[-1] == ?\n
1822
+ end
1823
+
1824
+ end
1825
+
1826
+
1827
+ class EscapedEperl < Eperl
1828
+ include EscapeEnhancer
1829
+ end
1830
+
1831
+
1832
+ #class XmlEperl < Eperl
1833
+ # include EscapeEnhancer
1834
+ #end
1835
+
1836
+
1837
+ end
1838
+ #--end of require 'erubis/engine/eperl'
1839
+ #--begin of require 'erubis/engine/ejavascript'
1840
+ ##
1841
+ ## $Rev: 21 $
1842
+ ## $Release: 2.0.0 $
1843
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
1844
+ ##
1845
+
1846
+ #--already included require 'erubis/engine'
1847
+ #--already included require 'erubis/enhancer'
1848
+
1849
+
1850
+ module Erubis
1851
+
1852
+
1853
+ ##
1854
+ ## engine for JavaScript
1855
+ ##
1856
+ class Ejavascript < Engine
1857
+
1858
+ def self.supported_properties() # :nodoc:
1859
+ list = super
1860
+ #list << [:indent, '', "indent spaces (ex. ' ')"]
1861
+ #list << [:buf, '_buf', "output buffer name"]
1862
+ return list
1863
+ end
1864
+
1865
+ def initialize(input, properties={})
1866
+ @indent = properties[:indent] || ''
1867
+ @buf = properties[:out] || '_buf'
1868
+ #@bufclass = properties[:outclass] || 'StringBuffer'
1869
+ super
1870
+ end
1871
+
1872
+ def add_preamble(src)
1873
+ src << "#{@indent}var #{@buf} = [];"
1874
+ end
1875
+
1876
+ def escape_text(text)
1877
+ @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n\\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
1878
+ return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
1879
+ end
1880
+
1881
+ #--
1882
+ #def escaped_expr(code)
1883
+ # @escape ||= 'escape'
1884
+ # return "#{@escape}(#{code.strip})"
1885
+ #end
1886
+ #++
1887
+
1888
+ def add_indent(src, indent)
1889
+ src << (src.empty? || src[-1] == ?\n ? indent : ' ')
1890
+ end
1891
+
1892
+ def add_text(src, text)
1893
+ return if text.empty?
1894
+ add_indent(src, @indent)
1895
+ src << @buf << '.push("'
1896
+ s = escape_text(text)
1897
+ if s[-1] == ?\n
1898
+ s[-2, 2] = ''
1899
+ src << s << "\");\n"
1900
+ else
1901
+ src << s << "\");"
1902
+ end
1903
+ end
1904
+
1905
+ def add_stmt(src, code)
1906
+ src << code
1907
+ end
1908
+
1909
+ def add_expr_literal(src, code)
1910
+ add_indent(src, @indent)
1911
+ src << @buf << '.push(' << code.strip << ');'
1912
+ end
1913
+
1914
+ def add_expr_escaped(src, code)
1915
+ add_indent(src, @indent)
1916
+ src << @buf << '.push(' << escaped_expr(code) << ');'
1917
+ end
1918
+
1919
+ def add_expr_debug(src, code)
1920
+ add_indent(src, @indent)
1921
+ code.strip!
1922
+ src << "alert(\"*** debug: #{code}=\"+(#{code}));"
1923
+ end
1924
+
1925
+ def add_postamble(src)
1926
+ src << "\n" if src[-1] == ?;
1927
+ src << @indent << 'document.write(' << @buf << ".join(\"\"));\n"
1928
+ end
1929
+
1930
+ end
1931
+
1932
+
1933
+ class EscapedEjavascript < Ejavascript
1934
+ include EscapeEnhancer
1935
+ end
1936
+
1937
+
1938
+ #class XmlEjavascript < Ejavascript
1939
+ # include EscapeEnhancer
1940
+ #end
1941
+
1942
+
1943
+ end
1944
+ #--end of require 'erubis/engine/ejavascript'
1945
+
1946
+
1947
+ module Erubis
1948
+
1949
+
1950
+ Ejs = Ejavascript
1951
+ EscapedEjs = EscapedEjavascript
1952
+
1953
+
1954
+ class CommandOptionError < ErubisError
1955
+ end
1956
+
1957
+
1958
+ ##
1959
+ ## main class of command
1960
+ ##
1961
+ ## ex.
1962
+ ## Main.main(ARGV)
1963
+ ##
1964
+ class Main
1965
+
1966
+ def self.main(argv=ARGV)
1967
+ status = 0
1968
+ begin
1969
+ Main.new.execute(ARGV)
1970
+ rescue CommandOptionError => ex
1971
+ $stderr.puts ex.message
1972
+ status = 1
1973
+ end
1974
+ exit(status)
1975
+ end
1976
+
1977
+ def initialize
1978
+ @single_options = "hvxTtSbeB"
1979
+ @arg_options = "pcrfKIlaE"
1980
+ @option_names = {
1981
+ ?h => :help,
1982
+ ?v => :version,
1983
+ ?x => :source,
1984
+ ?T => :notrim,
1985
+ ?t => :untabify,
1986
+ ?S => :intern,
1987
+ ?b => :bodyonly,
1988
+ ?B => :binding,
1989
+ ?p => :pattern,
1990
+ ?c => :class,
1991
+ ?e => :escape,
1992
+ ?r => :requires,
1993
+ ?f => :yamlfiles,
1994
+ ?K => :kanji,
1995
+ ?I => :includes,
1996
+ ?l => :lang,
1997
+ ?a => :action,
1998
+ ?E => :enhancers,
1999
+ }
2000
+ assert unless @single_options.length + @arg_options.length == @option_names.length
2001
+ (@single_options + @arg_options).each_byte do |ch|
2002
+ assert unless @option_names.key?(ch)
2003
+ end
2004
+ end
2005
+
2006
+
2007
+ def execute(argv=ARGV)
2008
+ ## parse command-line options
2009
+ options, properties = parse_argv(argv, @single_options, @arg_options)
2010
+ filenames = argv
2011
+ options[?h] = true if properties[:help]
2012
+ opts = Object.new
2013
+ arr = @option_names.collect { |ch, name| "def #{name}; @#{name}; end\n" }
2014
+ opts.instance_eval arr.join
2015
+ options.each do |ch, val|
2016
+ name = @option_names[ch]
2017
+ opts.instance_variable_set("@#{name}", val)
2018
+ end
2019
+
2020
+ ## help, version, enhancer list
2021
+ if opts.help || opts.version
2022
+ puts version() if opts.version
2023
+ puts usage() if opts.help
2024
+ puts show_properties() if opts.help
2025
+ puts show_enhancers() if opts.help
2026
+ return
2027
+ end
2028
+
2029
+ ## include path
2030
+ opts.includes.split(/,/).each do |path|
2031
+ $: << path
2032
+ end if opts.includes
2033
+
2034
+ ## require library
2035
+ opts.requires.split(/,/).each do |library|
2036
+ require library
2037
+ end if opts.requires
2038
+
2039
+ ## action
2040
+ action = opts.action
2041
+ action ||= 'compile' if opts.source
2042
+
2043
+ ## lang
2044
+ lang = opts.lang || 'ruby'
2045
+ action ||= 'compile' if opts.lang
2046
+
2047
+ ## class name of Eruby
2048
+ classname = opts.class
2049
+ klass = get_classobj(classname, lang)
2050
+
2051
+ ## kanji code
2052
+ $KCODE = opts.kanji if opts.kanji
2053
+
2054
+ ## read context values from yaml file
2055
+ yamlfiles = opts.yamlfiles
2056
+ context = load_yamlfiles(yamlfiles, opts)
2057
+
2058
+ ## properties for engine
2059
+ properties[:pattern] = opts.pattern if opts.pattern
2060
+ properties[:trim] = false if opts.notrim
2061
+ properties[:preamble] = properties[:postamble] = false if opts.bodyonly
2062
+
2063
+ ## create engine and extend enhancers
2064
+ engine = klass.new(nil, properties)
2065
+ enhancers = get_enhancers(opts.enhancers)
2066
+ enhancers.push(Erubis::EscapeEnhancer) if opts.escape
2067
+ enhancers.each do |enhancer|
2068
+ engine.extend(enhancer)
2069
+ engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
2070
+ end
2071
+
2072
+ ## compile and execute
2073
+ val = nil
2074
+ if filenames && !filenames.empty?
2075
+ filenames.each do |filename|
2076
+ test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
2077
+ engine.filename = filename
2078
+ engine.compile!(File.read(filename))
2079
+ print val if val = do_action(action, engine, context, opts)
2080
+ end
2081
+ else
2082
+ engine.filename = '(stdin)'
2083
+ engine.compile!($stdin.read())
2084
+ print val if val = do_action(action, engine, context, opts)
2085
+ end
2086
+
2087
+ end
2088
+
2089
+ private
2090
+
2091
+ def do_action(action, engine, context, opts)
2092
+ case action
2093
+ when 'compile'
2094
+ s = engine.src
2095
+ when nil, 'exec', 'execute'
2096
+ s = opts.binding ? engine.result(context) : engine.evaluate(context)
2097
+ else
2098
+ raise "*** internal error"
2099
+ end
2100
+ return s
2101
+ end
2102
+
2103
+ def usage
2104
+ command = File.basename($0)
2105
+ s = <<'END'
2106
+ erubis - embedded program compiler for multi-language
2107
+ Usage: #{command} [..options..] [file ...]
2108
+ -h, --help : help
2109
+ -v : version
2110
+ -x : compiled code
2111
+ -T : don't trim spaces around '<% %>'
2112
+ -b : body only (no preamble nor postamble)
2113
+ -e : escape (equal to '--E Escape')
2114
+ -p pattern : embedded pattern (default '<% %>')
2115
+ -l lang : compile but no execute (ruby/php/c/java/scheme/perl/js)
2116
+ -E enhancer,... : enhancer name (Escape, PercentLine, BiPattern, ...)
2117
+ -I path : library include path
2118
+ -K kanji : kanji code (euc/sjis/utf8) (default none)
2119
+ -f file.yaml : YAML file for context values (read stdin if filename is '-')
2120
+ -t : expand tab character in YAML file
2121
+ -S : convert mapping key from string to symbol in YAML file
2122
+ -B : invoke 'result(binding)' instead of 'evaluate(context)'
2123
+
2124
+ END
2125
+ # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
2126
+ # -r library : require library
2127
+ # -a : action (compile/execute)
2128
+ return s
2129
+ end
2130
+
2131
+ def show_properties
2132
+ s = "supported properties:\n"
2133
+ %w[(common) ruby php c java scheme perl javascript].each do |lang|
2134
+ list = Erubis::Engine.supported_properties
2135
+ if lang != '(common)'
2136
+ klass = Erubis.const_get("E#{lang}")
2137
+ list = klass.supported_properties - list
2138
+ end
2139
+ s << " * #{lang}\n"
2140
+ list.each do |name, default_val, desc|
2141
+ s << (" --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
2142
+ end
2143
+ end
2144
+ s << "\n"
2145
+ return s
2146
+ end
2147
+
2148
+ def show_enhancers
2149
+ s = "enhancers:\n"
2150
+ list = []
2151
+ ObjectSpace.each_object(Module) do |m| list << m end
2152
+ list.sort_by { |m| m.name }.each do |m|
2153
+ next unless m.name =~ /\AErubis::(.*)Enhancer\z/
2154
+ name = $1
2155
+ desc = m.desc
2156
+ s << (" %-13s : %s\n" % [name, desc])
2157
+ end
2158
+ return s
2159
+ end
2160
+
2161
+ def version
2162
+ release = ('$Release: 2.0.0 $' =~ /([.\d]+)/) && $1
2163
+ return release
2164
+ end
2165
+
2166
+ def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
2167
+ options = {}
2168
+ context = {}
2169
+ while argv[0] && argv[0][0] == ?-
2170
+ optstr = argv.shift
2171
+ optstr = optstr[1, optstr.length-1]
2172
+ #
2173
+ if optstr[0] == ?- # context
2174
+ unless optstr =~ /\A\-([-\w]+)(?:=(.*))?/
2175
+ raise CommandOptionError.new("-#{optstr}: invalid context value.")
2176
+ end
2177
+ name = $1; value = $2
2178
+ name = name.gsub(/-/, '_').intern
2179
+ #value = value.nil? ? true : YAML.load(value) # error, why?
2180
+ value = value.nil? ? true : YAML.load("---\n#{value}\n")
2181
+ context[name] = value
2182
+ #
2183
+ else # options
2184
+ while optstr && !optstr.empty?
2185
+ optchar = optstr[0]
2186
+ optstr[0,1] = ""
2187
+ if arg_none.include?(optchar)
2188
+ options[optchar] = true
2189
+ elsif arg_required.include?(optchar)
2190
+ arg = optstr.empty? ? argv.shift : optstr
2191
+ unless arg
2192
+ mesg = "-#{optchar.chr}: #{@option_args[optchar]} required."
2193
+ raise CommandOptionError.new(mesg)
2194
+ end
2195
+ options[optchar] = arg
2196
+ optstr = nil
2197
+ elsif arg_optional.include?(optchar)
2198
+ arg = optstr.empty? ? true : optstr
2199
+ options[optchar] = arg
2200
+ optstr = nil
2201
+ else
2202
+ raise CommandOptionError.new("-#{optchar.chr}: unknown option.")
2203
+ end
2204
+ end
2205
+ end
2206
+ #
2207
+ end # end of while
2208
+
2209
+ return options, context
2210
+ end
2211
+
2212
+ def untabify(text, width=8)
2213
+ sb = ''
2214
+ text.scan(/(.*?)\t/m) do |s, |
2215
+ len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
2216
+ sb << s << (" " * (width - len % width))
2217
+ end
2218
+ return $' ? (sb << $') : text
2219
+ end
2220
+
2221
+ def get_classobj(classname, lang)
2222
+ unless classname
2223
+ classname = lang =~ /\Axml(.*)/ ? "EscapedE#{$1}" : "E#{lang}"
2224
+ end
2225
+ begin
2226
+ klass = Erubis.const_get(classname)
2227
+ rescue NameError
2228
+ klass = nil
2229
+ end
2230
+ unless klass
2231
+ if lang
2232
+ msg = "-l #{lang}: invalid language name (class Erubis::#{classname} not found)."
2233
+ else
2234
+ msg = "-c #{classname}: invalid class name."
2235
+ end
2236
+ raise CommandOptionError.new(msg)
2237
+ end
2238
+ return klass
2239
+ end
2240
+
2241
+ def get_enhancers(enhancer_names)
2242
+ return [] unless enhancer_names
2243
+ enhancers = []
2244
+ shortname = nil
2245
+ begin
2246
+ enhancer_names.split(/,/).each do |shortname|
2247
+ enhancers << Erubis.const_get("#{shortname}Enhancer")
2248
+ end
2249
+ rescue NameError
2250
+ raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-E' to show all enhancers).")
2251
+ end
2252
+ return enhancers
2253
+ end
2254
+
2255
+ def load_yamlfiles(yamlfiles, opts)
2256
+ hash = {}
2257
+ return hash unless yamlfiles
2258
+ yamlfiles.split(/,/).each do |yamlfile|
2259
+ if yamlfile == '-'
2260
+ str = $stdin.read()
2261
+ else
2262
+ test(?f, yamlfile) or raise CommandOptionError.new("#{yamlfile}: file not found.")
2263
+ str = File.read(yamlfile)
2264
+ end
2265
+ str = yamlfile == '-' ? $stdin.read() : File.read(yamlfile)
2266
+ str = untabify(str) if opts.untabify
2267
+ ydoc = YAML.load(str)
2268
+ unless ydoc.is_a?(Hash)
2269
+ raise CommandOptionError.new("#{yamlfile}: root object is not a mapping.")
2270
+ end
2271
+ convert_mapping_key_from_string_to_symbol(ydoc) if opts.intern
2272
+ hash.update(ydoc)
2273
+ end
2274
+ context = hash
2275
+ return context
2276
+ end
2277
+
2278
+ def convert_mapping_key_from_string_to_symbol(ydoc)
2279
+ if ydoc.is_a?(Hash)
2280
+ ydoc.each do |key, val|
2281
+ ydoc[key.intern] = ydoc.delete(key) if key.is_a?(String)
2282
+ convert_mapping_key_from_string_to_symbol(val)
2283
+ end
2284
+ elsif ydoc.is_a?(Array)
2285
+ ydoc.each do |val|
2286
+ convert_mapping_key_from_string_to_symbol(val)
2287
+ end
2288
+ end
2289
+ return ydoc
2290
+ end
2291
+
2292
+ end
2293
+
2294
+ end
2295
+ #--end of require 'erubis/main'
2296
+
2297
+ Erubis::Main.main(ARGV)