xx 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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