nitro 0.25.0 → 0.26.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +531 -1
- data/ProjectInfo +29 -5
- data/README +1 -1
- data/doc/AUTHORS +12 -6
- data/doc/RELEASES +114 -0
- data/lib/glue/sweeper.rb +71 -0
- data/lib/nitro.rb +19 -12
- data/lib/nitro/adapter/cgi.rb +4 -0
- data/lib/nitro/adapter/webrick.rb +4 -2
- data/lib/nitro/caching.rb +1 -0
- data/lib/nitro/caching/fragments.rb +7 -1
- data/lib/nitro/caching/output.rb +6 -1
- data/lib/nitro/caching/stores.rb +13 -1
- data/lib/nitro/cgi.rb +9 -1
- data/lib/nitro/cgi/request.rb +11 -3
- data/lib/nitro/cgi/utils.rb +24 -2
- data/lib/nitro/compiler.rb +89 -63
- data/lib/nitro/compiler/cleanup.rb +16 -0
- data/lib/nitro/compiler/elements.rb +117 -0
- data/lib/nitro/compiler/markup.rb +3 -1
- data/lib/nitro/compiler/morphing.rb +203 -73
- data/lib/nitro/compiler/script_generator.rb +14 -0
- data/lib/nitro/compiler/shaders.rb +1 -1
- data/lib/nitro/context.rb +5 -6
- data/lib/nitro/controller.rb +43 -21
- data/lib/nitro/dispatcher.rb +86 -37
- data/lib/nitro/element.rb +3 -105
- data/lib/nitro/helper/benchmark.rb +3 -0
- data/lib/nitro/helper/dojo.rb +0 -0
- data/lib/nitro/helper/form.rb +85 -255
- data/lib/nitro/helper/form/controls.rb +274 -0
- data/lib/nitro/helper/javascript.rb +86 -6
- data/lib/nitro/helper/pager.rb +5 -0
- data/lib/nitro/helper/prototype.rb +49 -0
- data/lib/nitro/helper/scriptaculous.rb +0 -0
- data/lib/nitro/helper/xhtml.rb +11 -8
- data/lib/nitro/helper/xml.rb +1 -1
- data/lib/nitro/routing.rb +8 -1
- data/lib/nitro/scaffolding.rb +344 -0
- data/lib/nitro/server.rb +5 -1
- data/lib/nitro/server/runner.rb +19 -15
- data/lib/nitro/session.rb +32 -56
- data/lib/nitro/session/drbserver.rb +1 -1
- data/lib/nitro/session/file.rb +34 -15
- data/lib/nitro/session/memory.rb +13 -4
- data/lib/nitro/session/og.rb +56 -0
- data/proto/public/js/controls.js +30 -1
- data/proto/public/js/dragdrop.js +211 -146
- data/proto/public/js/effects.js +261 -399
- data/proto/public/js/prototype.js +131 -72
- data/proto/public/scaffold/edit.xhtml +10 -3
- data/proto/public/scaffold/form.xhtml +1 -7
- data/proto/public/scaffold/index.xhtml +20 -0
- data/proto/public/scaffold/list.xhtml +15 -8
- data/proto/public/scaffold/new.xhtml +10 -3
- data/proto/public/scaffold/search.xhtml +28 -0
- data/proto/public/scaffold/view.xhtml +8 -0
- data/proto/run.rb +93 -1
- data/src/part/admin.rb +4 -2
- data/src/part/admin/controller.rb +62 -28
- data/src/part/admin/skin.rb +8 -8
- data/src/part/admin/system.css +135 -0
- data/src/part/admin/template/index.xhtml +8 -12
- data/test/nitro/caching/tc_stores.rb +17 -0
- data/test/nitro/tc_caching.rb +1 -4
- data/test/nitro/tc_dispatcher.rb +22 -10
- data/test/nitro/tc_element.rb +1 -1
- data/test/nitro/tc_session.rb +23 -11
- data/test/public/blog/another/very_litle/index.xhtml +1 -0
- metadata +29 -15
- data/lib/nitro/dispatcher/general.rb +0 -62
- data/lib/nitro/dispatcher/nice.rb +0 -57
- data/lib/nitro/scaffold.rb +0 -171
- data/proto/public/index.xhtml +0 -83
- data/proto/public/js/scaffold.js +0 -74
- data/proto/public/settings.xhtml +0 -66
data/lib/nitro/caching/stores.rb
CHANGED
@@ -2,6 +2,8 @@ require 'fileutils'
|
|
2
2
|
|
3
3
|
require 'mega/synchash'
|
4
4
|
|
5
|
+
require 'glue/attribute'
|
6
|
+
|
5
7
|
module Nitro
|
6
8
|
|
7
9
|
# Adds support for caching.
|
@@ -20,8 +22,10 @@ module Caching
|
|
20
22
|
self[name] = content
|
21
23
|
end
|
22
24
|
|
25
|
+
alias_method :old_delete, :delete
|
26
|
+
|
23
27
|
def delete(name, options = {})
|
24
|
-
|
28
|
+
old_delete(name)
|
25
29
|
end
|
26
30
|
|
27
31
|
end
|
@@ -69,8 +73,16 @@ module Caching
|
|
69
73
|
|
70
74
|
end
|
71
75
|
|
76
|
+
#--
|
77
|
+
# TODO: implement me
|
78
|
+
#++
|
79
|
+
|
72
80
|
class DrbStrore
|
73
81
|
end
|
82
|
+
|
83
|
+
#--
|
84
|
+
# TODO: implement me
|
85
|
+
#++
|
74
86
|
|
75
87
|
class MemcacheStore
|
76
88
|
end
|
data/lib/nitro/cgi.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
require 'glue/configuration'
|
2
4
|
require 'nitro/cgi/http'
|
3
5
|
|
@@ -23,6 +25,12 @@ class Cgi
|
|
23
25
|
context.in = inp
|
24
26
|
context.headers = cgi.env
|
25
27
|
|
28
|
+
# gmosx: QUERY_STRING is sometimes not populated.
|
29
|
+
|
30
|
+
if context.query_string.empty? and context.uri =~ /\?/
|
31
|
+
context.headers['QUERY_STRING'] = context.uri.split('?').last
|
32
|
+
end
|
33
|
+
|
26
34
|
Cgi.parse_params(context)
|
27
35
|
Cgi.parse_cookies(context)
|
28
36
|
context.render(context.path)
|
@@ -293,4 +301,4 @@ end
|
|
293
301
|
end
|
294
302
|
|
295
303
|
# * George Moschovitis <gm@navel.gr>
|
296
|
-
# * Guillaume Pierronnet <guillaume.pierronnet@gmail.com>
|
304
|
+
# * Guillaume Pierronnet <guillaume.pierronnet@gmail.com>
|
data/lib/nitro/cgi/request.rb
CHANGED
@@ -39,7 +39,7 @@ module Request
|
|
39
39
|
# 443 == port
|
40
40
|
@headers['HTTPS'] == 'on'
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
# The request uri.
|
44
44
|
|
45
45
|
def uri
|
@@ -84,7 +84,14 @@ module Request
|
|
84
84
|
#++
|
85
85
|
|
86
86
|
def query_string
|
87
|
-
|
87
|
+
=begin
|
88
|
+
qs = headers['QUERY_STRING']
|
89
|
+
if qs.empty? and uri =~ /\?/
|
90
|
+
qs = headers['QUERY_STRING'] = uri.split('?').last
|
91
|
+
end
|
92
|
+
return qs
|
93
|
+
=end
|
94
|
+
headers['QUERY_STRING']
|
88
95
|
end
|
89
96
|
|
90
97
|
# The request method. Alternatively you could use the
|
@@ -160,6 +167,7 @@ module Request
|
|
160
167
|
not /XMLHttpRequest/i.match(@headers['HTTP_X_REQUESTED_WITH']).nil?
|
161
168
|
end
|
162
169
|
alias xhr? :xml_http_request?
|
170
|
+
alias ajax? :xml_http_request?
|
163
171
|
|
164
172
|
# Return the referer. For the initial page in the
|
165
173
|
# clickstream there is no referer, set "/" by default.
|
@@ -187,7 +195,7 @@ module Request
|
|
187
195
|
|
188
196
|
if @headers.include?('HTTP_X_FORWARDED_FOR') then
|
189
197
|
remote_ips = @headers['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
|
190
|
-
ip =~ /^unknown$|^(10|172\.16|192\.168)\./i
|
198
|
+
ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
|
191
199
|
end
|
192
200
|
|
193
201
|
return remote_ips.first.strip unless remote_ips.empty?
|
data/lib/nitro/cgi/utils.rb
CHANGED
@@ -10,7 +10,9 @@ module Request
|
|
10
10
|
# Different servers hold user agent in differnet
|
11
11
|
# strings (unify this).
|
12
12
|
|
13
|
-
def user_agent
|
14
13
|
headers['HTTP_USER_AGENT'] || headers['USER-AGENT']
|
15
14
|
end
|
15
|
+
def user_agent
|
16
|
+
headers['HTTP_USER_AGENT'] || headers['USER-AGENT']
|
17
|
+
end
|
16
18
|
|
17
19
|
def from_gecko?
|
18
20
|
user_agent =~ /Gecko/
|
@@ -34,9 +36,29 @@ module Request
|
|
34
36
|
def from_w3c?
|
35
37
|
from_gecko? or from_khtml? or from_opera?
|
36
38
|
end
|
39
|
+
|
40
|
+
def from_osx?
|
41
|
+
user_agent =~ /Mac OS X/ or user_agent =~ /Mac_PowerPC/
|
42
|
+
end
|
43
|
+
|
44
|
+
def from_os9?
|
45
|
+
end
|
46
|
+
|
47
|
+
def from_mac?
|
48
|
+
from_osx? or from_os9?
|
49
|
+
end
|
50
|
+
|
51
|
+
def from_unix?
|
52
|
+
user_agent =~ /linux/ or user_agent =~ /FreeBSD/
|
53
|
+
end
|
54
|
+
alias_method :from_linux?, :from_unix?
|
55
|
+
|
56
|
+
def from_windows?
|
57
|
+
user_agent =~ /Windows/
|
58
|
+
end
|
37
59
|
|
38
60
|
end
|
39
61
|
|
40
62
|
end
|
41
63
|
|
42
|
-
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
64
|
+
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
data/lib/nitro/compiler.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
require 'nano/kernel/singleton'
|
2
2
|
|
3
3
|
require 'glue/template'
|
4
|
+
|
5
|
+
require 'nitro/compiler/elements'
|
4
6
|
require 'nitro/compiler/errors'
|
7
|
+
require 'nitro/compiler/markup'
|
8
|
+
require 'nitro/compiler/morphing'
|
9
|
+
require 'nitro/compiler/include'
|
10
|
+
require 'nitro/compiler/cleanup'
|
5
11
|
|
6
12
|
module Nitro
|
7
13
|
|
@@ -13,6 +19,10 @@ class Compiler
|
|
13
19
|
unless const_defined? :PROTO_TEMPLATE_ROOT
|
14
20
|
PROTO_TEMPLATE_ROOT = "#{Nitro.proto_path}/public"
|
15
21
|
end
|
22
|
+
|
23
|
+
# The controller for this compiler.
|
24
|
+
|
25
|
+
attr_accessor :controller
|
16
26
|
|
17
27
|
# Set to true to force reloading of code and templates for
|
18
28
|
# each request. Extremely useful during development. Must be
|
@@ -20,50 +30,81 @@ class Compiler
|
|
20
30
|
# performance penalty.
|
21
31
|
|
22
32
|
setting :reload, :default => true, :doc => 'If true all code and templates are reloaded in each request'
|
23
|
-
|
33
|
+
|
34
|
+
def initialize(controller = nil)
|
35
|
+
@controller = controller
|
36
|
+
end
|
37
|
+
|
24
38
|
# Action names with double underscores (__) are converted
|
25
39
|
# to subdirectories. Here are some example mappings:
|
26
40
|
#
|
27
41
|
# hello_world -> template_root/hello_world.xhtml
|
28
42
|
# this__is__my__hello_world -> template_root/this/is/my/hello_world
|
29
43
|
|
30
|
-
def template_for_action(action,
|
31
|
-
|
32
|
-
|
44
|
+
def template_for_action(action, ext = Template.extension)
|
45
|
+
cklass = @controller
|
46
|
+
template_root = nil
|
47
|
+
checked_proto = nil
|
48
|
+
|
49
|
+
# search for template in controller and its ancestors's template_root
|
50
|
+
# if there is not an action defined in controller then also check in
|
51
|
+
# PROTO_TEMPLATE_ROOT
|
33
52
|
|
34
|
-
|
53
|
+
loop do
|
54
|
+
if cklass.respond_to?(:template_root) && template_root = cklass.template_root
|
55
|
+
cklass = cklass.superclass
|
56
|
+
elsif !@controller.respond_to?(:action) && !checked_proto
|
57
|
+
template_root = PROTO_TEMPLATE_ROOT
|
58
|
+
checked_proto = true
|
59
|
+
else
|
60
|
+
return nil # no template found
|
61
|
+
end
|
62
|
+
|
63
|
+
# attempt to find a template of the form
|
64
|
+
# template_root/action.xhtml
|
35
65
|
|
36
|
-
|
66
|
+
path = "#{template_root}/#{action.gsub(/__/, '/')}.#{ext}".squeeze('/')
|
67
|
+
return path if File.exist?(path)
|
68
|
+
|
37
69
|
# attempt to find a template of the form
|
38
70
|
# template_root/action/index.xhtml
|
39
71
|
|
40
72
|
path = "#{template_root}/#{action.gsub(/__/, '/')}/#{Template.default}.#{ext}".squeeze('/')
|
41
|
-
|
42
|
-
unless File.exist?(path)
|
43
|
-
# No template found!
|
44
|
-
return nil
|
45
|
-
end
|
73
|
+
return path if File.exist?(path)
|
46
74
|
end
|
75
|
+
end
|
76
|
+
alias_method :template?, :template_for_action
|
77
|
+
|
78
|
+
# Helper.
|
47
79
|
|
48
|
-
|
80
|
+
def action?(sym)
|
81
|
+
return @controller.action_methods.include?(sym.to_s)
|
49
82
|
end
|
50
83
|
|
51
|
-
# This
|
84
|
+
# This method transforms the template. Typically
|
52
85
|
# template processors are added as aspects to this method
|
53
86
|
# to allow for customized template transformation prior
|
54
87
|
# to compilation.
|
55
88
|
#
|
56
89
|
# The default transformation extracts the Ruby code from
|
57
|
-
# processing instructions
|
90
|
+
# processing instructions, and uses the StaticInclude,
|
91
|
+
# Morphing, Elements and Markup compiler modules.
|
58
92
|
|
59
93
|
def transform_template(template)
|
60
|
-
|
94
|
+
template = StaticInclude.transform(template)
|
95
|
+
template = Morphing.transform(template)
|
96
|
+
template = Elements.transform(template)
|
97
|
+
template = Markup.transform(template)
|
98
|
+
template = Cleanup.transform(template)
|
99
|
+
template = Template.transform(template)
|
61
100
|
end
|
62
101
|
|
63
102
|
# Compile the template into a render method.
|
103
|
+
# Don't compile the template if the controller
|
104
|
+
# responds_to? #{action}_template.
|
64
105
|
|
65
|
-
def compile_template(
|
66
|
-
Logger.debug "Compiling template '#{
|
106
|
+
def compile_template(action, path)
|
107
|
+
Logger.debug "Compiling template '#{@controller}: #{path}'" if $DBG
|
67
108
|
|
68
109
|
template = File.read(path)
|
69
110
|
|
@@ -74,7 +115,7 @@ class Compiler
|
|
74
115
|
}
|
75
116
|
|
76
117
|
begin
|
77
|
-
|
118
|
+
@controller.class_eval(code, path)
|
78
119
|
rescue SyntaxError => e
|
79
120
|
raise TemplateCompileError.new(code, template, e)
|
80
121
|
end
|
@@ -88,18 +129,12 @@ class Compiler
|
|
88
129
|
# TODO: cleanup this method.
|
89
130
|
#++
|
90
131
|
|
91
|
-
def compile_action(
|
92
|
-
#--
|
93
|
-
# gmosx: Move elsewhere.
|
94
|
-
#++
|
95
|
-
|
96
|
-
Aspects.include_advice_modules(klass)
|
97
|
-
|
132
|
+
def compile_action(action)
|
98
133
|
action = action.to_s.gsub(/_action$/, '')
|
99
|
-
|
134
|
+
|
100
135
|
return false unless action
|
101
136
|
|
102
|
-
Logger.debug "Compiling action '
|
137
|
+
Logger.debug "Compiling action '#@controller##{action}'" if $DBG
|
103
138
|
|
104
139
|
valid = false
|
105
140
|
|
@@ -111,16 +146,16 @@ class Compiler
|
|
111
146
|
|
112
147
|
# Inject the pre advices.
|
113
148
|
|
114
|
-
code << Aspects.gen_advice_code(action,
|
149
|
+
code << Aspects.gen_advice_code(action, @controller.advices, :pre)
|
115
150
|
|
116
151
|
# Call the action
|
117
152
|
|
118
|
-
if
|
153
|
+
if @controller.action_methods.include?(action)
|
119
154
|
valid = true
|
120
155
|
|
121
156
|
# Annotated parameters.
|
122
157
|
|
123
|
-
if params =
|
158
|
+
if params = @controller.ann(action.to_sym).params and (!params.nil?)
|
124
159
|
params = params.collect { |p| "@#{p} = @context['#{p}']" }
|
125
160
|
code << "#{params.join(';')}"
|
126
161
|
end
|
@@ -128,7 +163,7 @@ class Compiler
|
|
128
163
|
# Try to resolve action parameters. Returns negative
|
129
164
|
# numbers for arbitrary parameters.
|
130
165
|
|
131
|
-
param_count =
|
166
|
+
param_count = @controller.instance_method(action.intern).arity
|
132
167
|
|
133
168
|
if param_count != 0
|
134
169
|
if param_count > 0
|
@@ -172,38 +207,22 @@ class Compiler
|
|
172
207
|
|
173
208
|
# Take :view annotation into account.
|
174
209
|
|
175
|
-
view =
|
210
|
+
view = @controller.ann(action.to_sym).view # FIXME
|
176
211
|
view = action if view.nil?
|
177
212
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
# Don't use a proto template if there is an action
|
189
|
-
# defined.
|
190
|
-
|
191
|
-
template_root ||= PROTO_TEMPLATE_ROOT unless valid
|
192
|
-
|
193
|
-
if template_root and template_path = template_for_action(view.to_s, template_root)
|
194
|
-
valid = true
|
195
|
-
code << %{
|
196
|
-
#{action}_template;
|
197
|
-
}
|
198
|
-
break
|
199
|
-
end
|
200
|
-
|
201
|
-
break unless cklass = cklass.superclass
|
213
|
+
# Search the [controller] class and it's ancestors for the template
|
214
|
+
|
215
|
+
template_path = template_for_action(view.to_s)
|
216
|
+
if template_path or @controller.instance_methods.include?("#{action}_template")
|
217
|
+
valid = true
|
218
|
+
code << %{
|
219
|
+
#{action}_template
|
220
|
+
}
|
202
221
|
end
|
203
222
|
|
204
223
|
return false unless valid
|
205
224
|
|
206
|
-
if
|
225
|
+
if @controller.action_methods.include?(action)
|
207
226
|
code << %{
|
208
227
|
if @out.empty? and action_return_value.is_a?(String)
|
209
228
|
print(action_return_value)
|
@@ -220,7 +239,7 @@ class Compiler
|
|
220
239
|
|
221
240
|
# Inject the post advices.
|
222
241
|
|
223
|
-
code << Aspects.gen_advice_code(action,
|
242
|
+
code << Aspects.gen_advice_code(action, @controller.advices, :post)
|
224
243
|
|
225
244
|
code << %{
|
226
245
|
@action_name = @parent_action_name
|
@@ -230,12 +249,16 @@ class Compiler
|
|
230
249
|
# First compile the action method.
|
231
250
|
|
232
251
|
# begin
|
233
|
-
|
252
|
+
@controller.class_eval(code)
|
234
253
|
# rescue SyntaxError => e
|
235
254
|
# raise ActionCompileError.new(code, action, e)
|
236
255
|
# end
|
237
|
-
|
238
|
-
|
256
|
+
|
257
|
+
unless @controller.respond_to?("#{action}_template")
|
258
|
+
if template_path
|
259
|
+
compile_template(action, template_path)
|
260
|
+
end
|
261
|
+
end
|
239
262
|
|
240
263
|
return true
|
241
264
|
end
|
@@ -243,8 +266,8 @@ class Compiler
|
|
243
266
|
# Compiles an action method in the given (controller) class.
|
244
267
|
# A sync is used to make compilation thread safe.
|
245
268
|
|
246
|
-
def compile(
|
247
|
-
compile_action(
|
269
|
+
def compile(action)
|
270
|
+
compile_action(action)
|
248
271
|
end
|
249
272
|
|
250
273
|
# :section: Helper methods.
|
@@ -279,3 +302,6 @@ class Compiler
|
|
279
302
|
end
|
280
303
|
|
281
304
|
end
|
305
|
+
|
306
|
+
# * George Moschovitis <gm@navel.gr>
|
307
|
+
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'rexml/streamlistener'
|
3
|
+
|
4
|
+
require 'nitro/element'
|
5
|
+
require "glue/html"
|
6
|
+
|
7
|
+
module Nitro
|
8
|
+
|
9
|
+
# A compiler that handles the processing of Elements
|
10
|
+
|
11
|
+
class Elements # :nodoc: all
|
12
|
+
|
13
|
+
class Listener # :nodoc: all
|
14
|
+
include REXML::StreamListener
|
15
|
+
|
16
|
+
attr_accessor :buffer
|
17
|
+
attr_accessor :stack
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
@buffer = ''
|
22
|
+
@stack = []
|
23
|
+
end
|
24
|
+
|
25
|
+
PREFIX_RE = /^#{Element.prefix}:/
|
26
|
+
CAPITALIZED_RE = /^[A-Z]/
|
27
|
+
|
28
|
+
def tag_start(name, attributes)
|
29
|
+
# check if the name starts with the element prefix, or
|
30
|
+
# is capitalized.
|
31
|
+
if name =~ PREFIX_RE or name =~ CAPITALIZED_RE
|
32
|
+
name = name.split(':')[1].camelize if name =~ PREFIX_RE
|
33
|
+
|
34
|
+
obj = Object.const_get(name).new
|
35
|
+
|
36
|
+
attributes.each do | k, v |
|
37
|
+
obj.instance_variable_set("@#{k}", v)
|
38
|
+
end
|
39
|
+
|
40
|
+
@stack.push [obj, @buffer, @parent]
|
41
|
+
|
42
|
+
@buffer = obj._text
|
43
|
+
@parent.add_child(obj) if @parent
|
44
|
+
|
45
|
+
@parent = obj
|
46
|
+
else # This is a static element.
|
47
|
+
attrs = []
|
48
|
+
|
49
|
+
attributes.each do | k, v |
|
50
|
+
attrs << %|#{k}="#{v}"|
|
51
|
+
end
|
52
|
+
|
53
|
+
attrs = attrs.empty? ? nil : " #{attrs.join(' ')}"
|
54
|
+
|
55
|
+
@buffer << "<#{name}#{attrs}>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def tag_end(name)
|
60
|
+
# check if the name starts with the element prefix, or
|
61
|
+
# is capitalized.
|
62
|
+
if name =~ PREFIX_RE or name =~ CAPITALIZED_RE
|
63
|
+
name = name.split(':')[1].camelize if name =~ PREFIX_RE
|
64
|
+
obj, @buffer, @parent = @stack.pop
|
65
|
+
@buffer << obj.render
|
66
|
+
else
|
67
|
+
@buffer << "</#{name}>"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def text(str)
|
72
|
+
@buffer << str
|
73
|
+
end
|
74
|
+
|
75
|
+
def instruction(name, attributes)
|
76
|
+
@buffer << "<?#{name}#{attributes}?>"
|
77
|
+
end
|
78
|
+
|
79
|
+
def comment(c)
|
80
|
+
unless Template.strip_xml_comments
|
81
|
+
@buffer << "<!--#{c}-->"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class << self
|
87
|
+
def parse(source)
|
88
|
+
self.new.parse(source)
|
89
|
+
end
|
90
|
+
|
91
|
+
def transform(source)
|
92
|
+
self.new.transform(source)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Expand the elemens found in source.
|
97
|
+
|
98
|
+
def transform(source)
|
99
|
+
listener = Listener.new
|
100
|
+
REXML::Document.parse_stream(source, listener)
|
101
|
+
# gmosx, FIXME: optimize this, how?
|
102
|
+
# gmosx, FIXME: this is a hack fix, improve.
|
103
|
+
# TODO:farms why is cleanup called this many times?!?!? ... waste of gsubs
|
104
|
+
return listener.buffer
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# An (old) alias.
|
109
|
+
|
110
|
+
unless const_defined? :ElementProcessor
|
111
|
+
ElementProcessor = Elements
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
# * George Moschovitis <gm@navel.gr>
|
117
|
+
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|