erubis 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)