markdown.rb 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. require 'tilt/template'
  2. module Tilt
  3. # Discount Markdown implementation. See:
  4. # http://github.com/rtomayko/rdiscount
  5. #
  6. # RDiscount is a simple text filter. It does not support +scope+ or
  7. # +locals+. The +:smart+ and +:filter_html+ options may be set true
  8. # to enable those flags on the underlying RDiscount object.
  9. class RDiscountTemplate < Template
  10. self.default_mime_type = 'text/html'
  11. ALIAS = {
  12. :escape_html => :filter_html,
  13. :smartypants => :smart
  14. }
  15. FLAGS = [:smart, :filter_html, :smartypants, :escape_html]
  16. def flags
  17. FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag }
  18. end
  19. def self.engine_initialized?
  20. defined? ::RDiscount
  21. end
  22. def initialize_engine
  23. require_template_library 'rdiscount'
  24. end
  25. def prepare
  26. @engine = RDiscount.new(data, *flags)
  27. @output = nil
  28. end
  29. def evaluate(scope, locals, &block)
  30. @output ||= @engine.to_html
  31. end
  32. end
  33. # Upskirt Markdown implementation. See:
  34. # https://github.com/tanoku/redcarpet
  35. #
  36. # Supports both Redcarpet 1.x and 2.x
  37. class RedcarpetTemplate < Template
  38. def self.engine_initialized?
  39. defined? ::Redcarpet
  40. end
  41. def initialize_engine
  42. require_template_library 'redcarpet'
  43. end
  44. def prepare
  45. klass = [Redcarpet1, Redcarpet2].detect { |e| e.engine_initialized? }
  46. @engine = klass.new(file, line, options) { data }
  47. end
  48. def evaluate(scope, locals, &block)
  49. @engine.evaluate(scope, locals, &block)
  50. end
  51. # Compatibility mode for Redcarpet 1.x
  52. class Redcarpet1 < RDiscountTemplate
  53. self.default_mime_type = 'text/html'
  54. def self.engine_initialized?
  55. defined? ::RedcarpetCompat
  56. end
  57. def prepare
  58. @engine = RedcarpetCompat.new(data, *flags)
  59. @output = nil
  60. end
  61. end
  62. # Future proof mode for Redcarpet 2.x (not yet released)
  63. class Redcarpet2 < Template
  64. self.default_mime_type = 'text/html'
  65. def self.engine_initialized?
  66. defined? ::Redcarpet::Render
  67. end
  68. def generate_renderer
  69. renderer = options.delete(:renderer) || Redcarpet::Render::HTML
  70. return renderer unless options.delete(:smartypants)
  71. return renderer if renderer <= Redcarpet::Render::SmartyPants
  72. if renderer == Redcarpet::Render::XHTML
  73. Redcarpet::Render::SmartyHTML.new(:xhtml => true)
  74. elsif renderer == Redcarpet::Render::HTML
  75. Redcarpet::Render::SmartyHTML
  76. elsif renderer.is_a? Class
  77. Class.new(renderer) { include Redcarpet::Render::SmartyPants }
  78. else
  79. renderer.extend Redcarpet::Render::SmartyPants
  80. end
  81. end
  82. def prepare
  83. # try to support the same aliases
  84. RDiscountTemplate::ALIAS.each do |opt, aka|
  85. next if options.key? opt or not options.key? aka
  86. options[opt] = options.delete(aka)
  87. end
  88. # only raise an exception if someone is trying to enable :escape_html
  89. options.delete(:escape_html) unless options[:escape_html]
  90. @engine = Redcarpet::Markdown.new(generate_renderer, options)
  91. @output = nil
  92. end
  93. def evaluate(scope, locals, &block)
  94. @output ||= @engine.render(data)
  95. end
  96. end
  97. end
  98. # BlueCloth Markdown implementation. See:
  99. # http://deveiate.org/projects/BlueCloth/
  100. class BlueClothTemplate < Template
  101. self.default_mime_type = 'text/html'
  102. def self.engine_initialized?
  103. defined? ::BlueCloth
  104. end
  105. def initialize_engine
  106. require_template_library 'bluecloth'
  107. end
  108. def prepare
  109. @engine = BlueCloth.new(data, options)
  110. @output = nil
  111. end
  112. def evaluate(scope, locals, &block)
  113. @output ||= @engine.to_html
  114. end
  115. end
  116. # Maruku markdown implementation. See:
  117. # http://maruku.rubyforge.org/
  118. class MarukuTemplate < Template
  119. def self.engine_initialized?
  120. defined? ::Maruku
  121. end
  122. def initialize_engine
  123. require_template_library 'maruku'
  124. end
  125. def prepare
  126. @engine = Maruku.new(data, options)
  127. @output = nil
  128. end
  129. def evaluate(scope, locals, &block)
  130. @output ||= @engine.to_html
  131. end
  132. end
  133. # Kramdown Markdown implementation. See:
  134. # http://kramdown.rubyforge.org/
  135. class KramdownTemplate < Template
  136. DUMB_QUOTES = [39, 39, 34, 34]
  137. def self.engine_initialized?
  138. defined? ::Kramdown
  139. end
  140. def initialize_engine
  141. require_template_library 'kramdown'
  142. end
  143. def prepare
  144. options[:smart_quotes] = DUMB_QUOTES unless options[:smartypants]
  145. @engine = Kramdown::Document.new(data, options)
  146. @output = nil
  147. end
  148. def evaluate(scope, locals, &block)
  149. @output ||= @engine.to_html
  150. end
  151. end
  152. end