waves-edge 2009.03.10.13.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/bin/waves +30 -0
  2. data/doc/HISTORY +1 -0
  3. data/doc/LICENSE +22 -0
  4. data/doc/README +1 -0
  5. data/doc/VERSION +1 -0
  6. data/lib/caches/file.rb +48 -0
  7. data/lib/caches/memcached.rb +40 -0
  8. data/lib/caches/simple.rb +25 -0
  9. data/lib/caches/synchronized.rb +25 -0
  10. data/lib/commands/console.rb +35 -0
  11. data/lib/commands/generate.rb +52 -0
  12. data/lib/commands/help.rb +5 -0
  13. data/lib/commands/server.rb +68 -0
  14. data/lib/dispatchers/base.rb +68 -0
  15. data/lib/dispatchers/default.rb +25 -0
  16. data/lib/ext/float.rb +13 -0
  17. data/lib/ext/hash.rb +31 -0
  18. data/lib/ext/integer.rb +27 -0
  19. data/lib/ext/kernel.rb +20 -0
  20. data/lib/ext/module.rb +20 -0
  21. data/lib/ext/object.rb +33 -0
  22. data/lib/ext/string.rb +20 -0
  23. data/lib/ext/symbol.rb +11 -0
  24. data/lib/ext/tempfile.rb +5 -0
  25. data/lib/foundations/classic.rb +59 -0
  26. data/lib/foundations/compact.rb +52 -0
  27. data/lib/helpers/basic.rb +11 -0
  28. data/lib/helpers/doc_type.rb +34 -0
  29. data/lib/helpers/extended.rb +21 -0
  30. data/lib/helpers/form.rb +42 -0
  31. data/lib/helpers/formatting.rb +30 -0
  32. data/lib/helpers/layouts.rb +37 -0
  33. data/lib/helpers/model.rb +37 -0
  34. data/lib/helpers/view.rb +22 -0
  35. data/lib/layers/inflect/english.rb +35 -0
  36. data/lib/layers/mvc.rb +41 -0
  37. data/lib/layers/mvc/controllers.rb +41 -0
  38. data/lib/layers/mvc/extensions.rb +52 -0
  39. data/lib/layers/orm/migration.rb +79 -0
  40. data/lib/layers/orm/providers/active_record.rb +84 -0
  41. data/lib/layers/orm/providers/active_record/migrations/empty.rb.erb +9 -0
  42. data/lib/layers/orm/providers/active_record/tasks/generate.rb +28 -0
  43. data/lib/layers/orm/providers/active_record/tasks/schema.rb +22 -0
  44. data/lib/layers/orm/providers/data_mapper.rb +37 -0
  45. data/lib/layers/orm/providers/filebase.rb +25 -0
  46. data/lib/layers/orm/providers/sequel.rb +87 -0
  47. data/lib/layers/orm/providers/sequel/migrations/empty.rb.erb +9 -0
  48. data/lib/layers/orm/providers/sequel/tasks/generate.rb +30 -0
  49. data/lib/layers/orm/providers/sequel/tasks/schema.rb +16 -0
  50. data/lib/layers/renderers/erubis.rb +52 -0
  51. data/lib/layers/renderers/haml.rb +67 -0
  52. data/lib/layers/renderers/markaby.rb +41 -0
  53. data/lib/matchers/accept.rb +21 -0
  54. data/lib/matchers/base.rb +30 -0
  55. data/lib/matchers/content_type.rb +17 -0
  56. data/lib/matchers/path.rb +67 -0
  57. data/lib/matchers/query.rb +21 -0
  58. data/lib/matchers/request.rb +27 -0
  59. data/lib/matchers/resource.rb +19 -0
  60. data/lib/matchers/traits.rb +19 -0
  61. data/lib/matchers/uri.rb +20 -0
  62. data/lib/renderers/mixin.rb +13 -0
  63. data/lib/resources/mixin.rb +136 -0
  64. data/lib/resources/paths.rb +132 -0
  65. data/lib/runtime/configuration.rb +100 -0
  66. data/lib/runtime/console.rb +23 -0
  67. data/lib/runtime/logger.rb +35 -0
  68. data/lib/runtime/mime_types.rb +536 -0
  69. data/lib/runtime/mocks.rb +14 -0
  70. data/lib/runtime/monitor.rb +32 -0
  71. data/lib/runtime/request.rb +152 -0
  72. data/lib/runtime/response.rb +43 -0
  73. data/lib/runtime/response_mixin.rb +54 -0
  74. data/lib/runtime/runtime.rb +69 -0
  75. data/lib/runtime/server.rb +20 -0
  76. data/lib/runtime/session.rb +27 -0
  77. data/lib/runtime/worker.rb +86 -0
  78. data/lib/servers/base.rb +42 -0
  79. data/lib/servers/mongrel.rb +13 -0
  80. data/lib/servers/webrick.rb +13 -0
  81. data/lib/tasks/gem.rb +32 -0
  82. data/lib/tasks/generate.rb +85 -0
  83. data/lib/views/errors.rb +49 -0
  84. data/lib/views/mixin.rb +64 -0
  85. data/lib/waves.rb +63 -0
  86. data/samples/blog/Rakefile +25 -0
  87. data/samples/blog/configurations/default.rb +11 -0
  88. data/samples/blog/configurations/development.rb +29 -0
  89. data/samples/blog/configurations/production.rb +26 -0
  90. data/samples/blog/models/comment.rb +23 -0
  91. data/samples/blog/models/entry.rb +31 -0
  92. data/samples/blog/public/css/site.css +13 -0
  93. data/samples/blog/public/javascript/jquery-1.2.6.min.js +32 -0
  94. data/samples/blog/public/javascript/site.js +13 -0
  95. data/samples/blog/resources/entry.rb +39 -0
  96. data/samples/blog/resources/map.rb +9 -0
  97. data/samples/blog/schema/migrations/001_initial_schema.rb +17 -0
  98. data/samples/blog/schema/migrations/002_add_comments.rb +18 -0
  99. data/samples/blog/schema/migrations/templates/empty.rb.erb +9 -0
  100. data/samples/blog/startup.rb +8 -0
  101. data/samples/blog/templates/comment/add.mab +12 -0
  102. data/samples/blog/templates/comment/list.mab +6 -0
  103. data/samples/blog/templates/entry/edit.mab +14 -0
  104. data/samples/blog/templates/entry/list.mab +16 -0
  105. data/samples/blog/templates/entry/show.mab +18 -0
  106. data/samples/blog/templates/entry/summary.mab +9 -0
  107. data/samples/blog/templates/errors/not_found_404.mab +7 -0
  108. data/samples/blog/templates/errors/server_error_500.mab +2 -0
  109. data/samples/blog/templates/layouts/default.mab +19 -0
  110. data/samples/blog/templates/waves/status.mab +85 -0
  111. data/templates/classic/Rakefile +90 -0
  112. data/templates/classic/configurations/default.rb.erb +9 -0
  113. data/templates/classic/configurations/development.rb.erb +26 -0
  114. data/templates/classic/configurations/production.rb.erb +29 -0
  115. data/templates/classic/controllers/.gitignore +0 -0
  116. data/templates/classic/helpers/.gitignore +0 -0
  117. data/templates/classic/lib/tasks/.gitignore +0 -0
  118. data/templates/classic/models/.gitignore +0 -0
  119. data/templates/classic/public/css/.gitignore +0 -0
  120. data/templates/classic/public/flash/.gitignore +0 -0
  121. data/templates/classic/public/images/.gitignore +0 -0
  122. data/templates/classic/public/javascript/.gitignore +0 -0
  123. data/templates/classic/resources/.gitignore +0 -0
  124. data/templates/classic/resources/map.rb.erb +8 -0
  125. data/templates/classic/schema/migrations/.gitignore +0 -0
  126. data/templates/classic/startup.rb.erb +11 -0
  127. data/templates/classic/templates/errors/not_found_404.mab +7 -0
  128. data/templates/classic/templates/errors/server_error_500.mab +7 -0
  129. data/templates/classic/templates/layouts/default.mab +14 -0
  130. data/templates/classic/tmp/sessions/.gitignore +0 -0
  131. data/templates/classic/views/.gitignore +0 -0
  132. data/templates/compact/startup.rb.erb +11 -0
  133. data/test/ext/object.rb +55 -0
  134. data/test/ext/shortcuts.rb +73 -0
  135. data/test/helpers.rb +17 -0
  136. data/test/match/accept.rb +34 -0
  137. data/test/match/methods.rb +22 -0
  138. data/test/match/params.rb +33 -0
  139. data/test/match/path.rb +106 -0
  140. data/test/match/query.rb +40 -0
  141. data/test/process/request.rb +75 -0
  142. data/test/process/resource.rb +53 -0
  143. data/test/resources/path.rb +166 -0
  144. data/test/runtime/configurations.rb +19 -0
  145. data/test/runtime/request.rb +63 -0
  146. data/test/runtime/response.rb +55 -0
  147. data/test/views/views.rb +34 -0
  148. metadata +394 -0
@@ -0,0 +1,13 @@
1
+ module Waves
2
+ module Ext
3
+ module Float
4
+ def to_delimited(delim=',')
5
+ self.to_s.gsub(/(\d)(?=(\d\d\d)+\.)/, "\\1#{delim}")
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ class Float # :nodoc:
12
+ include Waves::Ext::Float
13
+ end
@@ -0,0 +1,31 @@
1
+ module Waves
2
+ module Ext # :nodoc:
3
+
4
+ # Utility methods mixed into Hash.
5
+ module Hash
6
+
7
+ # Return a copy of the hash where all keys have been converted to strings.
8
+ def stringify_keys
9
+ inject({}) do |options, (key, value)|
10
+ options[key.to_s] = value
11
+ options
12
+ end
13
+ end
14
+
15
+ # Destructively convert all keys to symbols.
16
+ def symbolize_keys!
17
+ keys.each do |key|
18
+ unless key.is_a?(Symbol)
19
+ self[key.to_sym] = self[key]
20
+ delete(key)
21
+ end
22
+ end
23
+ self
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ class Hash # :nodoc:
30
+ include Waves::Ext::Hash
31
+ end
@@ -0,0 +1,27 @@
1
+ module Waves
2
+ module Ext
3
+ module Integer
4
+ def seconds ; self ; end
5
+ def minutes ; self * 60 ; end
6
+ def hours ; self * 60.minutes ; end
7
+ def days ; self * 24.hours ; end
8
+ def weeks ; self * 7.days ; end
9
+ def bytes ; self ; end
10
+ def kilobytes ; self * 1024 ; end
11
+ def megabytes ; self * 1024.kilobytes ; end
12
+ def gigabytes ; self * 1024.megabytes ; end
13
+ def terabytes ; self * 1024.gigabytes ; end
14
+ def petabytes ; self * 1024.terabytes ; end
15
+ def exabytes ; self * 1024.petabytes ; end
16
+ def zettabytes ; self * 1024.exabytes ; end
17
+ def yottabytes ; self * 1024.zettabytes ; end
18
+ def to_delimited(delim=',')
19
+ self.to_s.gsub(/(\d)(?=(\d\d\d)+$)/, "\\1#{delim}")
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class Integer # :nodoc:
26
+ include Waves::Ext::Integer
27
+ end
@@ -0,0 +1,20 @@
1
+ module Kernel
2
+ unless respond_to?(:debugger)
3
+ # Starts a debugging session if ruby-debug has been loaded (call waves-server --debugger to do load it).
4
+ def debugger
5
+ Waves::Logger.info "Debugger invoked but not loaded. Start server with --debugger to enable."
6
+ end
7
+ end
8
+
9
+ unless respond_to?(:engine)
10
+ # 'engine' exists to provide a quick and easy (and MRI-compatible!) interface to the RUBY_ENGINE constant
11
+ def engine; defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'; end
12
+ end
13
+
14
+ def safe_trap(*signals)
15
+ signals.each { |s| trap(s) { yield } }
16
+ Thread.new { loop { sleep 1 } } if RUBY_PLATFORM =~ /mswin32/
17
+ end
18
+
19
+
20
+ end
@@ -0,0 +1,20 @@
1
+ module Waves
2
+ module Ext
3
+ module Module
4
+
5
+ def basename ; self.name.split('::').last || '' ; end
6
+ def rootname ; self.name.split('::').first ; end
7
+ def root ; eval( "::#{self.rootname}" ) ; end
8
+
9
+ # Just a convenience method for dynamically referencing submodules. Note that
10
+ # you cannot do const_get, because that will also attempt to deref the cname
11
+ # at global scope. So it is more efficient to just use eval.
12
+ def []( cname ) ; eval( "self::#{cname.to_s.camel_case}" ) ; end
13
+
14
+ end
15
+ end
16
+ end
17
+
18
+ class Module # :nodoc:
19
+ include Waves::Ext::Module
20
+ end
@@ -0,0 +1,33 @@
1
+ module Waves
2
+ module Ext
3
+ module Object
4
+ # This is an extremely powerful little function that will be built-in to Ruby 1.9.
5
+ # This version is from Mauricio Fernandez via ruby-talk. Works like instance_eval
6
+ # except that you can pass parameters to the block.
7
+ def instance_exec(*args, &block)
8
+ mname = "__instance_exec_#{Thread.current.object_id.abs}"
9
+ class << self; self end.class_eval{ define_method(mname, &block) }
10
+ begin
11
+ ret = send(mname, *args)
12
+ ensure
13
+ class << self; self end.class_eval{ undef_method(mname) } rescue nil
14
+ end
15
+ ret
16
+ end
17
+
18
+ def cache_method_missing(name, method_body, *args, &block)
19
+ self.class.module_eval <<-METHOD
20
+ def #{name}(*args, &block)
21
+ #{method_body}
22
+ end
23
+ METHOD
24
+ self.send(name, *args, &block)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+
31
+ class Object # :nodoc:
32
+ include Waves::Ext::Object
33
+ end
@@ -0,0 +1,20 @@
1
+ # Utility methods mixed into String.
2
+
3
+ class String
4
+
5
+ # Syntactic sugar for using File.join to concatenate the argument to the receiver.
6
+ #
7
+ # require "lib" / "utilities" / "string"
8
+ #
9
+ # The idea is not original, but we can't remember where we first saw it.
10
+ # Waves::Ext::Symbol defines the same method, allowing for :files / 'afilename.txt'
11
+ #
12
+
13
+ def / ( s ) ; File.join( self, s.to_s ); end
14
+
15
+ alias_method :lower_camel_case, :subcamelcase
16
+ alias_method :camel_case, :camelcase
17
+ alias_method :snake_case, :snakecase
18
+ alias_method :title_case, :titlecase
19
+
20
+ end
@@ -0,0 +1,11 @@
1
+ class Symbol
2
+
3
+ # Syntactic sugar for using File.join to concatenate the argument to the receiver.
4
+ #
5
+ # require :lib / :utilities / :string
6
+ #
7
+ # The idea is not original, but we can't remember where we first saw it.
8
+ # Waves::Ext::Symbol defines the same method, allowing for :files / 'afilename.txt'
9
+
10
+ def / ( s ) ; File.join( self.to_s, s.to_s ) ; end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'tempfile'
2
+ class Tempfile
3
+ # override method to prevent problem uploading files with Rack
4
+ def ==(other) ; eql?(other) || super ; end
5
+ end
@@ -0,0 +1,59 @@
1
+ module Waves
2
+ module Foundations
3
+
4
+ # Provides Sun MVC features for your application.
5
+ # Includes ERb-style templates. You can also include others via Renderer Layers.
6
+ # It does NOT include a default ORM. Use an ORM Layer for that.
7
+
8
+ module Classic
9
+
10
+ def self.included( app )
11
+
12
+ gem 'dyoder-autocode', '~> 1.0.1'
13
+ require 'autocode'
14
+ require 'layers/mvc'
15
+ require 'layers/inflect/english'
16
+ require 'helpers/extended'
17
+ require 'layers/renderers/erubis'
18
+ require 'layers/renderers/markaby'
19
+
20
+ app.module_eval do
21
+
22
+ include AutoCode
23
+
24
+ app.auto_create_module( :Configurations ) do
25
+ auto_create_class :Default, Waves::Configurations::Default
26
+ auto_load :Default, :directories => [ :configurations ]
27
+ auto_create_class true, :Default
28
+ auto_load true, :directories => [ :configurations ]
29
+ end
30
+
31
+ app.auto_create_module( :Resources ) do
32
+ auto_create_class :Default, Waves::Resources::Base
33
+ auto_load :Default, :directories => [ :resources ]
34
+ auto_create_class true, :Default
35
+ auto_load true, :directories => [ :resources ]
36
+ auto_eval :Map do
37
+
38
+ handler( Waves::Dispatchers::NotFoundError ) do
39
+ app::Views::Errors.new( request ).not_found_404
40
+ end
41
+
42
+ end
43
+ end
44
+
45
+ include Waves::Layers::Inflect::English
46
+ include Waves::Layers::MVC
47
+ include Waves::Renderers::Erubis
48
+ include Waves::Renderers::Markaby
49
+
50
+ end
51
+
52
+ Waves << app
53
+
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+
@@ -0,0 +1,52 @@
1
+ module Waves
2
+ module Foundations
3
+ module Compact
4
+ def self.included( app )
5
+ app.module_eval {
6
+ const_set( :Resources, Module.new {
7
+ const_set( :Map, Class.new {
8
+ include Waves::Resources::Mixin
9
+
10
+ handler( Exception ) do |e|
11
+ Waves.debug? ? raise( e ) : Waves::Views::Errors.new( request ).server_error_500
12
+ end
13
+
14
+ handler( Waves::Dispatchers::NotFoundError ) do |e|
15
+ Waves.debug? ? raise( e ) : Waves::Views::Errors.new( request ).not_found_404
16
+ end
17
+
18
+ })
19
+ })
20
+ const_set( :Configurations, Module.new {
21
+ const_set( :Development, Class.new( Waves::Configurations::Default ) {
22
+ log :level => :debug
23
+ host '127.0.0.1'
24
+ port 3000
25
+ server Waves::Servers::Mongrel
26
+ resource app::Resources::Map
27
+ })
28
+ const_set( :Production, Class.new( self::Development ) {
29
+ log :level => :error, :output => ( "log.#{$$}" ), :rotation => :weekly
30
+ port 80
31
+ host '0.0.0.0'
32
+ server Waves::Servers::Mongrel
33
+ application {
34
+ use Rack::Session::Cookie, :key => 'rack.session',
35
+ # :domain => 'foo.com',
36
+ :path => '/',
37
+ :expire_after => 2592000,
38
+ :secret => 'Change it'
39
+
40
+ run ::Waves::Dispatchers::Default.new
41
+ }
42
+
43
+ })
44
+ })
45
+ }
46
+ Waves << app
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+
@@ -0,0 +1,11 @@
1
+ module Waves
2
+ module Helpers
3
+ module Basic
4
+ attr_reader :request
5
+ include Waves::ResponseMixin
6
+
7
+ def app ; Waves.main ; end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module Waves
2
+
3
+ module Helpers
4
+
5
+ module DocType
6
+
7
+ DOCTYPES = {
8
+ :html3 => "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n",
9
+ :html4_transitional =>
10
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" " <<
11
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n",
12
+ :html4_strict =>
13
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " <<
14
+ "\"http://www.w3.org/TR/html4/strict.dtd\">\n",
15
+ :html4_frameset =>
16
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" " <<
17
+ "\"http://www.w3.org/TR/html4/frameset.dtd\">\n",
18
+ :xhtml1_transitional =>
19
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " <<
20
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
21
+ :xhtml1_strict =>
22
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " <<
23
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n",
24
+ :xhtml1_frameset =>
25
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" " <<
26
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n",
27
+ :xhtml2 => "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
28
+ }
29
+
30
+ def doctype(type) ; self << DOCTYPES[type||:html4_strict] ; end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ require 'helpers/basic'
2
+ require 'helpers/doc_type'
3
+ require 'helpers/layouts'
4
+ require 'helpers/formatting'
5
+ require 'helpers/model'
6
+ require 'helpers/view'
7
+ require 'helpers/form'
8
+
9
+ module Waves
10
+ module Helpers
11
+ module Extended
12
+ include Waves::Helpers::Basic
13
+ include Waves::Helpers::DocType
14
+ include Waves::Helpers::Layouts
15
+ include Waves::Helpers::Formatting
16
+ include Waves::Helpers::Model
17
+ include Waves::Helpers::View
18
+ include Waves::Helpers::Form
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ module Waves
2
+
3
+ module Helpers
4
+
5
+ # Form helpers are used in generating forms. Since Markaby already provides Ruby
6
+ # methods for basic form generation, the focus of this helper is on providing templates
7
+ # to handle things that go beyond the basics. You must define a form template
8
+ # directory with templates for each type of form element you wish to use. The names
9
+ # of the template should match the +type+ option provided in the property method.
10
+ #
11
+ # For example, this code:
12
+ #
13
+ # property :name => 'blog.title', :type => :text, :value => @blog.title
14
+ #
15
+ # will invoke the +text+ form view (the template in +templates/form/text.mab+),
16
+ # passing in the name ('blog.title') and the value (@blog.title) as instance variables.
17
+ #
18
+ # These helpers work best with Markaby, but may work for other Renderers.
19
+ #
20
+
21
+ module Form
22
+
23
+ # This method really is a place-holder for common wrappers around groups of
24
+ # properties. You will usually want to override this. As is, it simply places
25
+ # a DIV element with class 'properties' around the block.
26
+ def properties(&block)
27
+ div.properties do
28
+ yield
29
+ end
30
+ end
31
+
32
+ # Invokes the form view for the +type+ given in the option.
33
+ def property( options )
34
+ self << view( :form, options[:type], options )
35
+ end
36
+
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,30 @@
1
+ require 'redcloth'
2
+ module Waves
3
+ module Helpers
4
+
5
+ # Formatting helpers are used to convert specialized content, like Markaby or
6
+ # Textile, into valid HTML. It also provides common escaping functions.
7
+ module Formatting
8
+
9
+ # Escape a string as HTML content.
10
+ def escape_html(s); Rack::Utils.escape_html(s); end
11
+
12
+ # Escape a URI, converting quotes and spaces and so on.
13
+ def escape_uri(s); Rack::Utils.escape(s); end
14
+
15
+ # Treat content as Markaby and evaluate (only works within a Markaby template).
16
+ # Used to pull Markaby content from a file or database into a Markaby template.
17
+ def markaby( content ); self << eval( content ); end
18
+
19
+ # Treat content as Textile.
20
+ def textile( content )
21
+ return if content.nil? or content.empty?
22
+ #( ::RedCloth::TEXTILE_TAGS << [ 96.chr, '&8216;'] ).each do |pat,ent|
23
+ # content.gsub!( pat, ent.gsub('&','&#') )
24
+ #end
25
+ self << ::RedCloth.new( content ).to_html
26
+ end
27
+
28
+ end
29
+ end
30
+ end