erubis 2.1.0 → 2.2.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 (118) hide show
  1. data/{ChangeLog → CHANGES} +139 -6
  2. data/MIT-LICENSE +20 -0
  3. data/README.txt +20 -5
  4. data/benchmark/erubybench.rb +465 -229
  5. data/benchmark/erubybench.rhtml +39 -15
  6. data/benchmark/erubybench.yaml +126 -46
  7. data/bin/erubis +2 -2
  8. data/bin/notext +3 -3
  9. data/contrib/action_view_base_rb.patch +23 -0
  10. data/contrib/erubis +466 -308
  11. data/contrib/inline-require +2 -2
  12. data/doc-api/classes/ERB.html +101 -0
  13. data/doc-api/classes/Erubis.html +59 -6
  14. data/doc-api/classes/Erubis/ArrayEnhancer.html +12 -12
  15. data/doc-api/classes/Erubis/Basic/Converter.html +61 -57
  16. data/doc-api/classes/Erubis/BiPatternEnhancer.html +14 -14
  17. data/doc-api/classes/Erubis/CGenerator.html +60 -60
  18. data/doc-api/classes/Erubis/Context.html +125 -29
  19. data/doc-api/classes/Erubis/Converter.html +73 -22
  20. data/doc-api/classes/Erubis/Engine.html +55 -39
  21. data/doc-api/classes/Erubis/EscapeEnhancer.html +6 -6
  22. data/doc-api/classes/Erubis/Evaluator.html +19 -19
  23. data/doc-api/classes/Erubis/Generator.html +16 -10
  24. data/doc-api/classes/Erubis/HeaderFooterEnhancer.html +14 -14
  25. data/doc-api/classes/Erubis/{Helper.html → Helpers.html} +5 -6
  26. data/doc-api/classes/Erubis/Helpers/RailsHelper.html +296 -0
  27. data/doc-api/classes/Erubis/JavaGenerator.html +54 -54
  28. data/doc-api/classes/Erubis/JavascriptGenerator.html +60 -60
  29. data/doc-api/classes/Erubis/Main.html +42 -30
  30. data/doc-api/classes/Erubis/NoCodeEnhancer.html +5 -5
  31. data/doc-api/classes/Erubis/NoTextEnhancer.html +7 -7
  32. data/doc-api/classes/Erubis/OptimizedEruby.html +6 -6
  33. data/doc-api/classes/Erubis/OptimizedGenerator.html +72 -72
  34. data/doc-api/classes/Erubis/OptimizedXmlEruby.html +6 -6
  35. data/doc-api/classes/Erubis/PI/Converter.html +28 -81
  36. data/doc-api/classes/Erubis/PI/Ec.html +6 -6
  37. data/doc-api/classes/Erubis/PI/Ejava.html +6 -6
  38. data/doc-api/classes/Erubis/PI/Ejavascript.html +6 -6
  39. data/doc-api/classes/Erubis/PI/Eperl.html +6 -6
  40. data/doc-api/classes/Erubis/PI/Ephp.html +6 -6
  41. data/doc-api/classes/Erubis/PI/Eruby.html +7 -7
  42. data/doc-api/classes/Erubis/PI/Escheme.html +6 -6
  43. data/doc-api/classes/Erubis/PI/TinyEruby.html +66 -79
  44. data/doc-api/classes/Erubis/PercentLineEnhancer.html +8 -8
  45. data/doc-api/classes/Erubis/PerlGenerator.html +54 -54
  46. data/doc-api/classes/Erubis/PhpGenerator.html +54 -54
  47. data/doc-api/classes/Erubis/PrintEnabledEnhancer.html +21 -21
  48. data/doc-api/classes/Erubis/PrintOutEnhancer.html +30 -30
  49. data/doc-api/classes/Erubis/RubyEvaluator.html +12 -12
  50. data/doc-api/classes/Erubis/RubyGenerator.html +9 -9
  51. data/doc-api/classes/Erubis/SimplifyEnhancer.html +7 -6
  52. data/doc-api/classes/Erubis/StdoutEnhancer.html +12 -12
  53. data/doc-api/classes/Erubis/StringBufferEnhancer.html +13 -13
  54. data/doc-api/classes/Erubis/TinyEruby.html +56 -68
  55. data/doc-api/classes/Erubis/XmlHelper.html +20 -23
  56. data/doc-api/created.rid +1 -1
  57. data/doc-api/files/{__/README_txt.html → README_txt.html} +35 -20
  58. data/doc-api/files/erubis/context_rb.html +2 -2
  59. data/doc-api/files/erubis/converter_rb.html +2 -2
  60. data/doc-api/files/erubis/engine/ec_rb.html +2 -2
  61. data/doc-api/files/erubis/engine/ejava_rb.html +2 -2
  62. data/doc-api/files/erubis/engine/ejavascript_rb.html +2 -2
  63. data/doc-api/files/erubis/engine/enhanced_rb.html +2 -2
  64. data/doc-api/files/erubis/engine/eperl_rb.html +2 -2
  65. data/doc-api/files/erubis/engine/ephp_rb.html +2 -2
  66. data/doc-api/files/erubis/engine/eruby_rb.html +2 -3
  67. data/doc-api/files/erubis/engine/escheme_rb.html +2 -2
  68. data/doc-api/files/erubis/engine/optimized_rb.html +2 -2
  69. data/doc-api/files/erubis/engine_rb.html +2 -2
  70. data/doc-api/files/erubis/enhancer_rb.html +2 -2
  71. data/doc-api/files/erubis/error_rb.html +2 -2
  72. data/doc-api/files/erubis/evaluator_rb.html +2 -2
  73. data/doc-api/files/erubis/generator_rb.html +2 -2
  74. data/doc-api/files/erubis/helper_rb.html +2 -2
  75. data/doc-api/files/erubis/{helper/rails_rb.html → helpers/rails_helper_rb.html} +6 -31
  76. data/doc-api/files/erubis/local-setting_rb.html +2 -2
  77. data/doc-api/files/erubis/main_rb.html +4 -2
  78. data/doc-api/files/erubis/tiny_rb.html +2 -2
  79. data/doc-api/files/erubis_rb.html +2 -2
  80. data/doc-api/fr_class_index.html +3 -3
  81. data/doc-api/fr_file_index.html +2 -2
  82. data/doc-api/fr_method_index.html +142 -147
  83. data/doc-api/index.html +1 -1
  84. data/doc/users-guide.html +387 -218
  85. data/lib/erubis.rb +21 -25
  86. data/lib/erubis/context.rb +34 -4
  87. data/lib/erubis/converter.rb +159 -115
  88. data/lib/erubis/engine.rb +29 -12
  89. data/lib/erubis/engine/ec.rb +2 -2
  90. data/lib/erubis/engine/ejava.rb +2 -2
  91. data/lib/erubis/engine/ejavascript.rb +2 -2
  92. data/lib/erubis/engine/enhanced.rb +2 -2
  93. data/lib/erubis/engine/eperl.rb +2 -2
  94. data/lib/erubis/engine/ephp.rb +2 -2
  95. data/lib/erubis/engine/eruby.rb +5 -6
  96. data/lib/erubis/engine/escheme.rb +2 -2
  97. data/lib/erubis/engine/optimized.rb +2 -2
  98. data/lib/erubis/enhancer.rb +33 -7
  99. data/lib/erubis/error.rb +2 -2
  100. data/lib/erubis/evaluator.rb +2 -2
  101. data/lib/erubis/generator.rb +6 -3
  102. data/lib/erubis/helper.rb +6 -23
  103. data/lib/erubis/helpers/rails_helper.rb +202 -0
  104. data/lib/erubis/local-setting.rb +4 -4
  105. data/lib/erubis/main.rb +90 -35
  106. data/lib/erubis/tiny.rb +57 -52
  107. data/test/assert-text-equal.rb +2 -2
  108. data/test/test-engines.rb +5 -5
  109. data/test/test-erubis.rb +173 -63
  110. data/test/test-main.rb +135 -27
  111. data/test/test-notext.rb +2 -2
  112. data/test/test.rb +2 -2
  113. data/test/testutil.rb +2 -2
  114. metadata +16 -16
  115. data/LGPL +0 -504
  116. data/doc-api/classes/Erubis/Helper/CachedRailsTemplate.html +0 -198
  117. data/doc-api/classes/Erubis/Helper/RailsTemplate.html +0 -366
  118. data/lib/erubis/helper/rails.rb +0 -159
@@ -1,11 +1,17 @@
1
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
- "http://www.w3.org/TR/html4/loose.dtd">
3
- <html>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
5
  <head>
5
- <title>benchmark example</title>
6
+ <title>Stock Prices</title>
6
7
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
8
+ <meta http-equiv="Content-Style-Type" content="text/css" />
9
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
10
+ <link rel="shortcut icon" href="/images/favicon.ico" />
11
+ <link rel="stylesheet" type="text/css" href="/css/style.css" media="all" />
12
+ <script type="text/javascript" src="/js/util.js"></script>
7
13
  <style type="text/css">
8
- <!--
14
+ /*<![CDATA[*/
9
15
 
10
16
  body {
11
17
  color: #333333;
@@ -24,36 +30,54 @@ thead {
24
30
  .even {
25
31
  background-color: #CCCCFF;
26
32
  }
27
- -->
33
+
34
+ .minus {
35
+ color: #FF0000;
36
+ }
37
+
38
+ /*]]>*/
28
39
  </style>
29
40
 
30
41
  </head>
31
42
 
32
43
  <body>
33
44
 
34
- <h1>Companies</h1>
45
+ <h1>Stock Prices</h1>
35
46
 
36
47
  <table>
37
48
  <thead>
38
49
  <tr>
39
- <th>index</th><th>code</th><th>name</th>
50
+ <th>#</th><th>code</th><th>name</th><th>price</th><th>change</th><th>ratio</th>
40
51
  </tr>
41
52
  </thead>
42
53
  <tbody>
43
- <% data.each_with_index do |hash, i| %>
44
- <% n = i + 1 %>
54
+ <%
55
+ n = 0
56
+ for item in list
57
+ n += 1
58
+ %>
45
59
  <tr class="<%= n % 2 == 0 ? 'even' : 'odd' %>">
46
- <td style="text-align: center">
47
- <span><%= n %></span>
60
+ <td style="text-align: center"><%= n %></td>
61
+ <td>
62
+ <a href="/stocks/<%= item['code'] %>"><%= item['code'] %></a>
48
63
  </td>
49
64
  <td>
50
- <a href="/stock/<%= hash[:code] %>"><%= hash[:code] %></a>
65
+ <a href="<%= item['url'] %>"><%= item['name'] %></a>
51
66
  </td>
52
67
  <td>
53
- <a href="<%= hash[:url] %>"><%= hash[:name] %></a>
68
+ <strong><%= item['price'] %></strong>
54
69
  </td>
70
+ <% if item['change'] < 0.0 %>
71
+ <td class="minus"><%= item['change'] %></td>
72
+ <td class="minus"><%= item['ratio'] %></td>
73
+ <% else %>
74
+ <td><%= item['change'] %></td>
75
+ <td><%= item['ratio'] %></td>
76
+ <% end %>
55
77
  </tr>
56
- <% end %>
78
+ <%
79
+ end
80
+ %>
57
81
  </tbody>
58
82
  </table>
59
83
 
@@ -1,61 +1,141 @@
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.
1
+ list:
2
+ - name: Adobe Systems
3
+ name2: Adobe Systems Inc.
15
4
  url: http://www.adobe.com
16
5
  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.
6
+ price: 39.26
7
+ change: 0.13
8
+ ratio: 0.33
9
+ - name: Advanced Micro Devices
10
+ name2: Advanced Micro Devices Inc.
11
+ url: http://www.amd.com
12
+ code: AMD
13
+ price: 16.22
14
+ change: 0.17
15
+ ratio: 1.06
16
+ - name: Amazon.com
17
+ name2: Amazon.com Inc
18
+ url: http://www.amazon.com
19
+ code: AMZN
20
+ price: 36.85
21
+ change: -0.23
22
+ ratio: -0.62
23
+ - name: Apple
24
+ name2: Apple Inc.
25
+ url: http://www.apple.com
26
+ code: AAPL
27
+ price: 85.38
28
+ change: -0.87
29
+ ratio: -1.01
30
+ - name: BEA Systems
31
+ name2: BEA Systems Inc.
27
32
  url: http://www.bea.com
28
33
  code: BEAS
29
- - name: eBay Inc.
34
+ price: 12.46
35
+ change: 0.09
36
+ ratio: 0.73
37
+ - name: CA
38
+ name2: CA, Inc.
39
+ url: http://www.ca.com
40
+ code: CA
41
+ price: 24.66
42
+ change: 0.38
43
+ ratio: 1.57
44
+ - name: Cisco Systems
45
+ name2: Cisco Systems Inc.
46
+ url: http://www.cisco.com
47
+ code: CSCO
48
+ price: 26.35
49
+ change: 0.13
50
+ ratio: 0.5
51
+ - name: Dell
52
+ name2: Dell Corp.
53
+ url: http://www.dell.com/
54
+ code: DELL
55
+ price: 23.73
56
+ change: -0.42
57
+ ratio: -1.74
58
+ - name: eBay
59
+ name2: eBay Inc.
30
60
  url: http://www.ebay.com
31
61
  code: EBAY
32
- - name: Yahoo! Inc.
33
- url: http://www.yahoo.com
34
- code: YHOO
35
- - name: Google Inc.
62
+ price: 31.65
63
+ change: -0.8
64
+ ratio: -2.47
65
+ - name: Google
66
+ name2: Google Inc.
36
67
  url: http://www.google.com
37
68
  code: GOOG
38
- - name: Hewlett-Packard Co.
69
+ price: 495.84
70
+ change: 7.75
71
+ ratio: 1.59
72
+ - name: Hewlett-Packard
73
+ name2: Hewlett-Packard Co.
39
74
  url: http://www.hp.com
40
75
  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
76
+ price: 41.69
77
+ change: -0.02
78
+ ratio: -0.05
79
+ - name: IBM
80
+ name2: International Business Machines Corp.
81
+ url: http://www.ibm.com
82
+ code: IBM
83
+ price: 97.45
84
+ change: -0.06
85
+ ratio: -0.06
86
+ - name: Intel
87
+ name2: Intel Corp.
88
+ url: http://www.intel.com
89
+ code: INTC
90
+ price: 20.53
91
+ change: -0.07
92
+ ratio: -0.34
93
+ - name: Juniper Networks
94
+ name2: Juniper Networks, Inc
48
95
  url: http://www.juniper.net/
49
96
  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
97
+ price: 18.96
98
+ change: 0.5
99
+ ratio: 2.71
100
+ - name: Microsoft
101
+ name2: Microsoft Corp
102
+ url: http://www.microsoft.com
103
+ code: MSFT
104
+ price: 30.6
105
+ change: 0.15
106
+ ratio: 0.49
107
+ - name: Oracle
108
+ name2: Oracle Corp.
109
+ url: http://www.oracle.com
110
+ code: ORCL
111
+ price: 17.15
112
+ change: 0.17
113
+ ratio: 1.0
114
+ - name: SAP
115
+ name2: SAP AG
116
+ url: http://www.sap.com
117
+ code: SAP
118
+ price: 46.2
119
+ change: -0.16
120
+ ratio: -0.35
59
121
  - name: Seagate Technology
122
+ name2: Seagate Technology
60
123
  url: http://www.seagate.com/
61
124
  code: STX
125
+ price: 27.35
126
+ change: -0.36
127
+ ratio: -1.3
128
+ - name: Sun Microsystems
129
+ name2: Sun Microsystems Inc.
130
+ url: http://www.sun.com
131
+ code: SUNW
132
+ price: 6.33
133
+ change: -0.01
134
+ ratio: -0.16
135
+ - name: Yahoo
136
+ name2: Yahoo! Inc.
137
+ url: http://www.yahoo.com
138
+ code: YHOO
139
+ price: 28.04
140
+ change: -0.17
141
+ ratio: -0.6
data/bin/erubis CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  ###
4
4
  ### $Rev: 10 $
5
- ### $Release: 2.1.0 $
6
- ### copyright(c) 2006 kuwata-lab all rights reserved.
5
+ ### $Release: 2.2.0 $
6
+ ### copyright(c) 2006-2007 kuwata-lab all rights reserved.
7
7
  ###
8
8
 
9
9
  require 'erubis/main'
data/bin/notext CHANGED
@@ -4,8 +4,8 @@
4
4
  ### notext - retrieve embedded code from eRuby, PHP, and so on
5
5
  ###
6
6
  ### $Rev$
7
- ### $Release: 2.1.0 $
8
- ### copyright(c) 2006 kuwata-lab all rights reserved.
7
+ ### $Release: 2.2.0 $
8
+ ### copyright(c) 2006-2007 kuwata-lab all rights reserved.
9
9
  ###
10
10
 
11
11
  require 'erubis'
@@ -93,7 +93,7 @@ end
93
93
 
94
94
  ## help message
95
95
  if opt_help || opt_version
96
- version = ('$Release: 2.1.0 $' =~ /[\.\d]+/) && $&
96
+ version = ('$Release: 2.2.0 $' =~ /[\.\d]+/) && $&
97
97
  puts version if opt_version
98
98
  puts help() if opt_help
99
99
  exit(0)
@@ -0,0 +1,23 @@
1
+ --- action_view/base.rb (original)
2
+ +++ action_view/base.rb (working copy)
3
+ @@ -445,6 +445,11 @@
4
+ end
5
+ end
6
+
7
+ + # convert template into ruby code
8
+ + def convert_template_into_ruby_code(template)
9
+ + ERB.new(template, nil, @@erb_trim_mode).src
10
+ + end
11
+ +
12
+ # Create source code for given template
13
+ def create_template_source(extension, template, render_symbol, locals)
14
+ if template_requires_setup?(extension)
15
+ @@ -458,7 +463,7 @@
16
+ "update_page do |page|\n#{template}\nend"
17
+ end
18
+ else
19
+ - body = ERB.new(template, nil, @@erb_trim_mode).src
20
+ + body = convert_template_into_ruby_code(template)
21
+ end
22
+
23
+ @@template_args[render_symbol] ||= {}
@@ -2,36 +2,29 @@
2
2
 
3
3
  ###
4
4
  ### $Rev: 10 $
5
- ### $Release: 2.1.0 $
6
- ### copyright(c) 2006 kuwata-lab all rights reserved.
5
+ ### $Release: 2.2.0 $
6
+ ### copyright(c) 2006-2007 kuwata-lab all rights reserved.
7
7
  ###
8
8
 
9
9
  #--begin of require 'erubis/main'
10
10
  ###
11
- ### $Rev: 41 $
12
- ### $Release: 2.1.0 $
13
- ### copyright(c) 2006 kuwata-lab all rights reserved.
11
+ ### $Rev: 65 $
12
+ ### $Release: 2.2.0 $
13
+ ### copyright(c) 2006-2007 kuwata-lab all rights reserved.
14
14
  ###
15
15
 
16
16
  require 'yaml'
17
17
  #--begin of require 'erubis'
18
18
  ##
19
- ## $Rev: 36 $
20
- ## $Release: 2.1.0 $
21
- ## copyright(c) 2006 kuwata-lab all rights reserved.
19
+ ## $Rev: 59 $
20
+ ## $Release: 2.2.0 $
21
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
22
22
  ##
23
23
 
24
24
  ##
25
25
  ## an implementation of eRuby
26
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:
27
+ ## ex.
35
28
  ## input = <<'END'
36
29
  ## <ul>
37
30
  ## <% for item in @list %>
@@ -41,25 +34,24 @@ require 'yaml'
41
34
  ## </ul>
42
35
  ## END
43
36
  ## list = ['<aaa>', 'b&b', '"ccc"']
44
- ## eruby = Erubis::Eruby.new()
45
- ## code = eruby.convert(input)
37
+ ## eruby = Erubis::Eruby.new(input)
46
38
  ## puts "--- code ---"
47
- ## puts code
39
+ ## puts eruby.src
48
40
  ## puts "--- result ---"
49
- ## context = Object.new
50
- ## context.instance_variable_set("@list", list)
51
- ## puts context.instance_eval(code)
52
- ## # or @list = list; puts eval(code, binding())
41
+ ## context = Erubis::Context.new() # or new(:list=>list)
42
+ ## context[:list] = list
43
+ ## puts eruby.evaluate(context)
53
44
  ##
54
45
  ## result:
55
46
  ## --- source ---
56
- ## _buf = ""; _buf << " <ul>\n"
57
- ## for item in list
58
- ## _buf << " <li>"; _buf << ( item ).to_s; _buf << "\n"
59
- ## _buf << " "; _buf << Erubis::XmlEruby.escape( item ); _buf << "</li>\n"
60
- ## end
61
- ## _buf << " </ul>\n"
62
- ## _buf
47
+ ## _buf = ''; _buf << '<ul>
48
+ ## '; for item in @list
49
+ ## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
50
+ ## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
51
+ ## '; end
52
+ ## _buf << '</ul>
53
+ ## ';
54
+ ## _buf.to_s
63
55
  ## --- result ---
64
56
  ## <ul>
65
57
  ## <li><aaa>
@@ -72,19 +64,23 @@ require 'yaml'
72
64
  ##
73
65
 
74
66
 
67
+ module Erubis
68
+ VERSION = ('$Release: 2.2.0 $' =~ /([.\d]+)/) && $1
69
+ end
70
+
75
71
  #--begin of require 'erubis/engine'
76
72
  ##
77
- ## $Rev: 32 $
78
- ## $Release: 2.1.0 $
79
- ## copyright(c) 2006 kuwata-lab all rights reserved.
73
+ ## $Rev: 55 $
74
+ ## $Release: 2.2.0 $
75
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
80
76
  ##
81
77
 
82
78
 
83
79
  #--begin of require 'erubis/generator'
84
80
  ##
85
- ## $Rev: 32 $
86
- ## $Release: 2.1.0 $
87
- ## copyright(c) 2006 kuwata-lab all rights reserved.
81
+ ## $Rev: 42 $
82
+ ## $Release: 2.2.0 $
83
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
88
84
  ##
89
85
 
90
86
  #--begin of require 'abstract'
@@ -168,6 +164,9 @@ end
168
164
  module Erubis
169
165
 
170
166
 
167
+ ##
168
+ ## code generator, called by Converter module
169
+ ##
171
170
  module Generator
172
171
 
173
172
  def self.supported_properties() # :nodoc:
@@ -243,9 +242,9 @@ end
243
242
  #--end of require 'erubis/generator'
244
243
  #--begin of require 'erubis/converter'
245
244
  ##
246
- ## $Rev: 37 $
247
- ## $Release: 2.1.0 $
248
- ## copyright(c) 2006 kuwata-lab all rights reserved.
245
+ ## $Rev: 60 $
246
+ ## $Release: 2.2.0 $
247
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
249
248
  ##
250
249
 
251
250
  #--already included require 'abstract'
@@ -285,6 +284,36 @@ module Erubis
285
284
 
286
285
  protected
287
286
 
287
+ ##
288
+ ## detect spaces at beginning of line
289
+ ##
290
+ def detect_spaces_at_bol(text, is_bol)
291
+ lspace = nil
292
+ if text.empty?
293
+ lspace = "" if is_bol
294
+ elsif text[-1] == ?\n
295
+ lspace = ""
296
+ else
297
+ rindex = text.rindex(?\n)
298
+ if rindex
299
+ s = text[rindex+1..-1]
300
+ if s =~ /\A[ \t]*\z/
301
+ lspace = s
302
+ #text = text[0..rindex]
303
+ text[rindex+1..-1] = ''
304
+ end
305
+ else
306
+ if is_bol && text =~ /\A[ \t]*\z/
307
+ #lspace = text
308
+ #text = nil
309
+ lspace = text.dup
310
+ text[0..-1] = ''
311
+ end
312
+ end
313
+ end
314
+ return lspace
315
+ end
316
+
288
317
  ##
289
318
  ## (abstract) convert input to code
290
319
  ##
@@ -316,57 +345,65 @@ module Erubis
316
345
 
317
346
  def init_converter(properties={})
318
347
  super(properties)
319
- @pattern = properties[:pattern]
320
- @trim = properties[:trim] != false
348
+ @pattern = properties[:pattern]
349
+ @trim = properties[:trim] != false
321
350
  end
322
351
 
323
- #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
324
- DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
352
+ protected
325
353
 
326
354
  ## return regexp of pattern to parse eRuby script
327
- def pattern_regexp(pattern=@pattern)
328
- if pattern.nil? || pattern == '<% %>'
329
- return DEFAULT_REGEXP
330
- else
331
- prefix, postfix = pattern.split()
332
- #return /(.*?)(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
333
- return /(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
334
- end
355
+ def pattern_regexp(pattern)
356
+ prefix, postfix = pattern.split() # '<% %>' => '<%', '%>'
357
+ #return /(.*?)(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
358
+ #return /(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
359
+ return /#{prefix}(=+|-|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
335
360
  end
336
- protected :pattern_regexp
361
+ module_function :pattern_regexp
362
+
363
+ #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
364
+ #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
365
+ #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
366
+ DEFAULT_REGEXP = pattern_regexp('<% %>')
367
+
368
+ public
337
369
 
338
370
  def convert_input(src, input)
339
- regexp = pattern_regexp(@pattern)
371
+ pat = @pattern
372
+ regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
340
373
  pos = 0
341
- input.scan(regexp) do |lspace, indicator, code, rspace|
374
+ is_bol = true # is beginning of line
375
+ input.scan(regexp) do |indicator, code, rspace|
342
376
  match = Regexp.last_match()
343
- index = match.begin(0)
344
- text = input[pos, index - pos]
345
- pos = match.end(0)
346
- add_text(src, text)
377
+ len = match.begin(0) - pos
378
+ text = input[pos, len]
379
+ pos = match.end(0)
380
+ ch = indicator ? indicator[0] : nil
381
+ lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
382
+ is_bol = rspace ? true : false
383
+ add_text(src, text) if text && !text.empty?
347
384
  ## * when '<%= %>', do nothing
348
385
  ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
349
- if !indicator # <% %>
386
+ if ch == ?= # <%= %>
387
+ add_text(src, lspace) if lspace
388
+ add_expr(src, code, indicator)
389
+ add_text(src, rspace) if rspace
390
+ elsif ch == ?\# # <%# %>
391
+ n = code.count("\n") + (rspace ? 1 : 0)
350
392
  if @trim && lspace && rspace
351
- add_stmt(src, "#{lspace}#{code}#{rspace}")
393
+ add_stmt(src, "\n" * n)
352
394
  else
353
395
  add_text(src, lspace) if lspace
354
- add_stmt(src, code)
396
+ add_stmt(src, "\n" * n)
355
397
  add_text(src, rspace) if rspace
356
398
  end
357
- elsif indicator[0] == ?\# # <%# %>
358
- n = code.count("\n") + (rspace ? 1 : 0)
399
+ else # <% %>
359
400
  if @trim && lspace && rspace
360
- add_stmt(src, "\n" * n)
401
+ add_stmt(src, "#{lspace}#{code}#{rspace}")
361
402
  else
362
403
  add_text(src, lspace) if lspace
363
- add_stmt(src, "\n" * n)
404
+ add_stmt(src, code)
364
405
  add_text(src, rspace) if rspace
365
406
  end
366
- else # <%= %>
367
- add_text(src, lspace) if lspace
368
- add_expr(src, code, indicator)
369
- add_text(src, rspace) if rspace
370
407
  end
371
408
  end
372
409
  rest = $' || input # add input when no matched
@@ -415,9 +452,9 @@ module Erubis
415
452
 
416
453
  def init_converter(properties={})
417
454
  super(properties)
418
- @trim = !(properties[:trim] == false)
455
+ @trim = properties.fetch(:trim, true)
419
456
  @pi = properties[:pi] if properties[:pi]
420
- @embchar = properties[:embchar] || '@'
457
+ @embchar = properties[:embchar] || '@'
421
458
  @pattern = properties[:pattern]
422
459
  @pattern = '<% %>' if @pattern.nil? #|| @pattern == true
423
460
  end
@@ -430,60 +467,106 @@ module Erubis
430
467
  protected
431
468
 
432
469
  def convert_input(codebuf, input)
433
- parse_stmts(codebuf, input)
434
- #parse_stmts2(codebuf, input)
435
- end
436
-
437
- def parse_stmts(codebuf, input)
438
- #regexp = pattern_regexp(@pattern)
439
- @pi ||= 'e'
440
- @stmt_pattern ||= /(^[ \t]*)?<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
441
- pos = 0
442
- input.scan(@stmt_pattern) do |lspace, pi_arg, code, rspace|
443
- match = Regexp.last_match
444
- index = match.begin(0)
445
- text = input[pos, index - pos]
446
- pos = match.end(0)
447
- parse_exprs(codebuf, text) # unless text.empty?
448
- if @trim && lspace && rspace
449
- add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
450
- else
451
- add_text(codebuf, lspace)
452
- add_pi_stmt(codebuf, code, pi_arg)
453
- add_text(codebuf, rspace)
454
- end
455
- end
456
- rest = $' || input
457
- parse_exprs(codebuf, rest)
458
- end
459
-
460
- def parse_exprs(codebuf, input)
461
- unless @expr_pattern
470
+ unless @regexp
471
+ @pi ||= 'e'
462
472
  ch = Regexp.escape(@embchar)
463
473
  if @pattern
464
474
  left, right = @pattern.split(' ')
465
- @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
475
+ @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
466
476
  else
467
- @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
477
+ @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
468
478
  end
469
479
  end
480
+ #
481
+ is_bol = true
470
482
  pos = 0
471
- input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
472
- indicator = indicator1 || indicator2
473
- code = code1 || code2
483
+ input.scan(@regexp) do |pi_arg, stmt, rspace,
484
+ indicator1, expr1, indicator2, expr2|
474
485
  match = Regexp.last_match
475
- index = match.begin(0)
476
- text = input[pos, index - pos]
486
+ len = match.begin(0) - pos
487
+ text = input[pos, len]
477
488
  pos = match.end(0)
489
+ lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
490
+ is_bol = stmt && rspace ? true : false
478
491
  add_text(codebuf, text) # unless text.empty?
479
- add_pi_expr(codebuf, code, indicator)
492
+ #
493
+ if stmt
494
+ if @trim && lspace && rspace
495
+ add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
496
+ else
497
+ add_text(codebuf, lspace) if lspace
498
+ add_pi_stmt(codebuf, stmt, pi_arg)
499
+ add_text(codebuf, rspace) if rspace
500
+ end
501
+ else
502
+ add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
503
+ end
480
504
  end
481
505
  rest = $' || input
482
506
  add_text(codebuf, rest)
483
507
  end
484
508
 
509
+ #--
510
+ #def convert_input(codebuf, input)
511
+ # parse_stmts(codebuf, input)
512
+ # #parse_stmts2(codebuf, input)
513
+ #end
514
+ #
515
+ #def parse_stmts(codebuf, input)
516
+ # #regexp = pattern_regexp(@pattern)
517
+ # @pi ||= 'e'
518
+ # @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
519
+ # is_bol = true
520
+ # pos = 0
521
+ # input.scan(@stmt_pattern) do |pi_arg, code, rspace|
522
+ # match = Regexp.last_match
523
+ # len = match.begin(0) - pos
524
+ # text = input[pos, len]
525
+ # pos = match.end(0)
526
+ # lspace = detect_spaces_at_bol(text, is_bol)
527
+ # is_bol = rspace ? true : false
528
+ # parse_exprs(codebuf, text) # unless text.empty?
529
+ # if @trim && lspace && rspace
530
+ # add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
531
+ # else
532
+ # add_text(codebuf, lspace)
533
+ # add_pi_stmt(codebuf, code, pi_arg)
534
+ # add_text(codebuf, rspace)
535
+ # end
536
+ # end
537
+ # rest = $' || input
538
+ # parse_exprs(codebuf, rest)
539
+ #end
540
+ #
541
+ #def parse_exprs(codebuf, input)
542
+ # unless @expr_pattern
543
+ # ch = Regexp.escape(@embchar)
544
+ # if @pattern
545
+ # left, right = @pattern.split(' ')
546
+ # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
547
+ # else
548
+ # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
549
+ # end
550
+ # end
551
+ # pos = 0
552
+ # input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
553
+ # indicator = indicator1 || indicator2
554
+ # code = code1 || code2
555
+ # match = Regexp.last_match
556
+ # len = match.begin(0) - pos
557
+ # text = input[pos, len]
558
+ # pos = match.end(0)
559
+ # add_text(codebuf, text) # unless text.empty?
560
+ # add_pi_expr(codebuf, code, indicator)
561
+ # end
562
+ # rest = $' || input
563
+ # add_text(codebuf, rest)
564
+ #end
565
+ #++
566
+
485
567
  def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
486
568
  case pi_arg
569
+ when nil ; add_stmt(codebuf, code)
487
570
  when 'header' ; @header = code
488
571
  when 'footer' ; @footer = code
489
572
  when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
@@ -494,57 +577,17 @@ module Erubis
494
577
 
495
578
  def add_pi_expr(codebuf, code, indicator) # :nodoc:
496
579
  case indicator
497
- when nil, '', '==' # @{...}@ or <%== ... %>
580
+ when nil, '', '==' # @{...}@ or <%== ... %>
498
581
  @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
499
- when '!', '=' # @!{...}@ or <%= ... %>
582
+ when '!', '=' # @!{...}@ or <%= ... %>
500
583
  @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
501
- when '!!', '===' # @!!{...}@ or <%=== ... %>
584
+ when '!!', '===' # @!!{...}@ or <%=== ... %>
502
585
  add_expr_debug(codebuf, code)
503
586
  else
504
587
  # ignore
505
588
  end
506
589
  end
507
590
 
508
- ## (obsolete) equivarent to parse_stmts(), but a little slower than it.
509
- def parse_stmts2(codebuf, input) # :nodoc:
510
- #regexp = pattern_regexp(@pattern)
511
- @pi ||= 'e'
512
- unless @embedded_pattern
513
- ch = Regexp.escape(@embchar)
514
- if @pattern
515
- left, right = @pattern.split(' ')
516
- @embedded_pattern = /(^[ \t]*)?<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
517
- else
518
- @embedded_pattern = /(^[ \t]*)?<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
519
- end
520
- end
521
- pos = 0
522
- input.scan(@embedded_pattern) do |lspace, pi_arg, stmt, rspace,
523
- indicator1, expr1, indicator2, expr2|
524
- match = Regexp.last_match
525
- index = match.begin(0)
526
- text = input[pos, index - pos]
527
- pos = match.end(0)
528
- add_text(codebuf, text) # unless text.empty?
529
- if stmt
530
- code = stmt
531
- if @trim && lspace && rspace
532
- add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
533
- else
534
- add_text(codebuf, lspace)
535
- add_pi_stmt(codebuf, code, pi_arg)
536
- add_text(codebuf, rspace)
537
- end
538
- else
539
- code = expr1 || expr2
540
- indicator = indicator1 || indicator2
541
- add_pi_expr(codebuf, code, indicator)
542
- end
543
- end
544
- rest = $' || input
545
- add_text(codebuf, rest)
546
- end
547
-
548
591
  end
549
592
 
550
593
 
@@ -553,15 +596,15 @@ end
553
596
  #--begin of require 'erubis/evaluator'
554
597
  ##
555
598
  ## $Rev: 32 $
556
- ## $Release: 2.1.0 $
557
- ## copyright(c) 2006 kuwata-lab all rights reserved.
599
+ ## $Release: 2.2.0 $
600
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
558
601
  ##
559
602
 
560
603
  #--begin of require 'erubis/error'
561
604
  ##
562
605
  ## $Rev: 32 $
563
- ## $Release: 2.1.0 $
564
- ## copyright(c) 2006 kuwata-lab all rights reserved.
606
+ ## $Release: 2.2.0 $
607
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
565
608
  ##
566
609
 
567
610
  module Erubis
@@ -585,9 +628,9 @@ end
585
628
  #--end of require 'erubis/error'
586
629
  #--begin of require 'erubis/context'
587
630
  ##
588
- ## $Rev: 32 $
589
- ## $Release: 2.1.0 $
590
- ## copyright(c) 2006 kuwata-lab all rights reserved.
631
+ ## $Rev: 59 $
632
+ ## $Release: 2.2.0 $
633
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
591
634
  ##
592
635
 
593
636
 
@@ -615,6 +658,7 @@ module Erubis
615
658
  ## print eruby.evaluate(context)
616
659
  ##
617
660
  class Context
661
+ include Enumerable
618
662
 
619
663
  def initialize(hash=nil)
620
664
  hash.each do |name, value|
@@ -631,7 +675,36 @@ module Erubis
631
675
  end
632
676
 
633
677
  def keys
634
- return instance_variables.collect { |name| name[1,name.length-1] }
678
+ return instance_variables.collect { |name| name[1..-1] }
679
+ end
680
+
681
+ def each
682
+ instance_variables.each do |name|
683
+ key = name[1..-1]
684
+ value = instance_variable_get(name)
685
+ yield(key, value)
686
+ end
687
+ end
688
+
689
+ def to_hash
690
+ hash = {}
691
+ self.keys.each { |key| hash[key] = self[key] }
692
+ return hash
693
+ end
694
+
695
+ def update(context_or_hash)
696
+ arg = context_or_hash
697
+ if arg.is_a?(Hash)
698
+ arg.each do |key, val|
699
+ self[key] = val
700
+ end
701
+ else
702
+ arg.instance_variables.each do |varname|
703
+ key = varname[1..-1]
704
+ val = arg.instance_variable_get(varname)
705
+ self[key] = val
706
+ end
707
+ end
635
708
  end
636
709
 
637
710
  end
@@ -718,11 +791,6 @@ module Erubis
718
791
  #include Converter
719
792
  #include Generator
720
793
 
721
- # convert input string and set it to @src
722
- def convert!(input)
723
- @src = convert(input)
724
- end
725
-
726
794
  def initialize(input=nil, properties={})
727
795
  #@input = input
728
796
  init_generator(properties)
@@ -731,12 +799,34 @@ module Erubis
731
799
  @src = convert(input) if input
732
800
  end
733
801
 
734
- ## load file and create engine object
802
+
803
+ ##
804
+ ## convert input string and set it to @src
805
+ ##
806
+ def convert!(input)
807
+ @src = convert(input)
808
+ end
809
+
810
+
811
+ ##
812
+ ## load file, write cache file, and return engine object.
813
+ ## this method create cache file (filename + '.cache') automatically.
814
+ ##
735
815
  def self.load_file(filename, properties={})
736
- input = File.open(filename, 'rb') { |f| f.read }
737
- input.untaint # is it ok?
816
+ cachename = filename + '.cache'
738
817
  properties[:filename] = filename
739
- engine = self.new(input, properties)
818
+ if test(?f, cachename) && File.mtime(filename) <= File.mtime(cachename)
819
+ engine = self.new(nil, properties)
820
+ engine.src = File.read(cachename)
821
+ else
822
+ input = File.open(filename, 'rb') { |f| f.read }
823
+ engine = self.new(input, properties)
824
+ File.open(cachename, 'w') do |f|
825
+ f.flock(File::LOCK_EX)
826
+ f.write(engine.src)
827
+ end
828
+ end
829
+ engine.src.untaint # ok?
740
830
  return engine
741
831
  end
742
832
 
@@ -802,9 +892,9 @@ end
802
892
  #require 'erubis/context'
803
893
  #--begin of require 'erubis/helper'
804
894
  ##
805
- ## $Rev: 21 $
806
- ## $Release: 2.1.0 $
807
- ## copyright(c) 2006 kuwata-lab all rights reserved.
895
+ ## $Rev: 64 $
896
+ ## $Release: 2.2.0 $
897
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
808
898
  ##
809
899
 
810
900
 
@@ -825,28 +915,11 @@ module Erubis
825
915
  "'" => '&#039;',
826
916
  }
827
917
 
828
- def escape_xml(obj)
829
- #table = ESCAPE_TABLE
830
- #obj.to_s.gsub(/[&<>"]/) { |s| table[s] } # or /[&<>"']/
831
- obj.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
832
- #obj.to_s.gsub(SCAN_REGEXP) { |s| ESCAPE_TABLE[s] }
833
- #obj.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
918
+ def escape_xml(value)
919
+ value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
920
+ #value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
834
921
  end
835
922
 
836
- #--
837
- #def escape_xml(obj)
838
- # str = obj.to_s.dup
839
- # #str = obj.to_s
840
- # #str = str.dup if obj.__id__ == str.__id__
841
- # str.gsub!(/&/, '&amp;')
842
- # str.gsub!(/</, '&lt;')
843
- # str.gsub!(/>/, '&gt;')
844
- # str.gsub!(/"/, '&quot;')
845
- # str.gsub!(/'/, '&#039;')
846
- # return str
847
- #end
848
- #++
849
-
850
923
  alias h escape_xml
851
924
  alias html_escape escape_xml
852
925
 
@@ -857,9 +930,9 @@ end
857
930
  #--end of require 'erubis/helper'
858
931
  #--begin of require 'erubis/enhancer'
859
932
  ##
860
- ## $Rev: 32 $
861
- ## $Release: 2.1.0 $
862
- ## copyright(c) 2006 kuwata-lab all rights reserved.
933
+ ## $Rev: 60 $
934
+ ## $Release: 2.2.0 $
935
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
863
936
  ##
864
937
 
865
938
 
@@ -1072,7 +1145,7 @@ module Erubis
1072
1145
 
1073
1146
  def add_postamble(src)
1074
1147
  src << "\n" unless src[-1] == ?\n
1075
- src << "_buf\n"
1148
+ src << "_buf.to_s\n"
1076
1149
  end
1077
1150
 
1078
1151
  end
@@ -1101,6 +1174,31 @@ module Erubis
1101
1174
  end
1102
1175
 
1103
1176
 
1177
+ #--
1178
+ ###
1179
+ ### set buffer variable name to '_erbout' as well as '_buf'
1180
+ ###
1181
+ ### this is only for Eruby.
1182
+ ###
1183
+ #module ErboutEnhancer
1184
+ #
1185
+ # def self.desc # :nodoc:
1186
+ # "set buffer name '_erbout' as well as '_buf'"
1187
+ # end
1188
+ #
1189
+ # def add_preamble(src)
1190
+ # src << "_erbout = _buf = '';"
1191
+ # end
1192
+ #
1193
+ # def add_postamble(src)
1194
+ # src << "\n" unless src[-1] == ?\n
1195
+ # src << "_buf.to_s\n"
1196
+ # end
1197
+ #
1198
+ #end
1199
+ #++
1200
+
1201
+
1104
1202
  ##
1105
1203
  ## remove text and leave code, especially useful when debugging.
1106
1204
  ##
@@ -1181,9 +1279,10 @@ module Erubis
1181
1279
  #regexp = pattern_regexp(@pattern)
1182
1280
  pos = 0
1183
1281
  input.scan(SIMPLE_REGEXP) do |indicator, code|
1184
- index = Regexp.last_match.begin(0)
1185
- text = input[pos, index - pos]
1186
- pos = index + $&.length()
1282
+ match = Regexp.last_match
1283
+ index = match.begin(0)
1284
+ text = input[pos, index - pos]
1285
+ pos = match.end(0)
1187
1286
  add_text(src, text)
1188
1287
  if !indicator # <% %>
1189
1288
  add_stmt(src, code)
@@ -1381,14 +1480,13 @@ end
1381
1480
  #require 'erubis/tiny'
1382
1481
  #--begin of require 'erubis/engine/eruby'
1383
1482
  ##
1384
- ## $Rev: 33 $
1385
- ## $Release: 2.1.0 $
1386
- ## copyright(c) 2006 kuwata-lab all rights reserved.
1483
+ ## $Rev: 54 $
1484
+ ## $Release: 2.2.0 $
1485
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1387
1486
  ##
1388
1487
 
1389
1488
  #--already included require 'erubis/engine'
1390
1489
  #--already included require 'erubis/enhancer'
1391
- #--already included require 'abstract'
1392
1490
 
1393
1491
 
1394
1492
  module Erubis
@@ -1399,8 +1497,8 @@ module Erubis
1399
1497
  ##
1400
1498
  module RubyGenerator
1401
1499
  include Generator
1402
- #include StringBufferEnhancer
1403
- include ArrayBufferEnhancer
1500
+ #include ArrayBufferEnhancer
1501
+ include StringBufferEnhancer
1404
1502
 
1405
1503
  def init_generator(properties={})
1406
1504
  super
@@ -1510,22 +1608,22 @@ end
1510
1608
 
1511
1609
  #--begin of require 'erubis/local-setting'
1512
1610
  ##
1513
- ## $Rev: 13 $
1514
- ## $Release: 2.1.0 $
1515
- ## copyright(c) 2006 kuwata-lab all rights reserved.
1611
+ ## $Rev: 42 $
1612
+ ## $Release: 2.2.0 $
1613
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1516
1614
  ##
1517
1615
 
1518
1616
  ##
1519
1617
  ## you can add site-local settings here.
1520
- ## this files is 'require'd by erubis.rb
1618
+ ## this files is required by erubis.rb
1521
1619
  ##
1522
1620
  #--end of require 'erubis/local-setting'
1523
1621
  #--end of require 'erubis'
1524
1622
  #--begin of require 'erubis/tiny'
1525
1623
  ##
1526
- ## $Rev: 35 $
1527
- ## $Release: 2.1.0 $
1528
- ## copyright(c) 2006 kuwata-lab all rights reserved.
1624
+ ## $Rev: 54 $
1625
+ ## $Release: 2.2.0 $
1626
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1529
1627
  ##
1530
1628
 
1531
1629
  module Erubis
@@ -1549,44 +1647,47 @@ module Erubis
1549
1647
  EMBEDDED_PATTERN = /<%(=+|\#)?(.*?)-?%>/m
1550
1648
 
1551
1649
  def convert(input)
1552
- src = "_buf = [];" # preamble
1650
+ src = "_buf = '';" # preamble
1553
1651
  pos = 0
1554
1652
  input.scan(EMBEDDED_PATTERN) do |indicator, code|
1555
1653
  match = Regexp.last_match
1556
- index = match.begin(0)
1557
- text = input[pos, index - pos]
1654
+ len = match.begin(0) - pos
1655
+ text = input[pos, len]
1558
1656
  pos = match.end(0)
1559
- src << " _buf << '" << escape_text(text) << "';"
1657
+ #src << " _buf << '" << escape_text(text) << "';"
1658
+ text.gsub!(/['\\]/, '\\\\\&')
1659
+ src << " _buf << '" << text << "';" unless text.empty?
1560
1660
  if !indicator # <% %>
1561
1661
  src << code << ";"
1562
- elsif indicator[0] == ?\# # <%# %>
1563
- n = code.count("\n")
1564
- add_stmt(src, "\n" * n)
1662
+ elsif indicator == '#' # <%# %>
1663
+ src << ("\n" * code.count("\n"))
1565
1664
  else # <%= %>
1566
1665
  src << " _buf << (" << code << ").to_s;"
1567
1666
  end
1568
1667
  end
1569
1668
  rest = $' || input
1570
- src << " _buf << '" << escape_text(rest) << "';"
1571
- src << "\n_buf.join\n" # postamble
1669
+ #src << " _buf << '" << escape_text(rest) << "';"
1670
+ rest.gsub!(/['\\]/, '\\\\\&')
1671
+ src << " _buf << '" << rest << "';" unless rest.empty?
1672
+ src << "\n_buf.to_s\n" # postamble
1572
1673
  return src
1573
1674
  end
1574
1675
 
1575
- def escape_text(text)
1576
- return text.gsub!(/['\\]/, '\\\\\&') || text
1577
- end
1676
+ #def escape_text(text)
1677
+ # return text.gsub!(/['\\]/, '\\\\\&') || text
1678
+ #end
1578
1679
 
1579
- def result(binding=TOPLEVEL_BINDING)
1580
- eval @src, binding
1680
+ def result(_binding=TOPLEVEL_BINDING)
1681
+ eval @src, _binding
1581
1682
  end
1582
1683
 
1583
- def evaluate(context=Object.new)
1584
- if context.is_a?(Hash)
1585
- obj = Object.new
1586
- context.each do |k, v| obj.instance_variable_set("@#{k}", v) end
1587
- context = obj
1684
+ def evaluate(_context=Object.new)
1685
+ if _context.is_a?(Hash)
1686
+ _obj = Object.new
1687
+ _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1688
+ _context = _obj
1588
1689
  end
1589
- context.instance_eval @src
1690
+ _context.instance_eval @src
1590
1691
  end
1591
1692
 
1592
1693
  end
@@ -1605,56 +1706,58 @@ module Erubis
1605
1706
 
1606
1707
  attr_reader :src
1607
1708
 
1608
- EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|\$(!*)?\{(.*?)\}/
1709
+ EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|@(!+)?\{(.*?)\}@/m
1609
1710
 
1610
1711
  def convert(input)
1611
- src = "_buf = [];" # preamble
1712
+ src = "_buf = '';" # preamble
1612
1713
  pos = 0
1613
- input.scan(EMBEDDED_PATTERN) do |lspace, stmtcode, rspace, indicator, exprcode|
1714
+ input.scan(EMBEDDED_PATTERN) do |lspace, stmt, rspace, indicator, expr|
1614
1715
  match = Regexp.last_match
1615
- index = match.begin(0)
1616
- text = input[pos, index - pos]
1716
+ len = match.begin(0) - pos
1717
+ text = input[pos, len]
1617
1718
  pos = match.end(0)
1618
- if stmtcode # <?rb ... ?>
1619
- code = stmtcode
1620
- src << " _buf << '" << escape_text(text) << "';"
1719
+ #src << " _buf << '" << escape_text(text) << "';"
1720
+ text.gsub!(/['\\]/, '\\\\\&')
1721
+ src << " _buf << '" << text << "';" unless text.empty?
1722
+ if stmt # <?rb ... ?>
1621
1723
  if lspace && rspace
1622
- src << "#{lspace}#{code}#{rspace}"
1724
+ src << "#{lspace}#{stmt}#{rspace}"
1623
1725
  else
1624
- src << " _buf << '#{lspace}';" if lspace
1625
- src << code << ";"
1626
- src << " _buf << '#{rspace}';" if rspace
1726
+ src << " _buf << '" << lspace << "';" if lspace
1727
+ src << stmt << ";"
1728
+ src << " _buf << '" << rspace << "';" if rspace
1627
1729
  end
1628
1730
  else # ${...}, $!{...}
1629
- code = exprcode
1630
- if indicator.nil? || indicator.empty?
1631
- src << " _buf << #{@escape}(" << code << ");"
1731
+ if !indicator
1732
+ src << " _buf << " << @escape << "(" << expr << ");"
1632
1733
  elsif indicator == '!'
1633
- src << " _buf << (" << code << ").to_s;"
1734
+ src << " _buf << (" << expr << ").to_s;"
1634
1735
  end
1635
1736
  end
1636
1737
  end
1637
1738
  rest = $' || input
1638
- src << " _buf << '" << escape_text(rest) << "';"
1639
- src << "\n_buf.join\n" # postamble
1739
+ #src << " _buf << '" << escape_text(rest) << "';"
1740
+ rest.gsub!(/['\\]/, '\\\\\&')
1741
+ src << " _buf << '" << rest << "';" unless rest.empty?
1742
+ src << "\n_buf.to_s\n" # postamble
1640
1743
  return src
1641
1744
  end
1642
1745
 
1643
- def escape_text(text)
1644
- return text.gsub!(/['\\]/, '\\\\\&') || text
1645
- end
1746
+ #def escape_text(text)
1747
+ # return text.gsub!(/['\\]/, '\\\\\&') || text
1748
+ #end
1646
1749
 
1647
- def result(binding=TOPLEVEL_BINDING)
1648
- eval @src, binding
1750
+ def result(_binding=TOPLEVEL_BINDING)
1751
+ eval @src, _binding
1649
1752
  end
1650
1753
 
1651
- def evaluate(context=Object.new)
1652
- if context.is_a?(Hash)
1653
- obj = Object.new
1654
- context.each do |k, v| obj.instance_variable_set("@#{k}", v) end
1655
- context = obj
1754
+ def evaluate(_context=Object.new)
1755
+ if _context.is_a?(Hash)
1756
+ _obj = Object.new
1757
+ _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1758
+ _context = _obj
1656
1759
  end
1657
- context.instance_eval @src
1760
+ _context.instance_eval @src
1658
1761
  end
1659
1762
 
1660
1763
  end
@@ -1665,8 +1768,8 @@ end
1665
1768
  #--begin of require 'erubis/engine/enhanced'
1666
1769
  ##
1667
1770
  ## $Rev: 27 $
1668
- ## $Release: 2.1.0 $
1669
- ## copyright(c) 2006 kuwata-lab all rights reserved.
1771
+ ## $Release: 2.2.0 $
1772
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1670
1773
  ##
1671
1774
 
1672
1775
  #--already included require 'erubis/enhancer'
@@ -1774,8 +1877,8 @@ end
1774
1877
  #--begin of require 'erubis/engine/optimized'
1775
1878
  ##
1776
1879
  ## $Rev: 31 $
1777
- ## $Release: 2.1.0 $
1778
- ## copyright(c) 2006 kuwata-lab all rights reserved.
1880
+ ## $Release: 2.2.0 $
1881
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1779
1882
  ##
1780
1883
 
1781
1884
 
@@ -1905,8 +2008,8 @@ end
1905
2008
  #--begin of require 'erubis/engine/ephp'
1906
2009
  ##
1907
2010
  ## $Rev: 31 $
1908
- ## $Release: 2.1.0 $
1909
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2011
+ ## $Release: 2.2.0 $
2012
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
1910
2013
  ##
1911
2014
 
1912
2015
  #--already included require 'erubis/engine'
@@ -2007,8 +2110,8 @@ end
2007
2110
  #--begin of require 'erubis/engine/ec'
2008
2111
  ##
2009
2112
  ## $Rev: 33 $
2010
- ## $Release: 2.1.0 $
2011
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2113
+ ## $Release: 2.2.0 $
2114
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
2012
2115
  ##
2013
2116
 
2014
2117
  #--already included require 'erubis/engine'
@@ -2127,8 +2230,8 @@ end
2127
2230
  #--begin of require 'erubis/engine/ejava'
2128
2231
  ##
2129
2232
  ## $Rev: 31 $
2130
- ## $Release: 2.1.0 $
2131
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2233
+ ## $Release: 2.2.0 $
2234
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
2132
2235
  ##
2133
2236
 
2134
2237
  #--already included require 'erubis/engine'
@@ -2240,8 +2343,8 @@ end
2240
2343
  #--begin of require 'erubis/engine/escheme'
2241
2344
  ##
2242
2345
  ## $Rev: 33 $
2243
- ## $Release: 2.1.0 $
2244
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2346
+ ## $Release: 2.2.0 $
2347
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
2245
2348
  ##
2246
2349
 
2247
2350
  #--already included require 'erubis/engine'
@@ -2357,8 +2460,8 @@ end
2357
2460
  #--begin of require 'erubis/engine/eperl'
2358
2461
  ##
2359
2462
  ## $Rev: 40 $
2360
- ## $Release: 2.1.0 $
2361
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2463
+ ## $Release: 2.2.0 $
2464
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
2362
2465
  ##
2363
2466
 
2364
2467
  #--already included require 'erubis/engine'
@@ -2455,8 +2558,8 @@ end
2455
2558
  #--begin of require 'erubis/engine/ejavascript'
2456
2559
  ##
2457
2560
  ## $Rev: 31 $
2458
- ## $Release: 2.1.0 $
2459
- ## copyright(c) 2006 kuwata-lab all rights reserved.
2561
+ ## $Release: 2.2.0 $
2562
+ ## copyright(c) 2006-2007 kuwata-lab all rights reserved.
2460
2563
  ##
2461
2564
 
2462
2565
  #--already included require 'erubis/engine'
@@ -2601,22 +2704,24 @@ module Erubis
2601
2704
  end
2602
2705
 
2603
2706
  def initialize
2604
- @single_options = "hvxTtSbeB"
2605
- @arg_options = "pcrfKIlaE"
2707
+ @single_options = "hvxztSbeB"
2708
+ @arg_options = "pcrfKIlaEC"
2606
2709
  @option_names = {
2607
2710
  ?h => :help,
2608
2711
  ?v => :version,
2609
2712
  ?x => :source,
2610
- ?T => :notrim,
2713
+ ?z => :syntax,
2714
+ #?T => :notrim,
2611
2715
  ?t => :untabify,
2612
2716
  ?S => :intern,
2613
2717
  ?b => :bodyonly,
2614
2718
  ?B => :binding,
2615
2719
  ?p => :pattern,
2616
- ?c => :class,
2720
+ ?c => :context,
2721
+ ?C => :class,
2617
2722
  ?e => :escape,
2618
2723
  ?r => :requires,
2619
- ?f => :yamlfiles,
2724
+ ?f => :datafiles,
2620
2725
  ?K => :kanji,
2621
2726
  ?I => :includes,
2622
2727
  ?l => :lang,
@@ -2664,6 +2769,7 @@ module Erubis
2664
2769
 
2665
2770
  ## action
2666
2771
  action = opts.action
2772
+ action ||= 'syntax' if opts.syntax
2667
2773
  action ||= 'convert' if opts.source
2668
2774
 
2669
2775
  ## lang
@@ -2678,13 +2784,18 @@ module Erubis
2678
2784
  $KCODE = opts.kanji if opts.kanji
2679
2785
 
2680
2786
  ## read context values from yaml file
2681
- yamlfiles = opts.yamlfiles
2682
- context = load_yamlfiles(yamlfiles, opts)
2787
+ datafiles = opts.datafiles
2788
+ context = load_datafiles(datafiles, opts)
2789
+
2790
+ ## parse context data
2791
+ if opts.context
2792
+ context = parse_context_data(opts.context, opts)
2793
+ end
2683
2794
 
2684
2795
  ## properties for engine
2685
2796
  properties[:escape] = true if opts.escape && !properties.key?(:escape)
2686
2797
  properties[:pattern] = opts.pattern if opts.pattern
2687
- properties[:trim] = false if opts.notrim
2798
+ #properties[:trim] = false if opts.notrim
2688
2799
  properties[:preamble] = properties[:postamble] = false if opts.bodyonly
2689
2800
  properties[:pi] = nil if properties[:pi] == true
2690
2801
 
@@ -2699,32 +2810,39 @@ module Erubis
2699
2810
 
2700
2811
  ## convert and execute
2701
2812
  val = nil
2813
+ msg = "Syntax OK\n"
2702
2814
  if filenames && !filenames.empty?
2703
2815
  filenames.each do |filename|
2704
2816
  test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
2705
2817
  engine.filename = filename
2706
2818
  engine.convert!(File.read(filename))
2707
- print val if val = do_action(action, engine, context, opts)
2819
+ val = do_action(action, engine, context, filename, opts)
2820
+ msg = nil if val
2708
2821
  end
2709
2822
  else
2710
2823
  engine.filename = '(stdin)'
2711
2824
  engine.convert!($stdin.read())
2712
- print val if val = do_action(action, engine, context, opts)
2825
+ val = do_action(action, engine, context, filename, opts)
2826
+ msg = nil if val
2713
2827
  end
2828
+ print msg if action == 'syntax' && msg
2714
2829
 
2715
2830
  end
2716
2831
 
2717
2832
  private
2718
2833
 
2719
- def do_action(action, engine, context, opts)
2834
+ def do_action(action, engine, context, filename, opts)
2720
2835
  case action
2721
2836
  when 'convert'
2722
2837
  s = engine.src
2723
2838
  when nil, 'exec', 'execute'
2724
- s = opts.binding ? engine.result(context) : engine.evaluate(context)
2839
+ s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
2840
+ when 'syntax'
2841
+ s = check_syntax(filename, engine.src)
2725
2842
  else
2726
2843
  raise "*** internal error"
2727
2844
  end
2845
+ print s if s
2728
2846
  return s
2729
2847
  end
2730
2848
 
@@ -2735,8 +2853,8 @@ erubis - embedded program converter for multi-language
2735
2853
  Usage: #{command} [..options..] [file ...]
2736
2854
  -h, --help : help
2737
2855
  -v : version
2738
- -x : converted code
2739
- -T : don't trim spaces around '<% %>'
2856
+ -x : show converted code
2857
+ -z : syntax checking
2740
2858
  -b : body only (no preamble nor postamble)
2741
2859
  -e : escape (equal to '--E Escape')
2742
2860
  -p pattern : embedded pattern (default '<% %>')
@@ -2744,7 +2862,8 @@ Usage: #{command} [..options..] [file ...]
2744
2862
  -E e1,e2,... : enhancer names (Escape, PercentLine, BiPattern, ...)
2745
2863
  -I path : library include path
2746
2864
  -K kanji : kanji code (euc/sjis/utf8) (default none)
2747
- -f file.yaml : YAML file for context values (read stdin if filename is '-')
2865
+ -c context : context data string (yaml inline style or ruby code)
2866
+ -f datafile : context data file ('*.yaml', '*.yml', or '*.rb')
2748
2867
  -t : expand tab character in YAML file
2749
2868
  -S : convert mapping key from string to symbol in YAML file
2750
2869
  -B : invoke 'result(binding)' instead of 'evaluate(context)'
@@ -2752,6 +2871,7 @@ Usage: #{command} [..options..] [file ...]
2752
2871
 
2753
2872
  END
2754
2873
  #'
2874
+ # -T : don't trim spaces around '<% %>'
2755
2875
  # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
2756
2876
  # -r library : require library
2757
2877
  # -a : action (convert/execute)
@@ -2806,8 +2926,7 @@ END
2806
2926
  end
2807
2927
 
2808
2928
  def version
2809
- release = ('$Release: 2.1.0 $' =~ /([.\d]+)/) && $1
2810
- return release
2929
+ return Erubis::VERSION
2811
2930
  end
2812
2931
 
2813
2932
  def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
@@ -2914,27 +3033,51 @@ END
2914
3033
  return enhancers
2915
3034
  end
2916
3035
 
2917
- def load_yamlfiles(yamlfiles, opts)
2918
- hash = {}
2919
- return hash unless yamlfiles
2920
- yamlfiles.split(/,/).each do |yamlfile|
2921
- if yamlfile == '-'
2922
- str = $stdin.read()
3036
+ def load_datafiles(filenames, opts)
3037
+ context = Erubis::Context.new
3038
+ return hash unless filenames
3039
+ filenames.split(/,/).each do |filename|
3040
+ filename.strip!
3041
+ test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
3042
+ if filename =~ /\.ya?ml$/
3043
+ if opts.untabify
3044
+ ydoc = YAML.load(untabify(File.read(filename)))
3045
+ else
3046
+ ydoc = YAML.load_file(filename)
3047
+ end
3048
+ ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
3049
+ intern_hash_keys(ydoc) if opts.intern
3050
+ context.update(ydoc)
3051
+ elsif filename =~ /\.rb$/
3052
+ str = File.read(filename)
3053
+ context2 = Erubis::Context.new
3054
+ _instance_eval(context2, str)
3055
+ context.update(context2)
2923
3056
  else
2924
- test(?f, yamlfile) or raise CommandOptionError.new("#{yamlfile}: file not found.")
2925
- str = File.read(yamlfile)
3057
+ CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
2926
3058
  end
2927
- str = yamlfile == '-' ? $stdin.read() : File.read(yamlfile)
2928
- str = untabify(str) if opts.untabify
2929
- ydoc = YAML.load(str)
3059
+ end
3060
+ return context
3061
+ end
3062
+
3063
+ def _instance_eval(_context, _str)
3064
+ _context.instance_eval(_str)
3065
+ end
3066
+
3067
+ def parse_context_data(context_str, opts)
3068
+ if context_str[0] == ?{
3069
+ require 'yaml'
3070
+ ydoc = YAML.load(context_str)
2930
3071
  unless ydoc.is_a?(Hash)
2931
- raise CommandOptionError.new("#{yamlfile}: root object is not a mapping.")
3072
+ raise CommandOptionError.new("-c: root object is not a mapping.")
2932
3073
  end
2933
3074
  intern_hash_keys(ydoc) if opts.intern
2934
- hash.update(ydoc)
3075
+ return ydoc
3076
+ else
3077
+ context = Erubis::Context.new
3078
+ context.instance_eval(context_str, '-c')
3079
+ return context
2935
3080
  end
2936
- context = hash
2937
- return context
2938
3081
  end
2939
3082
 
2940
3083
  def intern_hash_keys(obj, done={})
@@ -2956,6 +3099,21 @@ END
2956
3099
  end
2957
3100
  end
2958
3101
 
3102
+ def check_syntax(filename, src)
3103
+ require 'open3'
3104
+ stdin, stdout, stderr = Open3.popen3('ruby -wc')
3105
+ stdin.write(src)
3106
+ stdin.close
3107
+ result = stdout.read()
3108
+ stdout.close()
3109
+ errmsg = stderr.read()
3110
+ stderr.close()
3111
+ return nil unless errmsg && !errmsg.empty?
3112
+ errmsg =~ /\A-:(\d+): /
3113
+ linenum, message = $1, $'
3114
+ return "#{filename}:#{linenum}: #{message}"
3115
+ end
3116
+
2959
3117
  end
2960
3118
 
2961
3119
  end