glue 0.31.0 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/AUTHORS +1 -1
- data/doc/LICENSE +2 -3
- data/doc/RELEASES +0 -4
- data/lib/glue.rb +3 -3
- data/lib/glue/attribute.rb +114 -0
- data/lib/glue/attributeutils.rb +117 -0
- data/lib/glue/autoreload.rb +0 -4
- data/lib/glue/builder.rb +0 -2
- data/lib/glue/builder/xml.rb +0 -2
- data/lib/glue/cache.rb +3 -5
- data/lib/glue/cache/drb.rb +0 -2
- data/lib/glue/cache/memory.rb +0 -2
- data/lib/glue/cache/og.rb +11 -6
- data/lib/glue/configuration.rb +60 -15
- data/lib/glue/fixture.rb +3 -5
- data/lib/glue/localization.rb +0 -2
- data/lib/glue/logger.rb +1 -2
- data/lib/glue/mail.rb +0 -2
- data/lib/glue/mailer.rb +4 -2
- data/lib/glue/mailer/incoming.rb +0 -2
- data/lib/glue/mailer/outgoing.rb +3 -5
- data/lib/glue/settings.rb +0 -2
- data/lib/glue/uri.rb +0 -2
- data/lib/glue/validation.rb +6 -8
- data/test/glue/builder/tc_xml.rb +3 -2
- data/test/glue/tc_attribute.rb +112 -0
- data/test/glue/{tc_property_mixins.rb → tc_attribute_mixins.rb} +9 -11
- data/test/glue/tc_configuration.rb +1 -1
- data/test/glue/tc_fixture.rb +4 -3
- data/test/glue/tc_logger.rb +2 -2
- data/test/glue/tc_mail.rb +22 -21
- data/test/glue/tc_stores.rb +0 -2
- data/test/glue/tc_uri.rb +12 -12
- data/test/glue/tc_validation.rb +13 -13
- metadata +52 -64
- data/INSTALL +0 -56
- data/ProjectInfo +0 -49
- data/README +0 -21
- data/lib/glue/markup.rb +0 -123
- data/lib/glue/property.rb +0 -290
- data/lib/glue/sanitize.rb +0 -48
- data/lib/glue/template.rb +0 -219
- data/setup.rb +0 -1585
- data/test/glue/tc_property.rb +0 -112
- data/test/glue/tc_property_type_checking.rb +0 -41
- data/test/glue/tc_template.rb +0 -35
data/lib/glue/property.rb
DELETED
@@ -1,290 +0,0 @@
|
|
1
|
-
require 'facet/annotation'
|
2
|
-
require 'facet/inheritor'
|
3
|
-
require 'facet/dictionary'
|
4
|
-
require 'facets/core/module/on_included'
|
5
|
-
require 'facets/more/aspects'
|
6
|
-
|
7
|
-
require 'glue/validation'
|
8
|
-
require 'og/entity'
|
9
|
-
require 'og/relation/all'
|
10
|
-
|
11
|
-
# A convienience structure that holds property
|
12
|
-
# metadata. A property is a special type of class annotation.
|
13
|
-
# Typically used in Og managed classes (ie Entities), but it
|
14
|
-
# is *not* Og specific.
|
15
|
-
#--
|
16
|
-
# TODO: reimplement type checking.
|
17
|
-
# TODO: try to clean this up.
|
18
|
-
#++
|
19
|
-
|
20
|
-
class Property
|
21
|
-
|
22
|
-
# The hash used to store the property options.
|
23
|
-
|
24
|
-
attr_accessor :hash
|
25
|
-
|
26
|
-
def initialize(hash)
|
27
|
-
@hash = hash
|
28
|
-
@hash = @hash.to_h unless @hash.is_a?(Hash)
|
29
|
-
end
|
30
|
-
|
31
|
-
def [](key)
|
32
|
-
@hash[key]
|
33
|
-
end
|
34
|
-
alias_method :method_missing, :[]
|
35
|
-
|
36
|
-
def []=(key, val)
|
37
|
-
@hash[key] = val
|
38
|
-
end
|
39
|
-
|
40
|
-
def <=>(other)
|
41
|
-
@hash[:symbol] <=> other.hash[:symbol]
|
42
|
-
end
|
43
|
-
|
44
|
-
def to_s
|
45
|
-
@hash[:symbol].to_s
|
46
|
-
end
|
47
|
-
alias_method :name, :to_s
|
48
|
-
|
49
|
-
# :section: Property related utils and helpers.
|
50
|
-
|
51
|
-
class << self
|
52
|
-
|
53
|
-
# Populate an object from a hash of values.
|
54
|
-
# This is a truly dangerous method.
|
55
|
-
#
|
56
|
-
# === Options:
|
57
|
-
# * name
|
58
|
-
# * force_boolean
|
59
|
-
|
60
|
-
def populate_object(obj, values, options = {})
|
61
|
-
# If a class is passed create an instance.
|
62
|
-
obj = obj.new if obj.is_a?(Class)
|
63
|
-
|
64
|
-
for prop in obj.class.properties.values
|
65
|
-
|
66
|
-
unless options[:all]
|
67
|
-
next if prop.symbol == obj.class.primary_key.symbol or prop.control == :none or prop.disable_control
|
68
|
-
end
|
69
|
-
|
70
|
-
prop_name = prop.symbol.to_s
|
71
|
-
|
72
|
-
# See if there is an incoming request param for this prop.
|
73
|
-
|
74
|
-
if values.has_key?(prop_name)
|
75
|
-
|
76
|
-
prop_value = values[prop_name]
|
77
|
-
|
78
|
-
# to_s must be called on the prop_value incase the
|
79
|
-
# request is IOString.
|
80
|
-
|
81
|
-
prop_value = prop_value.to_s unless prop_value.is_a?(Hash) or prop_value.is_a?(Array)
|
82
|
-
|
83
|
-
# If property is a Blob dont overwrite current
|
84
|
-
# property's data if "".
|
85
|
-
|
86
|
-
break if prop.klass == Og::Blob and prop_value.empty?
|
87
|
-
|
88
|
-
# If custom preprocessing is active then try and
|
89
|
-
# preprocess.
|
90
|
-
|
91
|
-
prop_value = preprocess_value(obj, prop, prop_value) if options[:preprocess]
|
92
|
-
|
93
|
-
# assign using __force_ methods.
|
94
|
-
obj.send("__force_#{prop_name}", prop_value)
|
95
|
-
|
96
|
-
# Set a boolean property to false if it is not in the request.
|
97
|
-
# requires force_boolean == true.
|
98
|
-
|
99
|
-
elsif options[:force_boolean] and (prop.klass == TrueClass or prop.klass == FalseClass)
|
100
|
-
obj.send("__force_#{prop_name}", 0)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
if options[:assign_relations]
|
105
|
-
for rel in obj.class.relations
|
106
|
-
|
107
|
-
unless options[:all]
|
108
|
-
next if rel.options[:control] == :none or rel.options[:disable_control]
|
109
|
-
end
|
110
|
-
|
111
|
-
rel_name = rel.name.to_s
|
112
|
-
|
113
|
-
# Renew the relations from values
|
114
|
-
|
115
|
-
if rel.kind_of?(Og::RefersTo)
|
116
|
-
if foreign_oid = values[rel_name]
|
117
|
-
foreign_oid = foreign_oid.to_s unless foreign_oid.is_a?(Hash) or foreign_oid.is_a?(Array)
|
118
|
-
foreign_oid = nil if foreign_oid == 'nil' or foreign_oid == 'none'
|
119
|
-
# if custom preprocessing is active then try and preprocess
|
120
|
-
foreign_oid = preprocess_value(obj, rel, foreign_oid) if options[:preprocess]
|
121
|
-
end
|
122
|
-
obj.send("__force_#{rel.foreign_key}", foreign_oid)
|
123
|
-
elsif rel.kind_of?(Og::JoinsMany) || rel.kind_of?(Og::HasMany)
|
124
|
-
collection = obj.send(rel_name)
|
125
|
-
collection.remove_all
|
126
|
-
if values.has_key?(rel_name)
|
127
|
-
primary_keys = values[rel_name]
|
128
|
-
|
129
|
-
# if custom preprocessing is active then try and preprocess
|
130
|
-
primary_keys = preprocess_value(obj, rel, primary_keys) if options[:preprocess]
|
131
|
-
|
132
|
-
primary_keys.each do |v|
|
133
|
-
next if v.to_s == "nil" or v.to_s == "none"
|
134
|
-
collection << rel.target_class[v.to_s.to_i]
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
#--
|
142
|
-
# gmosx, FIXME: this is a hack, will be replaced with proper
|
143
|
-
# code soon.
|
144
|
-
#++
|
145
|
-
|
146
|
-
for callback in obj.class.assign_callbacks
|
147
|
-
callback.call(obj, values, options)
|
148
|
-
end if obj.class.respond_to?(:assign_callbacks)
|
149
|
-
|
150
|
-
return obj
|
151
|
-
end
|
152
|
-
|
153
|
-
# This method will attempt to process [value] through the
|
154
|
-
# any on_populate preprocessors available.
|
155
|
-
#
|
156
|
-
# first looks if a method was specified on the property
|
157
|
-
#
|
158
|
-
# ie. property :this, String, :on_populate => :change_value
|
159
|
-
# ==> would mean #change_value(val) would get called
|
160
|
-
# TODO: set :on_populate to false to exclude it from any preprocessing
|
161
|
-
#
|
162
|
-
# next an #on_populate method will be looked for on any
|
163
|
-
# associated Nitro::Control (if controls is running)
|
164
|
-
#
|
165
|
-
# otherwise [value] is left untouched
|
166
|
-
|
167
|
-
def preprocess_value(obj, prop_or_rel, value)
|
168
|
-
if prop_or_rel.on_populate && obj.respond_to?(prop_or_rel.on_populate.to_sym)
|
169
|
-
return obj.send(prop_or_rel.on_populate.to_sym, value)
|
170
|
-
elsif Object.const_defined? :Nitro
|
171
|
-
if control = Nitro::Form::Control.fetch(obj, prop_or_rel, :default => nil) and control.respond_to?(:on_populate)
|
172
|
-
return control.on_populate(value)
|
173
|
-
end
|
174
|
-
else
|
175
|
-
return value
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def eval_helpers(writer, m, sym, klass)
|
180
|
-
return unless writer
|
181
|
-
|
182
|
-
code = %{
|
183
|
-
def __force_#{sym}(val)
|
184
|
-
if respond_to?(:force_#{sym})
|
185
|
-
self.#{sym} = force_#{sym}(val)
|
186
|
-
else
|
187
|
-
self.#{sym}=(} << case klass.name
|
188
|
-
when Fixnum.name: 'val.to_s.empty? ? nil : val.to_i'
|
189
|
-
when String.name: 'val.to_s'
|
190
|
-
when Float.name: 'val.to_f'
|
191
|
-
when Time.name: 'val.is_a?(Hash) ? Time.local(val["year"],val["month"],val["day"],val["hour"],val["min"]) : Time.parse(val.to_s)'
|
192
|
-
when Date.name: 'val.is_a?(Hash) ? Time.local(val["year"],val["month"],val["day"]).to_date : Time.parse(val.to_s).to_date'
|
193
|
-
when TrueClass.name, FalseClass.name: 'val == "on" or val == "true" ? true: val.to_i > 0'
|
194
|
-
else 'val'
|
195
|
-
end + %{)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
}
|
199
|
-
|
200
|
-
m.module_eval(code)
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
#--
|
207
|
-
# Extend the default Module.
|
208
|
-
#
|
209
|
-
# The properties hash, keeps the property metadata as a hash to avoid
|
210
|
-
# the null issue.
|
211
|
-
#++
|
212
|
-
|
213
|
-
class Module
|
214
|
-
[ nil, :_reader, :_writer, :_accessor].each do |m|
|
215
|
-
writer = (m != :reader)
|
216
|
-
code = %{
|
217
|
-
def prop#{m} (*args)
|
218
|
-
inheritor(:properties, Dictionary.new, :merge) unless @properties
|
219
|
-
|
220
|
-
args = args.flatten
|
221
|
-
harg = {}
|
222
|
-
while args.last.is_a?(Hash)
|
223
|
-
harg.update(args.pop)
|
224
|
-
end
|
225
|
-
|
226
|
-
harg[:klass] = args.pop if args.last.is_a?(Class)
|
227
|
-
klass = harg[:klass] ||= String
|
228
|
-
|
229
|
-
raise if args.empty? and harg.empty?
|
230
|
-
|
231
|
-
# If the class defines the include_as_property callback
|
232
|
-
# call to modify the base with custom code.
|
233
|
-
|
234
|
-
skip = false
|
235
|
-
|
236
|
-
if klass.respond_to? :included_as_property
|
237
|
-
skip = klass.included_as_property(self, args, harg)
|
238
|
-
end
|
239
|
-
|
240
|
-
unless skip
|
241
|
-
if !args.empty?
|
242
|
-
undef_keys = args.select{ |a| !method_defined?(a) }
|
243
|
-
unless undef_keys.empty?
|
244
|
-
attr#{m} *undef_keys
|
245
|
-
end
|
246
|
-
args.each { |a|
|
247
|
-
a = a.to_sym
|
248
|
-
an = define_annotation(a, harg)
|
249
|
-
ah = an.to_h.merge(:symbol => a)
|
250
|
-
# gmosx: allow for duplicate declarations.
|
251
|
-
properties![a] = Property.new(ah)
|
252
|
-
Property.eval_helpers(#{writer}, self, a, harg[:klass])
|
253
|
-
}
|
254
|
-
else
|
255
|
-
undef_keys = harg.keys.select{ |a| !method_defined?(a) }
|
256
|
-
attribute#{m} *undef_keys
|
257
|
-
harg.each { |a,h|
|
258
|
-
a = a.to_sym
|
259
|
-
an = define_annotation(a, h)
|
260
|
-
ah = an.to_h.merge(:symbol => a)
|
261
|
-
# gmosx: allow for property redefinitions.
|
262
|
-
properties![a] = Property.new(ah)
|
263
|
-
Property.eval_helpers(#{writer}, self, a, harg[:klass])
|
264
|
-
}
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
Module.__add_prop_hook__(self)
|
269
|
-
end
|
270
|
-
}
|
271
|
-
|
272
|
-
module_eval(code)
|
273
|
-
end
|
274
|
-
alias :property :prop_accessor
|
275
|
-
|
276
|
-
# NITRO specific!! leave blank in facets.
|
277
|
-
# TODO: factor in eval_helpers into the hook!
|
278
|
-
|
279
|
-
def self.__add_prop_hook__(m)
|
280
|
-
m.send(:include, Og::EntityMixin) unless m.ancestors.include?(Og::EntityMixin)
|
281
|
-
m.send(:include, Glue::Validation) unless m.ancestors.include?(Glue::Validation)
|
282
|
-
m.send(:include, ::Aspects) unless m.ancestors.include?(::Aspects)
|
283
|
-
end
|
284
|
-
|
285
|
-
end
|
286
|
-
|
287
|
-
# * George Moschovitis <gm@navel.gr>
|
288
|
-
# * Tom Sawyer <transfire@gmail.com>
|
289
|
-
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
290
|
-
# * Bryan Soto <bryan.a.soto@gmail.com>
|
data/lib/glue/sanitize.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# Code from rubyonrails project (http://www.rubyonrails.com)
|
2
|
-
# Temporarily here.
|
3
|
-
|
4
|
-
require 'html/tokenizer'
|
5
|
-
require 'html/node'
|
6
|
-
|
7
|
-
VERBOTEN_TAGS = %w(form script) unless defined?(VERBOTEN_TAGS)
|
8
|
-
VERBOTEN_ATTRS = /^on/i unless defined?(VERBOTEN_ATTRS)
|
9
|
-
|
10
|
-
class String
|
11
|
-
# Sanitizes the given HTML by making form and script tags into regular
|
12
|
-
# text, and removing all "onxxx" attributes (so that arbitrary Javascript
|
13
|
-
# cannot be executed). Also removes href attributes that start with
|
14
|
-
# "javascript:".
|
15
|
-
#
|
16
|
-
# Returns the sanitized text.
|
17
|
-
def self.sanitize(html)
|
18
|
-
# only do this if absolutely necessary
|
19
|
-
if html.index("<")
|
20
|
-
tokenizer = HTML::Tokenizer.new(html)
|
21
|
-
new_text = ""
|
22
|
-
|
23
|
-
while token = tokenizer.next
|
24
|
-
node = HTML::Node.parse(nil, 0, 0, token, false)
|
25
|
-
new_text << case node
|
26
|
-
when HTML::Tag
|
27
|
-
if VERBOTEN_TAGS.include?(node.name)
|
28
|
-
node.to_s.gsub(/</, "<")
|
29
|
-
else
|
30
|
-
if node.closing != :close
|
31
|
-
node.attributes.delete_if { |attr,v| attr =~ VERBOTEN_ATTRS }
|
32
|
-
if node.attributes["href"] =~ /^javascript:/i
|
33
|
-
node.attributes.delete "href"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
node.to_s
|
37
|
-
end
|
38
|
-
else
|
39
|
-
node.to_s.gsub(/</, "<")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
html = new_text
|
44
|
-
end
|
45
|
-
|
46
|
-
html
|
47
|
-
end
|
48
|
-
end
|
data/lib/glue/template.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
require 'facets/more/openobject'
|
2
|
-
require 'glue/configuration'
|
3
|
-
|
4
|
-
module Glue
|
5
|
-
|
6
|
-
# A template is a text file with embeded Ruby code. The template
|
7
|
-
# processor converts the original text file to ruby code and
|
8
|
-
# then evaluates this code to produce the result of the
|
9
|
-
# template transformation.
|
10
|
-
|
11
|
-
module TemplateMixin
|
12
|
-
|
13
|
-
# Convert a template to actual Ruby code, ready to be
|
14
|
-
# evaluated.
|
15
|
-
#
|
16
|
-
# [+template+]
|
17
|
-
# The template as a String.
|
18
|
-
#
|
19
|
-
# [+buffer+]
|
20
|
-
# The variable to act as a buffer where the ruby code
|
21
|
-
# for this template will be generated. Passed as a
|
22
|
-
# String.
|
23
|
-
#
|
24
|
-
# [+base_dir+]
|
25
|
-
# The base directory where the templates reside.
|
26
|
-
|
27
|
-
def compile_template(template, buffer = '@out', base_dir = Dir.pwd)
|
28
|
-
text = template.dup
|
29
|
-
|
30
|
-
# Strip the xml header! (interracts with the following gsub!)
|
31
|
-
text.gsub!(/<\?xml.*\?>/, "")
|
32
|
-
|
33
|
-
# Statically include sub-template files.
|
34
|
-
# The target file is included at compile time.
|
35
|
-
#
|
36
|
-
# gmosx: must be xformed before the <?r pi.
|
37
|
-
#
|
38
|
-
# Example:
|
39
|
-
# <?include href="root/myfile.sx" ?>
|
40
|
-
|
41
|
-
text.gsub!(/<\?include href=["|'](.*?)["|'](.*)\?>/) do |match|
|
42
|
-
itext = File.read("#{base_dir}/#$1")
|
43
|
-
itext.gsub!(/<\?xml.*\?>/, '')
|
44
|
-
itext.gsub!(/<\/?root(.*?)>/m, ' ');
|
45
|
-
itext
|
46
|
-
end
|
47
|
-
|
48
|
-
# Transform include instructions <include href="xxx" />
|
49
|
-
# must be transformed before the processinc instructions.
|
50
|
-
# Useful to include fragments cached on disk
|
51
|
-
#
|
52
|
-
# gmosx, FIXME: NOT TESTED! test and add caching.
|
53
|
-
# add load_statically_included fixes.
|
54
|
-
|
55
|
-
text.gsub!(/<include href=["|'](.*?)["|'](.*)(.?)\/>/) do |match|
|
56
|
-
"<?r File.read( '\#{@dispatcher.root}/#$1' ?>"
|
57
|
-
end
|
58
|
-
|
59
|
-
# xform render/inject instructions <render href="xxx" />
|
60
|
-
# must be transformed before the processinc instructions.
|
61
|
-
|
62
|
-
text.gsub!(/<(render|inject) href=["|'](.*?)["|'](.*)(.?)\/>/) do |match|
|
63
|
-
"<?r render '#$2' ?>"
|
64
|
-
end
|
65
|
-
|
66
|
-
# Remove <root> elements. typically removed by xslt but lets
|
67
|
-
# play it safe. The <root> element is typically added to
|
68
|
-
# template files to make them XHTML valid.
|
69
|
-
|
70
|
-
text.gsub!(/<(\/)?root>/, '')
|
71
|
-
|
72
|
-
# Transform the processing instructions, use <?r as
|
73
|
-
# a marker.
|
74
|
-
|
75
|
-
text.gsub!(/\?>/, "; #{buffer} << %^")
|
76
|
-
text.gsub!(/<\?r(\s?)/, "^; ")
|
77
|
-
|
78
|
-
# Transform alternative code tags.
|
79
|
-
# (very useful in xsl stylesheets)
|
80
|
-
|
81
|
-
text.gsub!(/<\/ruby>/, "; #{buffer} << %^")
|
82
|
-
text.gsub!(/<ruby>/, "^; ")
|
83
|
-
|
84
|
-
# Also handle erb/asp/jsp style tags. Those tags
|
85
|
-
# *cannot* be used with an xslt stylesheet.
|
86
|
-
|
87
|
-
text.gsub!(/%>/, "; #{buffer} << %^")
|
88
|
-
text.gsub!(/<%/, "^; ")
|
89
|
-
|
90
|
-
# Alterative versions of interpolation.
|
91
|
-
# (very useful in xsl stylesheets)
|
92
|
-
# Example: #\my_val\
|
93
|
-
|
94
|
-
text.gsub!(/\#\\(.*?)\\/, '#{\1}')
|
95
|
-
|
96
|
-
# Alternative for entities.
|
97
|
-
# (useful in xsl stylesheets)
|
98
|
-
# Examples: %nbsp;, %rquo;
|
99
|
-
|
100
|
-
text.gsub!(/%(#\d+|\w+);/, '&\1;')
|
101
|
-
|
102
|
-
# Compile time ruby code. This code is evaluated when
|
103
|
-
# compiling the template and the result injected directly
|
104
|
-
# into the result. Usefull for example to prevaluate
|
105
|
-
# localization. Just use the #[] marker instead of #{}.
|
106
|
-
|
107
|
-
text.gsub!(/\#\[(.*?)\]/) do |match|
|
108
|
-
eval($1)
|
109
|
-
end
|
110
|
-
|
111
|
-
text = "#{buffer} << %^" + text + "^"
|
112
|
-
|
113
|
-
return text
|
114
|
-
end
|
115
|
-
|
116
|
-
# Evaluate the template.
|
117
|
-
#
|
118
|
-
# [+ruby+]
|
119
|
-
# A String containing the compiled template
|
120
|
-
# code.
|
121
|
-
#
|
122
|
-
# [+binding+]
|
123
|
-
# The evaluation binding for the rendering.
|
124
|
-
|
125
|
-
def evaluate_template(ruby, the_binding = nil)
|
126
|
-
eval(ruby, the_binding)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Compile and render the template.
|
130
|
-
|
131
|
-
def process_template(template, buffer = '@out', the_binding = nil)
|
132
|
-
evaluate_template(compile_template(template, buffer), the_binding)
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
# A helper class that provides access to the Template methods
|
138
|
-
# as singleton methods.
|
139
|
-
|
140
|
-
class Template
|
141
|
-
|
142
|
-
# The default root directory where template files reside.
|
143
|
-
|
144
|
-
if File.exist?('template')
|
145
|
-
default_root = 'template'
|
146
|
-
elsif File.exist?('src/template')
|
147
|
-
default_root = 'src/template'
|
148
|
-
else
|
149
|
-
default_root = 'public'
|
150
|
-
end
|
151
|
-
|
152
|
-
setting :root, :default => default_root, :doc => 'The default root directory where template files reside'
|
153
|
-
|
154
|
-
# The default template name.
|
155
|
-
|
156
|
-
setting :default, :default => 'index', :doc => 'The default template name'
|
157
|
-
|
158
|
-
# The default template file extension.
|
159
|
-
|
160
|
-
setting :extension, :default => 'xhtml', :doc => 'The default template file extension'
|
161
|
-
|
162
|
-
# Strip xml comments from templates?
|
163
|
-
|
164
|
-
setting :strip_xml_comments, :default => false, :doc => 'Strip xml comments from templates?'
|
165
|
-
|
166
|
-
class << self
|
167
|
-
include TemplateMixin
|
168
|
-
alias_method :compile, :compile_template
|
169
|
-
alias_method :transform, :compile_template
|
170
|
-
alias_method :evaluate, :evaluate_template
|
171
|
-
alias_method :process, :process_template
|
172
|
-
end
|
173
|
-
|
174
|
-
include TemplateMixin
|
175
|
-
|
176
|
-
# Helper.
|
177
|
-
|
178
|
-
def render(template)
|
179
|
-
str = ''
|
180
|
-
process_template(template, 'str', binding)
|
181
|
-
return str
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
# A Template that reads from files and also
|
186
|
-
# provides a simple but effective caching scheme.
|
187
|
-
# An intuitive binding mechanism provides the
|
188
|
-
# expansion environment.
|
189
|
-
|
190
|
-
class FileTemplate < OpenObject
|
191
|
-
include TemplateMixin
|
192
|
-
|
193
|
-
@@compiled_template_cache = {}
|
194
|
-
|
195
|
-
attr_accessor :template_filename
|
196
|
-
|
197
|
-
def initialize(filename = nil)
|
198
|
-
super
|
199
|
-
@template_filename = filename
|
200
|
-
end
|
201
|
-
|
202
|
-
def process
|
203
|
-
__out__ = ''
|
204
|
-
|
205
|
-
unless compiled = @@compiled_template_cache[@template_filename]
|
206
|
-
template = File.read(@template_filename)
|
207
|
-
compiled = compile_template(template, '__out__')
|
208
|
-
@@compiled_template_cache[@template_filename] = compiled
|
209
|
-
end
|
210
|
-
|
211
|
-
evaluate_template(compiled, binding)
|
212
|
-
|
213
|
-
return __out__
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
end
|
218
|
-
|
219
|
-
# * George Moschovitis <gm@navel.gr>
|