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
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'nitro/helper/xhtml'
|
2
|
+
|
3
|
+
module Nitro
|
4
|
+
|
5
|
+
# :section: Property controls.
|
6
|
+
|
7
|
+
# A Form control.
|
8
|
+
|
9
|
+
class Control
|
10
|
+
include Nitro::XhtmlHelper
|
11
|
+
|
12
|
+
# Fetch the instance vars in a nice way use either rel
|
13
|
+
# or prop.
|
14
|
+
#
|
15
|
+
# values/value contain the contents of the prop or rel,
|
16
|
+
# (values reads better for relations)
|
17
|
+
|
18
|
+
attr_reader :prop
|
19
|
+
alias_method :rel, :prop
|
20
|
+
|
21
|
+
attr_reader :obj
|
22
|
+
|
23
|
+
attr_reader :value
|
24
|
+
alias_method :values, :value
|
25
|
+
|
26
|
+
# setup instance vars to use in methods
|
27
|
+
|
28
|
+
def initialize(obj, key, value=nil)
|
29
|
+
@obj = obj
|
30
|
+
@prop = key
|
31
|
+
@value = value || obj.send(key.name.to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Main bulk of the control. Overide to customise
|
35
|
+
|
36
|
+
def render
|
37
|
+
"No view for this control"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Label item. Override to customise
|
41
|
+
|
42
|
+
def label
|
43
|
+
%{<label for="#{prop.name}">#{prop[:title] || prop.name.to_s.humanize}</label>}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Custom callback to process the request information
|
47
|
+
# posted back from the form
|
48
|
+
#
|
49
|
+
# When Property.populate_object (or fill) is called
|
50
|
+
# with the :preprocess => true option then this
|
51
|
+
# method will get called before the value is pushed
|
52
|
+
# onto the object that is getting 'filled'
|
53
|
+
#
|
54
|
+
# Overide this on controls that require special mods
|
55
|
+
# to the incoming values
|
56
|
+
|
57
|
+
def on_populate(val)
|
58
|
+
puts "PREPROCESSING !"
|
59
|
+
return val
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def emit_style
|
65
|
+
if prop.respond_to?(:control_style)
|
66
|
+
style = prop.control_style
|
67
|
+
elsif self.class.respond_to?(:style)
|
68
|
+
style = self.class.style
|
69
|
+
else
|
70
|
+
style = nil
|
71
|
+
end
|
72
|
+
style ? %{ style="#{style}"} : ''
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
# Fixnum
|
78
|
+
|
79
|
+
class FixnumControl < Control
|
80
|
+
setting :style, :default => 'width: 100px', :doc => 'The default style'
|
81
|
+
|
82
|
+
def render
|
83
|
+
style = prop.control_style ||self.class.style
|
84
|
+
%{<input type="text" id="#{prop.symbol}_ctl" name="#{prop.symbol}" value="#{value}"#{emit_style} /> + -}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Float
|
89
|
+
|
90
|
+
class FloatControl < Control
|
91
|
+
setting :style, :default => 'width: 100px', :doc => 'The default style'
|
92
|
+
|
93
|
+
def render
|
94
|
+
style = prop.control_style ||self.class.style
|
95
|
+
%{<input type="text" id="#{prop.symbol}_ctl" name="#{prop.symbol}" value="#{value}"#{emit_style} /> + -}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Text
|
100
|
+
|
101
|
+
class TextControl < Control
|
102
|
+
setting :style, :default => 'width: 250px', :doc => 'The default style'
|
103
|
+
|
104
|
+
def render
|
105
|
+
%{<input type="text" id="#{prop.symbol}_ctl" name="#{prop.symbol}" value="#{value}"#{emit_style} />}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Textarea
|
110
|
+
|
111
|
+
class TextareaControl < Control
|
112
|
+
setting :style, :default => 'width: 500px; height: 100px', :doc => 'The default style'
|
113
|
+
|
114
|
+
def render
|
115
|
+
%{<textarea id="#{prop.symbol}_ctl" name="#{prop.symbol}"#{emit_style}>#{value}</textarea>}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# CheckboxControl < Control
|
120
|
+
|
121
|
+
class CheckboxControl < Control
|
122
|
+
setting :style, :default => '', :doc => 'The default style'
|
123
|
+
|
124
|
+
def render
|
125
|
+
checked = value == true ? ' checked="checked"':''
|
126
|
+
%{<input type="checkbox" id="#{prop.symbol}_ctl" name="#{prop.symbol}" value="true"#{emit_style}#{checked} />}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# :section: Relation controls.
|
131
|
+
|
132
|
+
# RefersTo. Also used for BelongsTo.
|
133
|
+
|
134
|
+
class RefersToControl < Control
|
135
|
+
def render
|
136
|
+
objs = rel.target_class.all
|
137
|
+
if selected = value
|
138
|
+
selected = selected.pk
|
139
|
+
end
|
140
|
+
|
141
|
+
str = %{<select id="#{rel.name}_ctl" name="#{rel.name}">}
|
142
|
+
str << %{<option value="nil">None</option>}
|
143
|
+
str << %{#{options(:labels => objs.map{|o| o.to_s}, :values => objs.map{|o| o.pk}, :selected => selected)}</select>}
|
144
|
+
|
145
|
+
return str
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# HasMany, ManyToMany and JoinsMany
|
150
|
+
|
151
|
+
class HasManyControl < Control
|
152
|
+
|
153
|
+
#pre :do_this, :on => :populate_object
|
154
|
+
|
155
|
+
def render
|
156
|
+
str = emit_container_start
|
157
|
+
str << emit_js
|
158
|
+
if selected_items.empty?
|
159
|
+
str << emit_selector(all_items, :removable => false)
|
160
|
+
else
|
161
|
+
removable = selected_items.size != 1 ? true : false
|
162
|
+
selected_items.each do |item|
|
163
|
+
str << emit_selector(all_items, :selected => item.pk)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
str << emit_container_end
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
# these parts are seperated from render to make it easier
|
172
|
+
# to extend and customise the HasManyControl
|
173
|
+
|
174
|
+
def all_items
|
175
|
+
rel.target_class.all
|
176
|
+
end
|
177
|
+
|
178
|
+
def selected_items
|
179
|
+
values
|
180
|
+
end
|
181
|
+
|
182
|
+
def emit_container_start
|
183
|
+
%{<div class="many_to_many_container">}
|
184
|
+
end
|
185
|
+
|
186
|
+
def emit_container_end
|
187
|
+
%{</div>}
|
188
|
+
end
|
189
|
+
|
190
|
+
# :removable controls wether the minus button is active
|
191
|
+
# :selected denotes the oid to flag as selected in the list
|
192
|
+
|
193
|
+
def emit_selector(items, options={})
|
194
|
+
removable = options.fetch(:removable, true)
|
195
|
+
%{
|
196
|
+
<div>
|
197
|
+
<select class="has_many_ctl" name="#{rel.name}[]" #{emit_style}>
|
198
|
+
<option value="nil">None</option>
|
199
|
+
#{options(:labels => items.map{|o| o.to_s}, :values => items.map{|o| o.pk}, :selected => options[:selected])}
|
200
|
+
</select>
|
201
|
+
<input type="button" class="#{rel.name}_remove_btn" value=" - " onclick="rm_#{rel.name}_rel(this);" #{'disabled="disabled"' unless removable} />
|
202
|
+
<input type="button" class="#{rel.name}_add_btn" value=" + " onclick="add_#{rel.name}_rel(this);" />
|
203
|
+
</div>
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
# Inline script: override this to change behavior
|
208
|
+
|
209
|
+
def emit_js
|
210
|
+
%{
|
211
|
+
<script type="text/javascript">
|
212
|
+
rm_#{rel.name}_rel = function(el){
|
213
|
+
ctl=el.parentNode;
|
214
|
+
container=ctl.parentNode;
|
215
|
+
container.removeChild(ctl);
|
216
|
+
inputTags = container.getElementsByTagName('input');
|
217
|
+
if(inputTags.length==2)
|
218
|
+
inputTags[0].disabled='disabled';
|
219
|
+
}
|
220
|
+
add_#{rel.name}_rel = function(el){
|
221
|
+
ctl=el.parentNode;
|
222
|
+
container=ctl.parentNode;
|
223
|
+
node=ctl.cloneNode(true);
|
224
|
+
node.getElementsByTagName('input')[0].removeAttribute('disabled');
|
225
|
+
if(container.lastChild==ctl) container.appendChild(node);
|
226
|
+
else container.insertBefore(node, ctl.nextSibling);
|
227
|
+
if(container.childNodes.length>1) container.getElementsByTagName('input')[0].disabled='';
|
228
|
+
}
|
229
|
+
</script>
|
230
|
+
}
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# The controls map.
|
235
|
+
|
236
|
+
class Control
|
237
|
+
|
238
|
+
# Setup the mapping of names => control classes
|
239
|
+
|
240
|
+
setting :map, :doc => 'Mappings of control names => classes', :default => {
|
241
|
+
:fixnum => FixnumControl,
|
242
|
+
:float => FloatControl,
|
243
|
+
:boolean => CheckboxControl,
|
244
|
+
:checkbox => CheckboxControl,
|
245
|
+
:string => TextControl,
|
246
|
+
:textarea => TextareaControl,
|
247
|
+
:true_class => CheckboxControl,
|
248
|
+
:refers_to => RefersToControl,
|
249
|
+
:belongs_to => RefersToControl,
|
250
|
+
:has_many => HasManyControl,
|
251
|
+
:many_to_many => HasManyControl,
|
252
|
+
:joins_many => HasManyControl
|
253
|
+
}
|
254
|
+
|
255
|
+
# Fetch a control, setup for 'obj' for a property, or relation
|
256
|
+
# or :symbol defaults to Control if not found
|
257
|
+
|
258
|
+
def self.fetch(obj, key, missing=self)
|
259
|
+
if key.kind_of? Og::Relation
|
260
|
+
control_sym = key[:control] || key.class.to_s.demodulize.underscore.to_sym
|
261
|
+
elsif key.kind_of? Property
|
262
|
+
control_sym = key[:control] || key.klass.to_s.underscore.to_sym
|
263
|
+
else
|
264
|
+
control_sym = key.to_sym
|
265
|
+
end
|
266
|
+
self.map.fetch(control_sym, missing).new(obj, key)
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
# * George Moschovitis <gm@navel.gr>
|
274
|
+
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'nano/inflect'
|
2
|
+
|
3
|
+
require 'nitro/compiler/morphing'
|
4
|
+
|
1
5
|
module Nitro
|
2
6
|
|
3
7
|
# A collection of useful Javascript helpers. This modules
|
@@ -11,7 +15,15 @@ module Nitro
|
|
11
15
|
|
12
16
|
module JavascriptHelper
|
13
17
|
|
14
|
-
|
18
|
+
# Insert an anchor to execute a given function when the link is followed.
|
19
|
+
# Call with the name of the link, and the function to be called:
|
20
|
+
# link_to_function "Do it." :go
|
21
|
+
|
22
|
+
def link_to_function(name, function)
|
23
|
+
%{<a href="#" onclick="#{function}; return false;">#{name}</a>}
|
24
|
+
end
|
25
|
+
|
26
|
+
# -- older stuff --
|
15
27
|
|
16
28
|
unless const_defined? :DEFAULT_JAVASCRIPT_FILES
|
17
29
|
DEFAULT_JAVASCRIPT_FILES = [
|
@@ -24,7 +36,23 @@ private
|
|
24
36
|
end
|
25
37
|
|
26
38
|
# :section: behaviour.js
|
39
|
+
#
|
40
|
+
# Behaviour.js is a third-party library for keeping HTML clean of javascript.
|
41
|
+
# The +behaviour+ method provides an interface to that library.
|
42
|
+
# To learn more about the concept, visit the distributor:
|
43
|
+
# http://bennolan.com/behaviour/
|
27
44
|
|
45
|
+
# Register javascript code with an HTML element of a given id with the
|
46
|
+
# +behaviour+ method.
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
#
|
50
|
+
# behaviour '#alert', %{
|
51
|
+
# el.onclick = function() {
|
52
|
+
# alert('Hello world');
|
53
|
+
# }
|
54
|
+
# }
|
55
|
+
|
28
56
|
def behaviour(id, js)
|
29
57
|
@_behaviours ||= []
|
30
58
|
@_behaviours << [id, js]
|
@@ -32,6 +60,24 @@ private
|
|
32
60
|
end
|
33
61
|
|
34
62
|
# :section: prototype.js
|
63
|
+
#
|
64
|
+
# Prototype.js is a third-party library that provides a number of functions
|
65
|
+
# for AJAX-style interaction with the browser. It depends on the Behaviour.js
|
66
|
+
# library. Prototype's homepage is http://prototype.conio.net/
|
67
|
+
|
68
|
+
# A live, or asynchronous, request is one that does not bring the user to a
|
69
|
+
# new page. It is used to send data back to the web server while the user is
|
70
|
+
# still interacting with a document.
|
71
|
+
#
|
72
|
+
# Call +live+ with the id of an achor element as a string or a symbol.
|
73
|
+
# Alternatively, add <tt>async="true"</tt> to the anchor (A) element. Specify the
|
74
|
+
# anchor to be called either as a second parameter to the +live+ method, or
|
75
|
+
# in the HREF option of the anchor element.
|
76
|
+
#
|
77
|
+
# Examples:
|
78
|
+
#
|
79
|
+
# live :id_of_anchor_element [:method]
|
80
|
+
# <a href="receiver" async="true">Go!</a>
|
35
81
|
|
36
82
|
def live_request(id, options = {})
|
37
83
|
__append_script_file__ 'js/behaviour.js'
|
@@ -57,7 +103,8 @@ private
|
|
57
103
|
alias_method :live, :live_request
|
58
104
|
alias_method :async, :live_request
|
59
105
|
|
60
|
-
#
|
106
|
+
# Clicking the element will make it disappear. If you want it to reappear,
|
107
|
+
# you'll have to call <tt>toggle()</tt>.
|
61
108
|
|
62
109
|
def toggleable(id, options = {})
|
63
110
|
__append_script_file__ 'js/prototype.js'
|
@@ -74,7 +121,7 @@ private
|
|
74
121
|
|
75
122
|
# :section: script.aculo.us dragdrop.js
|
76
123
|
|
77
|
-
#
|
124
|
+
# The user may click and drag the element about the screen.
|
78
125
|
|
79
126
|
def draggable(id, options = {})
|
80
127
|
__append_script_file__ 'js/behaviour.js'
|
@@ -215,7 +262,8 @@ private
|
|
215
262
|
# -----------------------------------------------------------
|
216
263
|
# :section: general javascript helpers.
|
217
264
|
|
218
|
-
#
|
265
|
+
# Inserts links to the .js files necessary for your page. Call it from within
|
266
|
+
# HEAD. Add other script files as arguments if desired.
|
219
267
|
|
220
268
|
def include_script(*files)
|
221
269
|
return if @_script_files.nil? and files.empty?
|
@@ -253,13 +301,15 @@ private
|
|
253
301
|
end
|
254
302
|
alias_method :helper_css, :emit_css
|
255
303
|
|
256
|
-
#
|
304
|
+
# Call this in your template/page to include the javascript statements that
|
305
|
+
# link your HTML to the javascript libraries. Must be called after the HTML
|
306
|
+
# elements involved, i.e., at the bottom of the page.
|
257
307
|
#--
|
258
308
|
# FIXME: refactor this!
|
259
309
|
#++
|
260
310
|
|
261
311
|
def emit_script
|
262
|
-
code = %|<script type="text/javascript">\n|
|
312
|
+
code = %|<script type="text/javascript">\n<!--\n|
|
263
313
|
unless @_behaviours.empty?
|
264
314
|
code << %|var _behaviours = {\n|
|
265
315
|
compo = []
|
@@ -276,6 +326,7 @@ private
|
|
276
326
|
#{@_script.join("\n")}
|
277
327
|
| if @_script
|
278
328
|
code << %|
|
329
|
+
//-->
|
279
330
|
</script>
|
280
331
|
|
|
281
332
|
end
|
@@ -307,6 +358,35 @@ private
|
|
307
358
|
|
308
359
|
end
|
309
360
|
|
361
|
+
# :section: Javascript related morphers.
|
362
|
+
|
363
|
+
# Transform a normal achor into an asynchronous request:
|
364
|
+
# <a href="..." async="true">...</a>
|
365
|
+
# becomes
|
366
|
+
# <a href="#" onclick="new Ajax.Request...; return false;">...</a>
|
367
|
+
|
368
|
+
class AsyncMorpher < Morpher
|
369
|
+
def before_start(buffer)
|
370
|
+
href = @attributes['href']
|
371
|
+
@attributes['href'] = '#'
|
372
|
+
@attributes['onclick'] = "new Ajax.Request('#{href}'); return false;"
|
373
|
+
@attributes.delete(@key)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
class LocalMorpher < Morpher
|
378
|
+
def before_start(buffer)
|
379
|
+
@attributes['href'] = '#'
|
380
|
+
@attributes['onclick'] = "ngs#{@value.camelcase(true)}();"
|
381
|
+
@attributes.delete(@key)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
# Install the morphers.
|
386
|
+
|
387
|
+
Morphing.add_morpher :async, AsyncMorpher
|
388
|
+
Morphing.add_morpher :local, LocalMorpher
|
389
|
+
|
310
390
|
end
|
311
391
|
|
312
392
|
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/helper/pager.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Nitro
|
2
|
+
|
3
|
+
module PrototypeHelper
|
4
|
+
|
5
|
+
def remote_function()
|
6
|
+
end
|
7
|
+
|
8
|
+
#--
|
9
|
+
# TODO: resolve html
|
10
|
+
#++
|
11
|
+
|
12
|
+
class JavascriptGenerator
|
13
|
+
attr_accessor :buffer
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@buffer = ''
|
17
|
+
end
|
18
|
+
|
19
|
+
# html = A string or a symbol to an action for rendering.
|
20
|
+
#--
|
21
|
+
# TODO: resolve html.
|
22
|
+
#++
|
23
|
+
|
24
|
+
def insert_html(id, html, options = {})
|
25
|
+
position = options.fetch(:where, :before)
|
26
|
+
record "new Insertion.#{position.to_s.camelize}(#{id.inspect}, #{html.inspect})"
|
27
|
+
end
|
28
|
+
|
29
|
+
def replace_html(id, html, options = {})
|
30
|
+
record "Element.update(#{id.inspect}, #{html.inspect})"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def record(code)
|
36
|
+
code = "#{line.to_s.chomp.gsub /\;$/, ''};"
|
37
|
+
@buffer << code
|
38
|
+
return code
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# * George Moschovitis <gm@navel.gr>
|