rhodes 0.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.
Files changed (53) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +4 -0
  3. data/Manifest.txt +52 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +33 -0
  6. data/bin/rhogen +8 -0
  7. data/generators/rhogen.rb +99 -0
  8. data/generators/templates/application/application.rb +4 -0
  9. data/generators/templates/application/index.html +25 -0
  10. data/generators/templates/model/config.rb +3 -0
  11. data/generators/templates/model/controller.rb +48 -0
  12. data/generators/templates/model/edit.erb +21 -0
  13. data/generators/templates/model/index.erb +10 -0
  14. data/generators/templates/model/new.erb +16 -0
  15. data/lib/ServeME.rb +7 -0
  16. data/lib/TestServe.rb +9 -0
  17. data/lib/builtinME.rb +481 -0
  18. data/lib/date.rb +1781 -0
  19. data/lib/date/format.rb +1313 -0
  20. data/lib/erb.rb +896 -0
  21. data/lib/find.rb +81 -0
  22. data/lib/rational.rb +19 -0
  23. data/lib/rho.rb +1 -0
  24. data/lib/rho/render.rb +9 -0
  25. data/lib/rho/renderME.rb +8 -0
  26. data/lib/rho/rho.rb +173 -0
  27. data/lib/rho/rhoapplication.rb +36 -0
  28. data/lib/rho/rhocontroller.rb +51 -0
  29. data/lib/rho/rhofsconnector.rb +39 -0
  30. data/lib/rho/rhofsconnectorME.rb +36 -0
  31. data/lib/rho/rhosupport.rb +139 -0
  32. data/lib/rhodes.rb +5 -0
  33. data/lib/rhofsconnector.rb +5 -0
  34. data/lib/rhom.rb +1 -0
  35. data/lib/rhom/rhom.rb +41 -0
  36. data/lib/rhom/rhom_db_adapter.rb +183 -0
  37. data/lib/rhom/rhom_db_adapterME.rb +91 -0
  38. data/lib/rhom/rhom_object.rb +53 -0
  39. data/lib/rhom/rhom_object_factory.rb +246 -0
  40. data/lib/singleton.rb +313 -0
  41. data/lib/time.rb +839 -0
  42. data/rhodes.gemspec +18 -0
  43. data/spec/app_generator_spec.rb +27 -0
  44. data/spec/generator_spec_helper.rb +12 -0
  45. data/spec/model_generator_spec.rb +28 -0
  46. data/spec/rho_spec.rb +28 -0
  47. data/spec/rhom_object_factory_spec.rb +147 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +14 -0
  50. data/spec/stubs.rb +17 -0
  51. data/spec/syncdbtest.sqlite +0 -0
  52. data/tasks/rspec.rake +34 -0
  53. metadata +157 -0
data/lib/erb.rb ADDED
@@ -0,0 +1,896 @@
1
+ # = ERB -- Ruby Templating
2
+ #
3
+ # Author:: Masatoshi SEKI
4
+ # Documentation:: James Edward Gray II and Gavin Sinclair
5
+ #
6
+ # See ERB for primary documentation and ERB::Util for a couple of utility
7
+ # routines.
8
+ #
9
+ # Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
10
+ #
11
+ # You can redistribute it and/or modify it under the same terms as Ruby.
12
+
13
+ #
14
+ # = ERB -- Ruby Templating
15
+ #
16
+ # == Introduction
17
+ #
18
+ # ERB provides an easy to use but powerful templating system for Ruby. Using
19
+ # ERB, actual Ruby code can be added to any plain text document for the
20
+ # purposes of generating document information details and/or flow control.
21
+ #
22
+ # A very simple example is this:
23
+ #
24
+ # require 'erb'
25
+ #
26
+ # x = 42
27
+ # template = ERB.new <<-EOF
28
+ # The value of x is: <%= x %>
29
+ # EOF
30
+ # puts template.result(binding)
31
+ #
32
+ # <em>Prints:</em> The value of x is: 42
33
+ #
34
+ # More complex examples are given below.
35
+ #
36
+ #
37
+ # == Recognized Tags
38
+ #
39
+ # ERB recognizes certain tags in the provided template and converts them based
40
+ # on the rules below:
41
+ #
42
+ # <% Ruby code -- inline with output %>
43
+ # <%= Ruby expression -- replace with result %>
44
+ # <%# comment -- ignored -- useful in testing %>
45
+ # % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
46
+ # %% replaced with % if first thing on a line and % processing is used
47
+ # <%% or %%> -- replace with <% or %> respectively
48
+ #
49
+ # All other text is passed through ERB filtering unchanged.
50
+ #
51
+ #
52
+ # == Options
53
+ #
54
+ # There are several settings you can change when you use ERB:
55
+ # * the nature of the tags that are recognized;
56
+ # * the value of <tt>$SAFE</tt> under which the template is run;
57
+ # * the binding used to resolve local variables in the template.
58
+ #
59
+ # See the ERB.new and ERB#result methods for more detail.
60
+ #
61
+ #
62
+ # == Examples
63
+ #
64
+ # === Plain Text
65
+ #
66
+ # ERB is useful for any generic templating situation. Note that in this example, we use the
67
+ # convenient "% at start of line" tag, and we quote the template literally with
68
+ # <tt>%q{...}</tt> to avoid trouble with the backslash.
69
+ #
70
+ # require "erb"
71
+ #
72
+ # # Create template.
73
+ # template = %q{
74
+ # From: James Edward Gray II <james@grayproductions.net>
75
+ # To: <%= to %>
76
+ # Subject: Addressing Needs
77
+ #
78
+ # <%= to[/\w+/] %>:
79
+ #
80
+ # Just wanted to send a quick note assuring that your needs are being
81
+ # addressed.
82
+ #
83
+ # I want you to know that my team will keep working on the issues,
84
+ # especially:
85
+ #
86
+ # <%# ignore numerous minor requests -- focus on priorities %>
87
+ # % priorities.each do |priority|
88
+ # * <%= priority %>
89
+ # % end
90
+ #
91
+ # Thanks for your patience.
92
+ #
93
+ # James Edward Gray II
94
+ # }.gsub(/^ /, '')
95
+ #
96
+ # message = ERB.new(template, 0, "%<>")
97
+ #
98
+ # # Set up template data.
99
+ # to = "Community Spokesman <spokesman@ruby_community.org>"
100
+ # priorities = [ "Run Ruby Quiz",
101
+ # "Document Modules",
102
+ # "Answer Questions on Ruby Talk" ]
103
+ #
104
+ # # Produce result.
105
+ # email = message.result
106
+ # puts email
107
+ #
108
+ # <i>Generates:</i>
109
+ #
110
+ # From: James Edward Gray II <james@grayproductions.net>
111
+ # To: Community Spokesman <spokesman@ruby_community.org>
112
+ # Subject: Addressing Needs
113
+ #
114
+ # Community:
115
+ #
116
+ # Just wanted to send a quick note assuring that your needs are being addressed.
117
+ #
118
+ # I want you to know that my team will keep working on the issues, especially:
119
+ #
120
+ # * Run Ruby Quiz
121
+ # * Document Modules
122
+ # * Answer Questions on Ruby Talk
123
+ #
124
+ # Thanks for your patience.
125
+ #
126
+ # James Edward Gray II
127
+ #
128
+ # === Ruby in HTML
129
+ #
130
+ # ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
131
+ # this example to provide a special binding when the template is run, so that the instance
132
+ # variables in the Product object can be resolved.
133
+ #
134
+ # require "erb"
135
+ #
136
+ # # Build template data class.
137
+ # class Product
138
+ # def initialize( code, name, desc, cost )
139
+ # @code = code
140
+ # @name = name
141
+ # @desc = desc
142
+ # @cost = cost
143
+ #
144
+ # @features = [ ]
145
+ # end
146
+ #
147
+ # def add_feature( feature )
148
+ # @features << feature
149
+ # end
150
+ #
151
+ # # Support templating of member data.
152
+ # def get_binding
153
+ # binding
154
+ # end
155
+ #
156
+ # # ...
157
+ # end
158
+ #
159
+ # # Create template.
160
+ # template = %{
161
+ # <html>
162
+ # <head><title>Ruby Toys -- <%= @name %></title></head>
163
+ # <body>
164
+ #
165
+ # <h1><%= @name %> (<%= @code %>)</h1>
166
+ # <p><%= @desc %></p>
167
+ #
168
+ # <ul>
169
+ # <% @features.each do |f| %>
170
+ # <li><b><%= f %></b></li>
171
+ # <% end %>
172
+ # </ul>
173
+ #
174
+ # <p>
175
+ # <% if @cost < 10 %>
176
+ # <b>Only <%= @cost %>!!!</b>
177
+ # <% else %>
178
+ # Call for a price, today!
179
+ # <% end %>
180
+ # </p>
181
+ #
182
+ # </body>
183
+ # </html>
184
+ # }.gsub(/^ /, '')
185
+ #
186
+ # rhtml = ERB.new(template)
187
+ #
188
+ # # Set up template data.
189
+ # toy = Product.new( "TZ-1002",
190
+ # "Rubysapien",
191
+ # "Geek's Best Friend! Responds to Ruby commands...",
192
+ # 999.95 )
193
+ # toy.add_feature("Listens for verbal commands in the Ruby language!")
194
+ # toy.add_feature("Ignores Perl, Java, and all C variants.")
195
+ # toy.add_feature("Karate-Chop Action!!!")
196
+ # toy.add_feature("Matz signature on left leg.")
197
+ # toy.add_feature("Gem studded eyes... Rubies, of course!")
198
+ #
199
+ # # Produce result.
200
+ # rhtml.run(toy.get_binding)
201
+ #
202
+ # <i>Generates (some blank lines removed):</i>
203
+ #
204
+ # <html>
205
+ # <head><title>Ruby Toys -- Rubysapien</title></head>
206
+ # <body>
207
+ #
208
+ # <h1>Rubysapien (TZ-1002)</h1>
209
+ # <p>Geek's Best Friend! Responds to Ruby commands...</p>
210
+ #
211
+ # <ul>
212
+ # <li><b>Listens for verbal commands in the Ruby language!</b></li>
213
+ # <li><b>Ignores Perl, Java, and all C variants.</b></li>
214
+ # <li><b>Karate-Chop Action!!!</b></li>
215
+ # <li><b>Matz signature on left leg.</b></li>
216
+ # <li><b>Gem studded eyes... Rubies, of course!</b></li>
217
+ # </ul>
218
+ #
219
+ # <p>
220
+ # Call for a price, today!
221
+ # </p>
222
+ #
223
+ # </body>
224
+ # </html>
225
+ #
226
+ #
227
+ # == Notes
228
+ #
229
+ # There are a variety of templating solutions available in various Ruby projects:
230
+ # * ERB's big brother, eRuby, works the same but is written in C for speed;
231
+ # * Amrita (smart at producing HTML/XML);
232
+ # * cs/Template (written in C for speed);
233
+ # * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
234
+ # * and others; search the RAA.
235
+ #
236
+ # Rails, the web application framework, uses ERB to create views.
237
+ #
238
+ class ERB
239
+ Revision = '$Date$' #'
240
+
241
+ # Returns revision information for the erb.rb module.
242
+ def self.version
243
+ "erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
244
+ end
245
+ end
246
+
247
+ #--
248
+ # ERB::Compiler
249
+ class ERB
250
+ class Compiler # :nodoc:
251
+ class PercentLine # :nodoc:
252
+ def initialize(str)
253
+ @value = str
254
+ end
255
+ attr_reader :value
256
+ alias :to_s :value
257
+
258
+ def empty?
259
+ @value.empty?
260
+ end
261
+ end
262
+
263
+ class Scanner # :nodoc:
264
+ @scanner_map = {}
265
+ def self.regist_scanner(klass, trim_mode, percent)
266
+ @scanner_map[[trim_mode, percent]] = klass
267
+ end
268
+
269
+ def self.default_scanner=(klass)
270
+ @default_scanner = klass
271
+ end
272
+
273
+ def self.make_scanner(src, trim_mode, percent)
274
+ klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
275
+ klass.new(src, trim_mode, percent)
276
+ end
277
+
278
+ def initialize(src, trim_mode, percent)
279
+ @src = src
280
+ @stag = nil
281
+ end
282
+ attr_accessor :stag
283
+
284
+ def scan; end
285
+ end
286
+
287
+ class TrimScanner < Scanner # :nodoc:
288
+ def initialize(src, trim_mode, percent)
289
+ super
290
+ @trim_mode = trim_mode
291
+ @percent = percent
292
+ if @trim_mode == '>'
293
+ @scan_line = self.method(:trim_line1)
294
+ elsif @trim_mode == '<>'
295
+ @scan_line = self.method(:trim_line2)
296
+ elsif @trim_mode == '-'
297
+ @scan_line = self.method(:explicit_trim_line)
298
+ else
299
+ @scan_line = self.method(:scan_line)
300
+ end
301
+ end
302
+ attr_accessor :stag
303
+
304
+ def scan(&block)
305
+ @stag = nil
306
+ if @percent
307
+ @src.each do |line|
308
+ percent_line(line, &block)
309
+ end
310
+ else
311
+ @scan_line.call(@src, &block)
312
+ end
313
+ nil
314
+ end
315
+
316
+ def percent_line(line, &block)
317
+ if @stag || line[0] != ?%
318
+ return @scan_line.call(line, &block)
319
+ end
320
+
321
+ line[0] = ''
322
+ if line[0] == ?%
323
+ @scan_line.call(line, &block)
324
+ else
325
+ yield(PercentLine.new(line.chomp))
326
+ end
327
+ end
328
+
329
+ def scan_line(line)
330
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
331
+ tokens.each do |token|
332
+ next if token.empty?
333
+ yield(token)
334
+ end
335
+ end
336
+ end
337
+
338
+ def trim_line1(line)
339
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
340
+ tokens.each do |token|
341
+ next if token.empty?
342
+ if token == "%>\n"
343
+ yield('%>')
344
+ yield(:cr)
345
+ else
346
+ yield(token)
347
+ end
348
+ end
349
+ end
350
+ end
351
+
352
+ def trim_line2(line)
353
+ head = nil
354
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
355
+ tokens.each do |token|
356
+ next if token.empty?
357
+ head = token unless head
358
+ if token == "%>\n"
359
+ yield('%>')
360
+ if is_erb_stag?(head)
361
+ yield(:cr)
362
+ else
363
+ yield("\n")
364
+ end
365
+ head = nil
366
+ else
367
+ yield(token)
368
+ head = nil if token == "\n"
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ def explicit_trim_line(line)
375
+ line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
376
+ tokens.each do |token|
377
+ next if token.empty?
378
+ if @stag.nil? && /[ \t]*<%-/ =~ token
379
+ yield('<%')
380
+ elsif @stag && token == "-%>\n"
381
+ yield('%>')
382
+ yield(:cr)
383
+ elsif @stag && token == '-%>'
384
+ yield('%>')
385
+ else
386
+ yield(token)
387
+ end
388
+ end
389
+ end
390
+ end
391
+
392
+ ERB_STAG = %w(<%= <%# <%)
393
+ def is_erb_stag?(s)
394
+ ERB_STAG.member?(s)
395
+ end
396
+ end
397
+
398
+ Scanner.default_scanner = TrimScanner
399
+
400
+ class SimpleScanner < Scanner # :nodoc:
401
+ def scan
402
+ @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
403
+ tokens.each do |token|
404
+ next if token.empty?
405
+ yield(token)
406
+ end
407
+ end
408
+ end
409
+ end
410
+
411
+ Scanner.regist_scanner(SimpleScanner, nil, false)
412
+
413
+ begin
414
+ require 'strscan'
415
+ class SimpleScanner2 < Scanner # :nodoc:
416
+ def scan
417
+ stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
418
+ etag_reg = /(.*?)(%%>|%>|\z)/m
419
+ scanner = StringScanner.new(@src)
420
+ while ! scanner.eos?
421
+ scanner.scan(@stag ? etag_reg : stag_reg)
422
+ yield(scanner[1])
423
+ yield(scanner[2])
424
+ end
425
+ end
426
+ end
427
+ Scanner.regist_scanner(SimpleScanner2, nil, false)
428
+
429
+ class PercentScanner < Scanner # :nodoc:
430
+ def scan(&blk)
431
+ stag_reg = /(.*?)(^%%|^%|<%%|<%=|<%#|<%|\z)/m
432
+ etag_reg = /(.*?)(%%>|%>|\z)/m
433
+ scanner = StringScanner.new(@src)
434
+ while ! scanner.eos?
435
+ scanner.scan(@stag ? etag_reg : stag_reg)
436
+ yield(scanner[1])
437
+
438
+ elem = scanner[2]
439
+ if elem == '%%'
440
+ yield('%')
441
+ inline_scan(scanner.scan(/.*?(\n|\z)/), &blk)
442
+ elsif elem == '%'
443
+ yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
444
+ else
445
+ yield(elem)
446
+ end
447
+ end
448
+ end
449
+
450
+ def inline_scan(line)
451
+ stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
452
+ etag_reg = /(.*?)(%%>|%>|\z)/m
453
+ scanner = StringScanner.new(line)
454
+ while ! scanner.eos?
455
+ scanner.scan(@stag ? etag_reg : stag_reg)
456
+ yield(scanner[1])
457
+ yield(scanner[2])
458
+ end
459
+ end
460
+ end
461
+ Scanner.regist_scanner(PercentScanner, nil, true)
462
+
463
+ class ExplicitScanner < Scanner # :nodoc:
464
+ def scan
465
+ stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
466
+ etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
467
+ scanner = StringScanner.new(@src)
468
+ while ! scanner.eos?
469
+ scanner.scan(@stag ? etag_reg : stag_reg)
470
+ yield(scanner[1])
471
+
472
+ elem = scanner[2]
473
+ if /[ \t]*<%-/ =~ elem
474
+ yield('<%')
475
+ elsif elem == '-%>'
476
+ yield('%>')
477
+ yield(:cr) if scanner.scan(/(\n|\z)/)
478
+ else
479
+ yield(elem)
480
+ end
481
+ end
482
+ end
483
+ end
484
+ Scanner.regist_scanner(ExplicitScanner, '-', false)
485
+
486
+ rescue LoadError
487
+ end
488
+
489
+ class Buffer # :nodoc:
490
+ def initialize(compiler)
491
+ @compiler = compiler
492
+ @line = []
493
+ @script = ""
494
+ @compiler.pre_cmd.each do |x|
495
+ push(x)
496
+ end
497
+ end
498
+ attr_reader :script
499
+
500
+ def push(cmd)
501
+ @line << cmd
502
+ end
503
+
504
+ def cr
505
+ @script << (@line.join('; '))
506
+ @line = []
507
+ @script << "\n"
508
+ end
509
+
510
+ def close
511
+ return unless @line
512
+ @compiler.post_cmd.each do |x|
513
+ push(x)
514
+ end
515
+ @script << (@line.join('; '))
516
+ @line = nil
517
+ end
518
+ end
519
+
520
+ def content_dump(s)
521
+ n = s.count("\n")
522
+ if n > 0
523
+ s.dump + "\n" * n
524
+ else
525
+ s.dump
526
+ end
527
+ end
528
+
529
+ def compile(s)
530
+ out = Buffer.new(self)
531
+
532
+ content = ''
533
+ scanner = make_scanner(s)
534
+ scanner.scan do |token|
535
+ next if token.nil?
536
+ next if token == ''
537
+ if scanner.stag.nil?
538
+ case token
539
+ when PercentLine
540
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
541
+ content = ''
542
+ out.push(token.to_s)
543
+ out.cr
544
+ when :cr
545
+ out.cr
546
+ when '<%', '<%=', '<%#'
547
+ scanner.stag = token
548
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
549
+ content = ''
550
+ when "\n"
551
+ content << "\n"
552
+ out.push("#{@put_cmd} #{content_dump(content)}")
553
+ content = ''
554
+ when '<%%'
555
+ content << '<%'
556
+ else
557
+ content << token
558
+ end
559
+ else
560
+ case token
561
+ when '%>'
562
+ case scanner.stag
563
+ when '<%'
564
+ if content[-1] == ?\n
565
+ content.chop!
566
+ out.push(content)
567
+ out.cr
568
+ else
569
+ out.push(content)
570
+ end
571
+ when '<%='
572
+ out.push("#{@insert_cmd}((#{content}).to_s)")
573
+ when '<%#'
574
+ # out.push("# #{content_dump(content)}")
575
+ end
576
+ scanner.stag = nil
577
+ content = ''
578
+ when '%%>'
579
+ content << '%>'
580
+ else
581
+ content << token
582
+ end
583
+ end
584
+ end
585
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
586
+ out.close
587
+ out.script
588
+ end
589
+
590
+ def prepare_trim_mode(mode)
591
+ case mode
592
+ when 1
593
+ return [false, '>']
594
+ when 2
595
+ return [false, '<>']
596
+ when 0
597
+ return [false, nil]
598
+ when String
599
+ perc = mode.include?('%')
600
+ if mode.include?('-')
601
+ return [perc, '-']
602
+ elsif mode.include?('<>')
603
+ return [perc, '<>']
604
+ elsif mode.include?('>')
605
+ return [perc, '>']
606
+ else
607
+ [perc, nil]
608
+ end
609
+ else
610
+ return [false, nil]
611
+ end
612
+ end
613
+
614
+ def make_scanner(src)
615
+ Scanner.make_scanner(src, @trim_mode, @percent)
616
+ end
617
+
618
+ def initialize(trim_mode)
619
+ @percent, @trim_mode = prepare_trim_mode(trim_mode)
620
+ @put_cmd = 'print'
621
+ @insert_cmd = @put_cmd
622
+ @pre_cmd = []
623
+ @post_cmd = []
624
+ end
625
+ attr_reader :percent, :trim_mode
626
+ attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd
627
+ end
628
+ end
629
+
630
+ #--
631
+ # ERB
632
+ class ERB
633
+ #
634
+ # Constructs a new ERB object with the template specified in _str_.
635
+ #
636
+ # An ERB object works by building a chunk of Ruby code that will output
637
+ # the completed template when run. If _safe_level_ is set to a non-nil value,
638
+ # ERB code will be run in a separate thread with <b>$SAFE</b> set to the
639
+ # provided level.
640
+ #
641
+ # If _trim_mode_ is passed a String containing one or more of the following
642
+ # modifiers, ERB will adjust its code generation as listed:
643
+ #
644
+ # % enables Ruby code processing for lines beginning with %
645
+ # <> omit newline for lines starting with <% and ending in %>
646
+ # > omit newline for lines ending in %>
647
+ #
648
+ # _eoutvar_ can be used to set the name of the variable ERB will build up
649
+ # its output in. This is useful when you need to run multiple ERB
650
+ # templates through the same binding and/or when you want to control where
651
+ # output ends up. Pass the name of the variable to be used inside a String.
652
+ #
653
+ # === Example
654
+ #
655
+ # require "erb"
656
+ #
657
+ # # build data class
658
+ # class Listings
659
+ # PRODUCT = { :name => "Chicken Fried Steak",
660
+ # :desc => "A well messages pattie, breaded and fried.",
661
+ # :cost => 9.95 }
662
+ #
663
+ # attr_reader :product, :price
664
+ #
665
+ # def initialize( product = "", price = "" )
666
+ # @product = product
667
+ # @price = price
668
+ # end
669
+ #
670
+ # def build
671
+ # b = binding
672
+ # # create and run templates, filling member data variables
673
+ # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b
674
+ # <%= PRODUCT[:name] %>
675
+ # <%= PRODUCT[:desc] %>
676
+ # END_PRODUCT
677
+ # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@price").result b
678
+ # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
679
+ # <%= PRODUCT[:desc] %>
680
+ # END_PRICE
681
+ # end
682
+ # end
683
+ #
684
+ # # setup template data
685
+ # listings = Listings.new
686
+ # listings.build
687
+ #
688
+ # puts listings.product + "\n" + listings.price
689
+ #
690
+ # _Generates_
691
+ #
692
+ # Chicken Fried Steak
693
+ # A well messages pattie, breaded and fried.
694
+ #
695
+ # Chicken Fried Steak -- 9.95
696
+ # A well messages pattie, breaded and fried.
697
+ #
698
+ def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
699
+ @safe_level = safe_level
700
+ compiler = ERB::Compiler.new(trim_mode)
701
+ set_eoutvar(compiler, eoutvar)
702
+ @src = compiler.compile(str)
703
+ @filename = nil
704
+ end
705
+
706
+ # The Ruby code generated by ERB
707
+ attr_reader :src
708
+
709
+ # The optional _filename_ argument passed to Kernel#eval when the ERB code
710
+ # is run
711
+ attr_accessor :filename
712
+
713
+ #
714
+ # Can be used to set _eoutvar_ as described in ERB#new. It's probably easier
715
+ # to just use the constructor though, since calling this method requires the
716
+ # setup of an ERB _compiler_ object.
717
+ #
718
+ def set_eoutvar(compiler, eoutvar = '_erbout')
719
+ compiler.put_cmd = "#{eoutvar}.concat"
720
+ compiler.insert_cmd = "#{eoutvar}.concat"
721
+
722
+ cmd = []
723
+ cmd.push "#{eoutvar} = ''"
724
+
725
+ compiler.pre_cmd = cmd
726
+
727
+ cmd = []
728
+ cmd.push(eoutvar)
729
+
730
+ compiler.post_cmd = cmd
731
+ end
732
+
733
+ # Generate results and print them. (see ERB#result)
734
+ def run(b=TOPLEVEL_BINDING)
735
+ print self.result(b)
736
+ end
737
+
738
+ #
739
+ # Executes the generated ERB code to produce a completed template, returning
740
+ # the results of that code. (See ERB#new for details on how this process can
741
+ # be affected by _safe_level_.)
742
+ #
743
+ # _b_ accepts a Binding or Proc object which is used to set the context of
744
+ # code evaluation.
745
+ #
746
+ def result(b=TOPLEVEL_BINDING)
747
+ if @safe_level
748
+ proc {
749
+ $SAFE = @safe_level
750
+ eval(@src, b, (@filename || '(erb)'), 1)
751
+ }.call
752
+ else
753
+ eval(@src, b, (@filename || '(erb)'), 1)
754
+ end
755
+ end
756
+
757
+ # Define _methodname_ as instance method of _mod_ from compiled ruby source.
758
+ #
759
+ # example:
760
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
761
+ # erb = ERB.new(File.read(filename))
762
+ # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
763
+ # print MyClass.new.render('foo', 123)
764
+ def def_method(mod, methodname, fname='(ERB)')
765
+ mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0)
766
+ end
767
+
768
+ # Create unnamed module, define _methodname_ as instance method of it, and return it.
769
+ #
770
+ # example:
771
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
772
+ # erb = ERB.new(File.read(filename))
773
+ # erb.filename = filename
774
+ # MyModule = erb.def_module('render(arg1, arg2)')
775
+ # class MyClass
776
+ # include MyModule
777
+ # end
778
+ def def_module(methodname='erb')
779
+ mod = Module.new
780
+ def_method(mod, methodname, @filename || '(ERB)')
781
+ mod
782
+ end
783
+
784
+ # Define unnamed class which has _methodname_ as instance method, and return it.
785
+ #
786
+ # example:
787
+ # class MyClass_
788
+ # def initialize(arg1, arg2)
789
+ # @arg1 = arg1; @arg2 = arg2
790
+ # end
791
+ # end
792
+ # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
793
+ # erb = ERB.new(File.read(filename))
794
+ # erb.filename = filename
795
+ # MyClass = erb.def_class(MyClass_, 'render()')
796
+ # print MyClass.new('foo', 123).render()
797
+ def def_class(superklass=Object, methodname='result')
798
+ cls = Class.new(superklass)
799
+ def_method(cls, methodname, @filename || '(ERB)')
800
+ cls
801
+ end
802
+ end
803
+
804
+ #--
805
+ # ERB::Util
806
+ class ERB
807
+ # A utility module for conversion routines, often handy in HTML generation.
808
+ module Util
809
+ public
810
+ #
811
+ # A utility method for escaping HTML tag characters in _s_.
812
+ #
813
+ # require "erb"
814
+ # include ERB::Util
815
+ #
816
+ # puts html_escape("is a > 0 & a < 10?")
817
+ #
818
+ # _Generates_
819
+ #
820
+ # is a &gt; 0 &amp; a &lt; 10?
821
+ #
822
+ def html_escape(s)
823
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
824
+ end
825
+ alias h html_escape
826
+ module_function :h
827
+ module_function :html_escape
828
+
829
+ #
830
+ # A utility method for encoding the String _s_ as a URL.
831
+ #
832
+ # require "erb"
833
+ # include ERB::Util
834
+ #
835
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
836
+ #
837
+ # _Generates_
838
+ #
839
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
840
+ #
841
+ def url_encode(s)
842
+ s.to_s.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
843
+ end
844
+ alias u url_encode
845
+ module_function :u
846
+ module_function :url_encode
847
+ end
848
+ end
849
+
850
+ #--
851
+ # ERB::DefMethod
852
+ class ERB
853
+ # Utility module to define eRuby script as instance method.
854
+ #
855
+ # === Example
856
+ #
857
+ # example.rhtml:
858
+ # <% for item in @items %>
859
+ # <b><%= item %></b>
860
+ # <% end %>
861
+ #
862
+ # example.rb:
863
+ # require 'erb'
864
+ # class MyClass
865
+ # extend ERB::DefMethod
866
+ # def_erb_method('render()', 'example.rhtml')
867
+ # def initialize(items)
868
+ # @items = items
869
+ # end
870
+ # end
871
+ # print MyClass.new([10,20,30]).render()
872
+ #
873
+ # result:
874
+ #
875
+ # <b>10</b>
876
+ #
877
+ # <b>20</b>
878
+ #
879
+ # <b>30</b>
880
+ #
881
+ module DefMethod
882
+ public
883
+ # define _methodname_ as instance method of current module, using ERB object or eRuby file
884
+ def def_erb_method(methodname, erb_or_fname)
885
+ if erb_or_fname.kind_of? String
886
+ fname = erb_or_fname
887
+ erb = ERB.new(File.read(fname))
888
+ erb.def_method(self, methodname, fname)
889
+ else
890
+ erb = erb_or_fname
891
+ erb.def_method(self, methodname, erb.filename || '(ERB)')
892
+ end
893
+ end
894
+ module_function :def_erb_method
895
+ end
896
+ end