xx 2.0.0 → 2.1.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.
- data/lib/binding_of_caller.rb +83 -0
- data/lib/xx-2.1.0.rb +925 -0
- data/lib/xx.rb +219 -4
- data/lib/{xx-2.0.0.rb → xx.rb.bak} +123 -3
- metadata +5 -3
@@ -0,0 +1,83 @@
|
|
1
|
+
unless(defined?(Continuation) and Continuation.respond_to?('create'))
|
2
|
+
# to satisfy rdoc
|
3
|
+
class Continuation #:nodoc:
|
4
|
+
end
|
5
|
+
def Continuation.create(*args, &block) # :nodoc:
|
6
|
+
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
|
7
|
+
result ||= args
|
8
|
+
return *[cc, *result]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Binding; end # for RDoc
|
13
|
+
# This method returns the binding of the method that called your
|
14
|
+
# method. It will raise an Exception when you're not inside a method.
|
15
|
+
#
|
16
|
+
# It's used like this:
|
17
|
+
# def inc_counter(amount = 1)
|
18
|
+
# Binding.of_caller do |binding|
|
19
|
+
# # Create a lambda that will increase the variable 'counter'
|
20
|
+
# # in the caller of this method when called.
|
21
|
+
# inc = eval("lambda { |arg| counter += arg }", binding)
|
22
|
+
# # We can refer to amount from inside this block safely.
|
23
|
+
# inc.call(amount)
|
24
|
+
# end
|
25
|
+
# # No other statements can go here. Put them inside the block.
|
26
|
+
# end
|
27
|
+
# counter = 0
|
28
|
+
# 2.times { inc_counter }
|
29
|
+
# counter # => 2
|
30
|
+
#
|
31
|
+
# Binding.of_caller must be the last statement in the method.
|
32
|
+
# This means that you will have to put everything you want to
|
33
|
+
# do after the call to Binding.of_caller into the block of it.
|
34
|
+
# This should be no problem however, because Ruby has closures.
|
35
|
+
# If you don't do this an Exception will be raised. Because of
|
36
|
+
# the way that Binding.of_caller is implemented it has to be
|
37
|
+
# done this way.
|
38
|
+
def Binding.of_caller(&block)
|
39
|
+
old_critical = Thread.critical
|
40
|
+
Thread.critical = true
|
41
|
+
count = 0
|
42
|
+
cc, result, error, extra_data = Continuation.create(nil, nil)
|
43
|
+
error.call if error
|
44
|
+
|
45
|
+
tracer = lambda do |*args|
|
46
|
+
type, context, extra_data = args[0], args[4], args
|
47
|
+
if type == "return"
|
48
|
+
count += 1
|
49
|
+
# First this method and then calling one will return --
|
50
|
+
# the trace event of the second event gets the context
|
51
|
+
# of the method which called the method that called this
|
52
|
+
# method.
|
53
|
+
if count == 2
|
54
|
+
# It would be nice if we could restore the trace_func
|
55
|
+
# that was set before we swapped in our own one, but
|
56
|
+
# this is impossible without overloading set_trace_func
|
57
|
+
# in current Ruby.
|
58
|
+
set_trace_func(nil)
|
59
|
+
cc.call(eval("binding", context), nil, extra_data)
|
60
|
+
end
|
61
|
+
elsif type == "line" then
|
62
|
+
nil
|
63
|
+
elsif type == "c-return" and extra_data[3] == :set_trace_func then
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
set_trace_func(nil)
|
67
|
+
error_msg = "Binding.of_caller used in non-method context or " +
|
68
|
+
"trailing statements of method using it aren't in the block."
|
69
|
+
cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unless result
|
74
|
+
set_trace_func(tracer)
|
75
|
+
return nil
|
76
|
+
else
|
77
|
+
Thread.critical = old_critical
|
78
|
+
case block.arity
|
79
|
+
when 1 then yield(result)
|
80
|
+
else yield(result, extra_data)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/xx-2.1.0.rb
ADDED
@@ -0,0 +1,925 @@
|
|
1
|
+
unless(defined?($__xx_rb__) or defined?(XX))
|
2
|
+
|
3
|
+
require "rexml/document"
|
4
|
+
|
5
|
+
module XX
|
6
|
+
#--{{{
|
7
|
+
VERSION = "2.1.0"
|
8
|
+
def self.version() VERSION end
|
9
|
+
|
10
|
+
LIBDIR = File.dirname(File.expand_path(__FILE__)) << File::SEPARATOR
|
11
|
+
def self.libdir() LIBDIR end
|
12
|
+
|
13
|
+
require libdir + "binding_of_caller"
|
14
|
+
|
15
|
+
%w(
|
16
|
+
CRAZY_LIKE_A_HELL
|
17
|
+
PERMISSIVE
|
18
|
+
STRICT
|
19
|
+
ANY
|
20
|
+
).each{|c| const_set c, c}
|
21
|
+
|
22
|
+
class Document
|
23
|
+
#--{{{
|
24
|
+
attr "doc"
|
25
|
+
attr "stack"
|
26
|
+
attr "size"
|
27
|
+
attr_accessor "xmldecl"
|
28
|
+
|
29
|
+
def initialize *a, &b
|
30
|
+
#--{{{
|
31
|
+
@doc = ::REXML::Document::new *a, &b
|
32
|
+
@stack = [@doc]
|
33
|
+
@xmldecl = nil
|
34
|
+
@size = 0
|
35
|
+
#--}}}
|
36
|
+
end
|
37
|
+
def top
|
38
|
+
#--{{{
|
39
|
+
@stack.last
|
40
|
+
#--}}}
|
41
|
+
end
|
42
|
+
def push element
|
43
|
+
#--{{{
|
44
|
+
@stack.push element
|
45
|
+
#--}}}
|
46
|
+
end
|
47
|
+
def pop
|
48
|
+
#--{{{
|
49
|
+
@stack.pop unless @stack.size == 1
|
50
|
+
#--}}}
|
51
|
+
end
|
52
|
+
def tracking_additions
|
53
|
+
#--{{{
|
54
|
+
n = @size
|
55
|
+
yield
|
56
|
+
return @size - n
|
57
|
+
#--}}}
|
58
|
+
end
|
59
|
+
def to_str port = ""
|
60
|
+
#--{{{
|
61
|
+
xmldecl ? ugly(port) : pretty(port)
|
62
|
+
#--}}}
|
63
|
+
end
|
64
|
+
alias_method "to_s", "to_str"
|
65
|
+
def pretty port = ""
|
66
|
+
#--{{{
|
67
|
+
@doc.write port, indent=0, transitive=false, ie_hack=true
|
68
|
+
port
|
69
|
+
#--}}}
|
70
|
+
end
|
71
|
+
def ugly port = ''
|
72
|
+
#--{{{
|
73
|
+
@doc.write port, indent=-1, transitive=false, ie_hack=true
|
74
|
+
port
|
75
|
+
#--}}}
|
76
|
+
end
|
77
|
+
alias_method "compact", "ugly"
|
78
|
+
def create element
|
79
|
+
#--{{{
|
80
|
+
push element
|
81
|
+
begin
|
82
|
+
object = nil
|
83
|
+
additions =
|
84
|
+
tracking_additions do
|
85
|
+
object = yield element if block_given?
|
86
|
+
end
|
87
|
+
if object and additions.zero?
|
88
|
+
self << object
|
89
|
+
end
|
90
|
+
ensure
|
91
|
+
pop
|
92
|
+
end
|
93
|
+
self << element
|
94
|
+
element
|
95
|
+
#--}}}
|
96
|
+
end
|
97
|
+
def << object
|
98
|
+
#--{{{
|
99
|
+
t, x = top, object
|
100
|
+
|
101
|
+
if x
|
102
|
+
case t
|
103
|
+
when ::REXML::Document
|
104
|
+
|
105
|
+
begin
|
106
|
+
t <<
|
107
|
+
case x
|
108
|
+
when ::REXML::Document
|
109
|
+
x.root || ::REXML::Text::new(x.to_s)
|
110
|
+
when ::REXML::Element
|
111
|
+
x
|
112
|
+
when ::REXML::CData
|
113
|
+
x
|
114
|
+
when ::REXML::Text
|
115
|
+
x
|
116
|
+
else # string
|
117
|
+
::REXML::Text::new(x.to_s)
|
118
|
+
end
|
119
|
+
rescue
|
120
|
+
if t.respond_to? "root"
|
121
|
+
t = t.root
|
122
|
+
retry
|
123
|
+
else
|
124
|
+
raise
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
when ::REXML::Element
|
129
|
+
t <<
|
130
|
+
case x
|
131
|
+
when ::REXML::Document
|
132
|
+
x.root || ::REXML::Text::new(x.to_s)
|
133
|
+
when ::REXML::Element
|
134
|
+
x
|
135
|
+
when ::REXML::CData
|
136
|
+
#::REXML::Text::new(x.write(""))
|
137
|
+
x
|
138
|
+
when ::REXML::Text
|
139
|
+
x
|
140
|
+
else # string
|
141
|
+
::REXML::Text::new(x.to_s)
|
142
|
+
end
|
143
|
+
|
144
|
+
when ::REXML::Text
|
145
|
+
t <<
|
146
|
+
case x
|
147
|
+
when ::REXML::Document
|
148
|
+
x.write ""
|
149
|
+
when ::REXML::Element
|
150
|
+
x.write ""
|
151
|
+
when ::REXML::CData
|
152
|
+
x.write ""
|
153
|
+
when ::REXML::Text
|
154
|
+
x.write ""
|
155
|
+
else # string
|
156
|
+
x.to_s
|
157
|
+
end
|
158
|
+
|
159
|
+
else # other - try anyhow
|
160
|
+
t <<
|
161
|
+
case x
|
162
|
+
when ::REXML::Document
|
163
|
+
x.write ""
|
164
|
+
when ::REXML::Element
|
165
|
+
x.write ""
|
166
|
+
when ::REXML::CData
|
167
|
+
x.write ""
|
168
|
+
when ::REXML::Text
|
169
|
+
x.write ""
|
170
|
+
else # string
|
171
|
+
x.to_s
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
@size += 1
|
177
|
+
self
|
178
|
+
#--}}}
|
179
|
+
end
|
180
|
+
#--}}}
|
181
|
+
end
|
182
|
+
|
183
|
+
module Markup
|
184
|
+
#--{{{
|
185
|
+
class Error < ::StandardError; end
|
186
|
+
|
187
|
+
module InstanceMethods
|
188
|
+
#--{{{
|
189
|
+
def _ tag_name, *a, &b
|
190
|
+
#--{{{
|
191
|
+
hashes, nothashes = a.partition{|x| Hash === x}
|
192
|
+
|
193
|
+
doc = xx_doc
|
194
|
+
element = ::REXML::Element::new "#{ tag_name }"
|
195
|
+
|
196
|
+
hashes.each{|h| h.each{|k,v| element.add_attribute k.to_s, v}}
|
197
|
+
nothashes.each{|nh| element << ::REXML::Text::new(nh.to_s)}
|
198
|
+
|
199
|
+
doc.create element, &b
|
200
|
+
#--}}}
|
201
|
+
end
|
202
|
+
alias_method "xx_tag" , "_"
|
203
|
+
alias_method "__" , "_"
|
204
|
+
alias_method "g__" , "_"
|
205
|
+
def method_missing m, *a, &b
|
206
|
+
#--{{{
|
207
|
+
m = m.to_s
|
208
|
+
|
209
|
+
tag_name = m.sub! %r/_+$/, ''
|
210
|
+
|
211
|
+
super unless tag_name
|
212
|
+
|
213
|
+
__ tag_name, *a, &b
|
214
|
+
#--}}}
|
215
|
+
end
|
216
|
+
def xx_which *argv
|
217
|
+
#--{{{
|
218
|
+
@xx_which = nil unless defined? @xx_which
|
219
|
+
if argv.empty?
|
220
|
+
@xx_which
|
221
|
+
else
|
222
|
+
xx_which = @xx_which
|
223
|
+
begin
|
224
|
+
@xx_which = argv.shift
|
225
|
+
return yield
|
226
|
+
ensure
|
227
|
+
@xx_which = xx_which
|
228
|
+
end
|
229
|
+
end
|
230
|
+
#--}}}
|
231
|
+
end
|
232
|
+
def xx_with_doc_in_effect *a, &b
|
233
|
+
#--{{{
|
234
|
+
@xx_docs ||= []
|
235
|
+
doc = ::XX::Document::new *a
|
236
|
+
ddoc = doc.doc
|
237
|
+
begin
|
238
|
+
@xx_docs.push doc
|
239
|
+
|
240
|
+
doctype = xx_config_for "doctype", xx_which
|
241
|
+
if doctype
|
242
|
+
unless ddoc.doctype
|
243
|
+
doctype = ::REXML::DocType::new doctype unless
|
244
|
+
::REXML::DocType === doctype
|
245
|
+
ddoc << doctype
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
xmldecl = xx_config_for "xmldecl", xx_which
|
250
|
+
if xmldecl
|
251
|
+
if ddoc.xml_decl == ::REXML::XMLDecl::default
|
252
|
+
xmldecl = ::REXML::XMLDecl::new xmldecl unless
|
253
|
+
::REXML::XMLDecl === xmldecl
|
254
|
+
ddoc << xmldecl
|
255
|
+
doc.xmldecl = ::REXML::XMLDecl
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
b.call doc if b
|
260
|
+
|
261
|
+
return doc
|
262
|
+
ensure
|
263
|
+
@xx_docs.pop
|
264
|
+
end
|
265
|
+
#--}}}
|
266
|
+
end
|
267
|
+
def xx_doc
|
268
|
+
#--{{{
|
269
|
+
@xx_docs.last rescue raise "no xx_doc in effect!"
|
270
|
+
#--}}}
|
271
|
+
end
|
272
|
+
def xx_text_ *objects, &b
|
273
|
+
#--{{{
|
274
|
+
doc = xx_doc
|
275
|
+
|
276
|
+
text =
|
277
|
+
::REXML::Text::new("",
|
278
|
+
respect_whitespace=true, parent=nil
|
279
|
+
)
|
280
|
+
|
281
|
+
objects.each do |object|
|
282
|
+
text << object.to_s if object
|
283
|
+
end
|
284
|
+
|
285
|
+
doc.create text, &b
|
286
|
+
#--}}}
|
287
|
+
end
|
288
|
+
alias_method "t__", "xx_text_"
|
289
|
+
alias_method "text__", "xx_text_"
|
290
|
+
def xx_markup_ *objects, &b
|
291
|
+
#--{{{
|
292
|
+
doc = xx_doc
|
293
|
+
|
294
|
+
doc2 = ::REXML::Document::new ""
|
295
|
+
|
296
|
+
objects.each do |object|
|
297
|
+
(doc2.root ? doc2.root : doc2) << ::REXML::Document::new(object.to_s)
|
298
|
+
end
|
299
|
+
|
300
|
+
|
301
|
+
ret = doc.create doc2, &b
|
302
|
+
puts doc2.to_s
|
303
|
+
STDIN.gets
|
304
|
+
ret
|
305
|
+
#--}}}
|
306
|
+
end
|
307
|
+
alias_method "x__", "xx_markup_"
|
308
|
+
alias_method "markup__", "xx_markup_"
|
309
|
+
def xx_any_ *objects, &b
|
310
|
+
#--{{{
|
311
|
+
doc = xx_doc
|
312
|
+
nothing = %r/.^/m
|
313
|
+
|
314
|
+
text =
|
315
|
+
::REXML::Text::new("",
|
316
|
+
respect_whitespace=true, parent=nil, raw=true, entity_filter=nil, illegal=nothing
|
317
|
+
)
|
318
|
+
|
319
|
+
objects.each do |object|
|
320
|
+
text << object.to_s if object
|
321
|
+
end
|
322
|
+
|
323
|
+
doc.create text, &b
|
324
|
+
#--}}}
|
325
|
+
end
|
326
|
+
alias_method "any__", "xx_any_"
|
327
|
+
alias_method "h__", "xx_any_"
|
328
|
+
alias_method "x__", "xx_any_" # supplant for now
|
329
|
+
def xx_cdata_ *objects, &b
|
330
|
+
#--{{{
|
331
|
+
doc = xx_doc
|
332
|
+
|
333
|
+
cdata = ::REXML::CData::new ""
|
334
|
+
|
335
|
+
objects.each do |object|
|
336
|
+
cdata << object.to_s if object
|
337
|
+
end
|
338
|
+
|
339
|
+
doc.create cdata, &b
|
340
|
+
#--}}}
|
341
|
+
end
|
342
|
+
alias_method "cdata__", "xx_cdata_"
|
343
|
+
alias_method "c__", "xx_cdata_"
|
344
|
+
def xx_parse_attributes string
|
345
|
+
#--{{{
|
346
|
+
string = string.to_s
|
347
|
+
tokens = string.split %r/,/o
|
348
|
+
tokens.map{|t| t.sub!(%r/[^=]+=/){|key_eq| key_eq.chop << " : "}}
|
349
|
+
xx_parse_yaml_attributes(tokens.join(','))
|
350
|
+
#--}}}
|
351
|
+
end
|
352
|
+
alias_method "a__", "xx_parse_attributes"
|
353
|
+
def xx_parse_yaml_attributes string
|
354
|
+
#--{{{
|
355
|
+
require "yaml"
|
356
|
+
string = string.to_s
|
357
|
+
string = "{" << string unless string =~ %r/^\s*[{]/o
|
358
|
+
string = string << "}" unless string =~ %r/[}]\s*$/o
|
359
|
+
obj = ::YAML::load string
|
360
|
+
raise ArgumentError, "<#{ obj.class }> not Hash!" unless Hash === obj
|
361
|
+
obj
|
362
|
+
#--}}}
|
363
|
+
end
|
364
|
+
alias_method "y__", "xx_parse_yaml_attributes"
|
365
|
+
def xx_class
|
366
|
+
#--{{{
|
367
|
+
@xx_class ||= self.class
|
368
|
+
#--}}}
|
369
|
+
end
|
370
|
+
def xx_tag_method_name *a, &b
|
371
|
+
#--{{{
|
372
|
+
xx_class.xx_tag_method_name *a, &b
|
373
|
+
#--}}}
|
374
|
+
end
|
375
|
+
def xx_define_tmp_method *a, &b
|
376
|
+
#--{{{
|
377
|
+
xx_class.xx_define_tmp_method *a, &b
|
378
|
+
#--}}}
|
379
|
+
end
|
380
|
+
def xx_define_tag_method *a, &b
|
381
|
+
#--{{{
|
382
|
+
xx_class.xx_define_tag_method *a, &b
|
383
|
+
#--}}}
|
384
|
+
end
|
385
|
+
def xx_remove_tag_method *a, &b
|
386
|
+
#--{{{
|
387
|
+
xx_class.xx_tag_remove_method *a, &b
|
388
|
+
#--}}}
|
389
|
+
end
|
390
|
+
def xx_ancestors
|
391
|
+
#--{{{
|
392
|
+
raise Error, "no xx_which in effect" unless xx_which
|
393
|
+
xx_class.xx_ancestors xx_which
|
394
|
+
#--}}}
|
395
|
+
end
|
396
|
+
def xx_config
|
397
|
+
#--{{{
|
398
|
+
xx_class.xx_config
|
399
|
+
#--}}}
|
400
|
+
end
|
401
|
+
def xx_config_for *a, &b
|
402
|
+
#--{{{
|
403
|
+
xx_class.xx_config_for *a, &b
|
404
|
+
#--}}}
|
405
|
+
end
|
406
|
+
def xx_configure *a, &b
|
407
|
+
#--{{{
|
408
|
+
xx_class.xx_configure *a, &b
|
409
|
+
#--}}}
|
410
|
+
end
|
411
|
+
#--}}}
|
412
|
+
end
|
413
|
+
|
414
|
+
module ClassMethods
|
415
|
+
#--{{{
|
416
|
+
def xx_tag_method_name m
|
417
|
+
#--{{{
|
418
|
+
m = m.to_s
|
419
|
+
tag_method, tag_name = m, m.gsub(%r/_+$/, "")
|
420
|
+
[ tag_method, tag_name ]
|
421
|
+
#--}}}
|
422
|
+
end
|
423
|
+
def xx_define_tmp_method m
|
424
|
+
#--{{{
|
425
|
+
define_method(m){ raise NotImplementedError, m.to_s }
|
426
|
+
#--}}}
|
427
|
+
end
|
428
|
+
def xx_define_tag_method tag_method, tag_name = nil
|
429
|
+
#--{{{
|
430
|
+
tag_method = tag_method.to_s
|
431
|
+
tag_name ||= tag_method.sub(%r/_$/, '')
|
432
|
+
|
433
|
+
module_eval <<-code
|
434
|
+
def #{ tag_method } *a, &b
|
435
|
+
hashes, nothashes = a.partition{|x| Hash === x}
|
436
|
+
|
437
|
+
doc = xx_doc
|
438
|
+
element = ::REXML::Element::new '#{ tag_name }'
|
439
|
+
|
440
|
+
hashes.each{|h| h.each{|k,v| element.add_attribute k.to_s, v}}
|
441
|
+
nothashes.each{|nh| element << ::REXML::Text::new(nh.to_s)}
|
442
|
+
|
443
|
+
doc.create element, &b
|
444
|
+
end
|
445
|
+
code
|
446
|
+
tag_method
|
447
|
+
#--}}}
|
448
|
+
end
|
449
|
+
def xx_remove_tag_method tag_method
|
450
|
+
#--{{{
|
451
|
+
remove_method tag_method rescue nil
|
452
|
+
#--}}}
|
453
|
+
end
|
454
|
+
def xx_ancestors xx_which = self
|
455
|
+
#--{{{
|
456
|
+
list = []
|
457
|
+
ancestors.each do |a|
|
458
|
+
list << a if a < xx_which
|
459
|
+
end
|
460
|
+
xx_which.ancestors.each do |a|
|
461
|
+
list << a if a <= Markup
|
462
|
+
end
|
463
|
+
list
|
464
|
+
#--}}}
|
465
|
+
end
|
466
|
+
def xx_config
|
467
|
+
#--{{{
|
468
|
+
@@xx_config ||= Hash::new{|h,k| h[k] = {}}
|
469
|
+
#--}}}
|
470
|
+
end
|
471
|
+
def xx_config_for key, xx_which = nil
|
472
|
+
#--{{{
|
473
|
+
key = key.to_s
|
474
|
+
xx_which ||= self
|
475
|
+
xx_ancestors(xx_which).each do |a|
|
476
|
+
if xx_config[a].has_key? key
|
477
|
+
return xx_config[a][key]
|
478
|
+
end
|
479
|
+
end
|
480
|
+
nil
|
481
|
+
#--}}}
|
482
|
+
end
|
483
|
+
def xx_configure key, value, xx_which = nil
|
484
|
+
#--{{{
|
485
|
+
key = key.to_s
|
486
|
+
xx_which ||= self
|
487
|
+
xx_config[xx_which][key] = value
|
488
|
+
#--}}}
|
489
|
+
end
|
490
|
+
#--}}}
|
491
|
+
end
|
492
|
+
|
493
|
+
extend ClassMethods
|
494
|
+
include InstanceMethods
|
495
|
+
|
496
|
+
def self::included other, *a, &b
|
497
|
+
#--{{{
|
498
|
+
ret = super
|
499
|
+
other.module_eval do
|
500
|
+
include Markup::InstanceMethods
|
501
|
+
extend Markup::ClassMethods
|
502
|
+
class << self
|
503
|
+
define_method("included", Markup::XX_MARKUP_RECURSIVE_INCLUSION_PROC)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
ret
|
507
|
+
#--}}}
|
508
|
+
end
|
509
|
+
XX_MARKUP_RECURSIVE_INCLUSION_PROC = method("included").to_proc
|
510
|
+
|
511
|
+
xx_configure "method_missing", XX::PERMISSIVE
|
512
|
+
xx_configure "tags", []
|
513
|
+
xx_configure "doctype", nil
|
514
|
+
xx_configure "xmldecl", nil
|
515
|
+
#--}}}
|
516
|
+
end
|
517
|
+
|
518
|
+
module XHTML
|
519
|
+
#--{{{
|
520
|
+
include Markup
|
521
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
|
522
|
+
|
523
|
+
def xhtml_ which = XHTML, *a, &b
|
524
|
+
#--{{{
|
525
|
+
xx_which(which) do
|
526
|
+
doc = xx_with_doc_in_effect *a, &b
|
527
|
+
ddoc = doc.doc
|
528
|
+
root = ddoc.root
|
529
|
+
if root and root.name and root.name =~ %r/^html$/i
|
530
|
+
if root.attribute("lang",nil).nil? or root.attribute("lang",nil).to_s.empty?
|
531
|
+
root.add_attribute "lang", "en"
|
532
|
+
end
|
533
|
+
if root.attribute("xml:lang").nil? or root.attribute("xml:lang").to_s.empty?
|
534
|
+
root.add_attribute "xml:lang", "en"
|
535
|
+
end
|
536
|
+
if root.namespace.nil? or root.namespace.to_s.empty?
|
537
|
+
root.add_namespace "http://www.w3.org/1999/xhtml"
|
538
|
+
end
|
539
|
+
end
|
540
|
+
doc
|
541
|
+
end
|
542
|
+
#--}}}
|
543
|
+
end
|
544
|
+
alias_method "xhtml__", "xhtml_"
|
545
|
+
|
546
|
+
module Strict
|
547
|
+
#--{{{
|
548
|
+
include XHTML
|
549
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd")
|
550
|
+
xx_configure "tags", %w(
|
551
|
+
html head body div span DOCTYPE title link meta style p
|
552
|
+
h1 h2 h3 h4 h5 h6 strong em abbr acronym address bdo blockquote cite q code
|
553
|
+
ins del dfn kbd pre samp var br a base img
|
554
|
+
area map object param ul ol li dl dt dd table
|
555
|
+
tr td th tbody thead tfoot col colgroup caption form input
|
556
|
+
textarea select option optgroup button label fieldset legend script noscript b
|
557
|
+
i tt sub sup big small hr
|
558
|
+
)
|
559
|
+
xx_configure "method_missing", ::XX::STRICT
|
560
|
+
|
561
|
+
def xhtml_ which = XHTML::Strict, *a, &b
|
562
|
+
#--{{{
|
563
|
+
super(which, *a, &b)
|
564
|
+
#--}}}
|
565
|
+
end
|
566
|
+
alias_method "xhtml__", "xhtml_"
|
567
|
+
#--}}}
|
568
|
+
end
|
569
|
+
|
570
|
+
module Transitional
|
571
|
+
#--{{{
|
572
|
+
include XHTML
|
573
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
|
574
|
+
def xhtml_ which = XHTML::Transitional, *a, &b
|
575
|
+
#--{{{
|
576
|
+
super(which, *a, &b)
|
577
|
+
#--}}}
|
578
|
+
end
|
579
|
+
alias_method "xhtml__", "xhtml_"
|
580
|
+
#--}}}
|
581
|
+
end
|
582
|
+
#--}}}
|
583
|
+
end
|
584
|
+
|
585
|
+
module HTML4
|
586
|
+
#--{{{
|
587
|
+
include Markup
|
588
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN")
|
589
|
+
|
590
|
+
def html4_ which = HTML4, *a, &b
|
591
|
+
#--{{{
|
592
|
+
xx_which(which){ xx_with_doc_in_effect *a, &b }
|
593
|
+
#--}}}
|
594
|
+
end
|
595
|
+
alias_method "html4__", "html4_"
|
596
|
+
|
597
|
+
module Strict
|
598
|
+
#--{{{
|
599
|
+
include HTML4
|
600
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN")
|
601
|
+
xx_configure "tags", %w(
|
602
|
+
html head body div span DOCTYPE title link meta style p
|
603
|
+
h1 h2 h3 h4 h5 h6 strong em abbr acronym address bdo blockquote cite q code
|
604
|
+
ins del dfn kbd pre samp var br a base img
|
605
|
+
area map object param ul ol li dl dt dd table
|
606
|
+
tr td th tbody thead tfoot col colgroup caption form input
|
607
|
+
textarea select option optgroup button label fieldset legend script noscript b
|
608
|
+
i tt sub sup big small hr
|
609
|
+
)
|
610
|
+
xx_configure "method_missing", ::XX::STRICT
|
611
|
+
def html4_ which = HTML4::Strict, *a, &b
|
612
|
+
#--{{{
|
613
|
+
super(which, *a, &b)
|
614
|
+
#--}}}
|
615
|
+
end
|
616
|
+
alias_method "html4__", "html4_"
|
617
|
+
#--}}}
|
618
|
+
end
|
619
|
+
|
620
|
+
module Transitional
|
621
|
+
#--{{{
|
622
|
+
include HTML4
|
623
|
+
xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN")
|
624
|
+
def html4_ which = HTML4::Transitional, *a, &b
|
625
|
+
#--{{{
|
626
|
+
super(which, *a, &b)
|
627
|
+
#--}}}
|
628
|
+
end
|
629
|
+
alias_method "html4__", "html4_"
|
630
|
+
#--}}}
|
631
|
+
end
|
632
|
+
#--}}}
|
633
|
+
end
|
634
|
+
HTML = HTML4
|
635
|
+
|
636
|
+
module XML
|
637
|
+
#--{{{
|
638
|
+
include Markup
|
639
|
+
xx_configure "xmldecl", ::REXML::XMLDecl::new
|
640
|
+
|
641
|
+
def xml_ *a, &b
|
642
|
+
#--{{{
|
643
|
+
xx_which(XML){ xx_with_doc_in_effect *a, &b }
|
644
|
+
#--}}}
|
645
|
+
end
|
646
|
+
alias_method "xml__", "xml_"
|
647
|
+
#--}}}
|
648
|
+
end
|
649
|
+
|
650
|
+
module Template
|
651
|
+
#--{{{
|
652
|
+
class Basic
|
653
|
+
#--{{{
|
654
|
+
%w( path inline type object template port pretty ).each{|a| attr_accessor a}
|
655
|
+
def initialize opts = {}, &b
|
656
|
+
#--{{{
|
657
|
+
@path = opts['path'] || opts[:path]
|
658
|
+
@inline = opts['inline'] || opts[:inline]
|
659
|
+
@type = opts['type'] || opts[:type]
|
660
|
+
@object = opts['object'] || opts[:object]
|
661
|
+
@pretty = opts['pretty'] || opts[:pretty]
|
662
|
+
@port = opts['port'] || opts[:port] || STDOUT
|
663
|
+
|
664
|
+
bool = lambda{|value| value ? true : false}
|
665
|
+
raise ArgumentError unless(bool[@path] ^ bool[@inline])
|
666
|
+
|
667
|
+
path_init(&b) if @path
|
668
|
+
inline_init(&b) if @inline
|
669
|
+
|
670
|
+
@type =
|
671
|
+
case @type.to_s.downcase.strip
|
672
|
+
when /^xhtml$/
|
673
|
+
XHTML
|
674
|
+
when /^xml$/
|
675
|
+
XML
|
676
|
+
when /^html4$/
|
677
|
+
HTML4
|
678
|
+
else
|
679
|
+
XHTML
|
680
|
+
end
|
681
|
+
#--}}}
|
682
|
+
end
|
683
|
+
def path_init &b
|
684
|
+
#--{{{
|
685
|
+
@template = IO.read @path
|
686
|
+
@type = @path[%r/\.[^\.]+$/o] || XHTML unless @type
|
687
|
+
#--}}}
|
688
|
+
end
|
689
|
+
def inline_init &b
|
690
|
+
#--{{{
|
691
|
+
@template = (@inline || b.call).to_s
|
692
|
+
@type ||= XHTML
|
693
|
+
#--}}}
|
694
|
+
end
|
695
|
+
def expand binding, opts = {}
|
696
|
+
#--{{{
|
697
|
+
port = opts['port'] || opts[:port] || STDOUT
|
698
|
+
pretty = opts['pretty'] || opts[:pretty]
|
699
|
+
|
700
|
+
object = eval 'self', binding
|
701
|
+
|
702
|
+
unless type === object
|
703
|
+
__m = type
|
704
|
+
klass = object.class
|
705
|
+
klass.module_eval{ include __m }
|
706
|
+
end
|
707
|
+
|
708
|
+
doc = eval @template, binding
|
709
|
+
|
710
|
+
display = pretty ? 'pretty' : 'to_str'
|
711
|
+
|
712
|
+
doc.send display, port
|
713
|
+
#--}}}
|
714
|
+
end
|
715
|
+
alias_method "result", "expand"
|
716
|
+
#--}}}
|
717
|
+
end
|
718
|
+
|
719
|
+
class File < Basic
|
720
|
+
#--{{{
|
721
|
+
def initialize *argv, &b
|
722
|
+
#--{{{
|
723
|
+
opts, argv = argv.partition{|arg| Hash === arg}
|
724
|
+
opts = opts.inject{|a,b| a.update b}
|
725
|
+
path = argv.shift
|
726
|
+
raise ArgumentError, "no path" unless path
|
727
|
+
raise ArgumentError, "bad opts" unless Hash === opts or opts.nil?
|
728
|
+
opts ||= {}
|
729
|
+
opts['path'] = opts[:path] = path.to_s
|
730
|
+
super opts, &b
|
731
|
+
#--}}}
|
732
|
+
end
|
733
|
+
#--}}}
|
734
|
+
end
|
735
|
+
|
736
|
+
class Inline < Basic
|
737
|
+
#--{{{
|
738
|
+
def initialize *argv, &b
|
739
|
+
#--{{{
|
740
|
+
opts, argv = argv.partition{|arg| Hash === arg}
|
741
|
+
opts = opts.inject{|a,b| a.update b}
|
742
|
+
inline = argv.shift || b.call
|
743
|
+
raise ArgumentError, "no inline" unless inline
|
744
|
+
raise ArgumentError, "bad opts" unless Hash === opts or opts.nil?
|
745
|
+
opts ||= {}
|
746
|
+
opts['inline'] = opts[:inline] = inline.to_s
|
747
|
+
super opts, &b
|
748
|
+
#--}}}
|
749
|
+
end
|
750
|
+
#--}}}
|
751
|
+
end
|
752
|
+
#--}}}
|
753
|
+
end
|
754
|
+
|
755
|
+
module Expandable
|
756
|
+
#--{{{
|
757
|
+
module InstanceMethods
|
758
|
+
#--{{{
|
759
|
+
def xx_template_file *a, &b
|
760
|
+
#--{{{
|
761
|
+
template = XX::Template::File.new *a, &b
|
762
|
+
template.object ||= self
|
763
|
+
template
|
764
|
+
#--}}}
|
765
|
+
end
|
766
|
+
def xx_template_inline *a, &b
|
767
|
+
#--{{{
|
768
|
+
template = XX::Template::Inline.new *a, &b
|
769
|
+
template.object ||= self
|
770
|
+
template
|
771
|
+
#--}}}
|
772
|
+
end
|
773
|
+
def xx_expand template, opts = {}
|
774
|
+
#--{{{
|
775
|
+
port = opts['port'] || opts[:port] || STDOUT
|
776
|
+
pretty = opts['pretty'] || opts[:pretty]
|
777
|
+
binding = opts['binding'] || opts[:binding]
|
778
|
+
|
779
|
+
type = template.type
|
780
|
+
|
781
|
+
unless type === self
|
782
|
+
klass = self.class
|
783
|
+
klass.module_eval{ include type }
|
784
|
+
end
|
785
|
+
|
786
|
+
display = pretty ? 'pretty' : 'to_str'
|
787
|
+
|
788
|
+
Binding.of_caller do |scope|
|
789
|
+
binding ||= eval('binding', scope)
|
790
|
+
doc = eval template.template, binding
|
791
|
+
doc.send display, port
|
792
|
+
end
|
793
|
+
#--}}}
|
794
|
+
end
|
795
|
+
def xx_expand_file *a, &b
|
796
|
+
#--{{{
|
797
|
+
template = xx_template_file *a, &b
|
798
|
+
|
799
|
+
type = template.type
|
800
|
+
pretty = template.pretty
|
801
|
+
port = template.port
|
802
|
+
|
803
|
+
unless type === self
|
804
|
+
klass = self.class
|
805
|
+
klass.module_eval{ include type }
|
806
|
+
end
|
807
|
+
|
808
|
+
display = pretty ? 'pretty' : 'to_str'
|
809
|
+
|
810
|
+
Binding.of_caller do |scope|
|
811
|
+
binding ||= eval('binding', scope)
|
812
|
+
doc = eval template.template, binding
|
813
|
+
doc.send display, port
|
814
|
+
end
|
815
|
+
#--}}}
|
816
|
+
end
|
817
|
+
alias_method "xx_expand_path", "xx_expand_file"
|
818
|
+
alias_method "xx_expand_template", "xx_expand_file"
|
819
|
+
def xx_expand_inline *a, &b
|
820
|
+
#--{{{
|
821
|
+
template = xx_template_inline *a, &b
|
822
|
+
|
823
|
+
type = template.type
|
824
|
+
pretty = template.pretty
|
825
|
+
port = template.port
|
826
|
+
|
827
|
+
unless type === self
|
828
|
+
klass = self.class
|
829
|
+
klass.module_eval{ include type }
|
830
|
+
end
|
831
|
+
|
832
|
+
display = pretty ? 'pretty' : 'to_str'
|
833
|
+
|
834
|
+
Binding.of_caller do |scope|
|
835
|
+
binding ||= eval('binding', scope)
|
836
|
+
doc = eval template.template, binding
|
837
|
+
doc.send display, port
|
838
|
+
end
|
839
|
+
#--}}}
|
840
|
+
end
|
841
|
+
alias_method "xx_expand_string", "xx_expand_inline"
|
842
|
+
#--}}}
|
843
|
+
end
|
844
|
+
module ClassMethods
|
845
|
+
end
|
846
|
+
def self.included other
|
847
|
+
#--{{{
|
848
|
+
other.instance_eval{ include InstanceMethods }
|
849
|
+
other.extend ClassMethods
|
850
|
+
#--}}}
|
851
|
+
end
|
852
|
+
#--}}}
|
853
|
+
end
|
854
|
+
|
855
|
+
#--}}}
|
856
|
+
end
|
857
|
+
|
858
|
+
$__xx_rb__ = __FILE__
|
859
|
+
end
|
860
|
+
|
861
|
+
|
862
|
+
|
863
|
+
|
864
|
+
|
865
|
+
|
866
|
+
|
867
|
+
|
868
|
+
|
869
|
+
|
870
|
+
#
|
871
|
+
# simple examples - see samples/ dir for more complete examples
|
872
|
+
#
|
873
|
+
|
874
|
+
if __FILE__ == $0
|
875
|
+
|
876
|
+
class Table < ::Array
|
877
|
+
include XX::XHTML::Strict
|
878
|
+
include XX::HTML4::Strict
|
879
|
+
include XX::XML
|
880
|
+
|
881
|
+
def doc
|
882
|
+
html_{
|
883
|
+
head_{ title_{ "xhtml/html4/xml demo" } }
|
884
|
+
|
885
|
+
div_{
|
886
|
+
h_{ "< malformed html & un-escaped symbols" }
|
887
|
+
}
|
888
|
+
|
889
|
+
t_{ "escaped & text > <" }
|
890
|
+
|
891
|
+
x_{ "<any_valid> xml </any_valid>" }
|
892
|
+
|
893
|
+
div_(:style => :sweet){
|
894
|
+
em_ "this is a table"
|
895
|
+
|
896
|
+
table_(:width => 42, :height => 42){
|
897
|
+
each{|row| tr_{ row.each{|cell| td_ cell } } }
|
898
|
+
}
|
899
|
+
}
|
900
|
+
|
901
|
+
script_(:type => :dangerous){ cdata_{ "javascript" } }
|
902
|
+
}
|
903
|
+
end
|
904
|
+
def to_xhtml
|
905
|
+
xhtml_{ doc }
|
906
|
+
end
|
907
|
+
def to_html4
|
908
|
+
html4_{ doc }
|
909
|
+
end
|
910
|
+
def to_xml
|
911
|
+
xml_{ doc }
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
table = Table[ %w( 0 1 2 ), %w( a b c ) ]
|
916
|
+
|
917
|
+
methods = %w( to_xhtml to_html4 to_xml )
|
918
|
+
|
919
|
+
methods.each do |method|
|
920
|
+
2.times{ puts "-" * 42 }
|
921
|
+
puts(table.send(method).pretty)
|
922
|
+
puts
|
923
|
+
end
|
924
|
+
|
925
|
+
end
|