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.
@@ -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