rhodes 0.1.0

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