/scalate-jruby/src/main/resources/haml-3.0.25/lib/haml/filters.rb

http://github.com/scalate/scalate · Ruby · 371 lines · 295 code · 6 blank · 70 comment · 5 complexity · e41d69177abaeebff9f2ebb5846d166a MD5 · raw file

  1. module Haml
  2. # The module containing the default Haml filters,
  3. # as well as the base module, {Haml::Filters::Base}.
  4. #
  5. # @see Haml::Filters::Base
  6. module Filters
  7. # @return [{String => Haml::Filters::Base}] a hash of filter names to classes
  8. def self.defined
  9. @defined ||= {}
  10. end
  11. # The base module for Haml filters.
  12. # User-defined filters should be modules including this module.
  13. # The name of the filter is taken by downcasing the module name.
  14. # For instance, if the module is named `FooBar`, the filter will be `:foobar`.
  15. #
  16. # A user-defined filter should override either \{#render} or {\#compile}.
  17. # \{#render} is the most common.
  18. # It takes a string, the filter source,
  19. # and returns another string, the result of the filter.
  20. # For example, the following will define a filter named `:sass`:
  21. #
  22. # module Haml::Filters::Sass
  23. # include Haml::Filters::Base
  24. #
  25. # def render(text)
  26. # ::Sass::Engine.new(text).render
  27. # end
  28. # end
  29. #
  30. # For details on overriding \{#compile}, see its documentation.
  31. #
  32. # Note that filters overriding \{#render} automatically support `#{}`
  33. # for interpolating Ruby code.
  34. # Those overriding \{#compile} will need to add such support manually
  35. # if it's desired.
  36. module Base
  37. # This method is automatically called when {Base} is included in a module.
  38. # It automatically defines a filter
  39. # with the downcased name of that module.
  40. # For example, if the module is named `FooBar`, the filter will be `:foobar`.
  41. #
  42. # @param base [Module, Class] The module that this is included in
  43. def self.included(base)
  44. Filters.defined[base.name.split("::").last.downcase] = base
  45. base.extend(base)
  46. end
  47. # Takes the source text that should be passed to the filter
  48. # and returns the result of running the filter on that string.
  49. #
  50. # This should be overridden in most individual filter modules
  51. # to render text with the given filter.
  52. # If \{#compile} is overridden, however, \{#render} doesn't need to be.
  53. #
  54. # @param text [String] The source text for the filter to process
  55. # @return [String] The filtered result
  56. # @raise [Haml::Error] if it's not overridden
  57. def render(text)
  58. raise Error.new("#{self.inspect}#render not defined!")
  59. end
  60. # Same as \{#render}, but takes a {Haml::Engine} options hash as well.
  61. # It's only safe to rely on options made available in {Haml::Engine#options\_for\_buffer}.
  62. #
  63. # @see #render
  64. # @param text [String] The source text for the filter to process
  65. # @return [String] The filtered result
  66. # @raise [Haml::Error] if it or \{#render} isn't overridden
  67. def render_with_options(text, options)
  68. render(text)
  69. end
  70. # Same as \{#compile}, but requires the necessary files first.
  71. # *This is used by {Haml::Engine} and is not intended to be overridden or used elsewhere.*
  72. #
  73. # @see #compile
  74. def internal_compile(*args)
  75. resolve_lazy_requires
  76. compile(*args)
  77. end
  78. # This should be overridden when a filter needs to have access to the Haml evaluation context.
  79. # Rather than applying a filter to a string at compile-time,
  80. # \{#compile} uses the {Haml::Precompiler} instance to compile the string to Ruby code
  81. # that will be executed in the context of the active Haml template.
  82. #
  83. # Warning: the {Haml::Precompiler} interface is neither well-documented
  84. # nor guaranteed to be stable.
  85. # If you want to make use of it, you'll probably need to look at the source code
  86. # and should test your filter when upgrading to new Haml versions.
  87. #
  88. # @param precompiler [Haml::Precompiler] The precompiler instance
  89. # @param text [String] The text of the filter
  90. # @raise [Haml::Error] if none of \{#compile}, \{#render}, and \{#render_with_options} are overridden
  91. def compile(precompiler, text)
  92. resolve_lazy_requires
  93. filter = self
  94. precompiler.instance_eval do
  95. if contains_interpolation?(text)
  96. return if options[:suppress_eval]
  97. text = unescape_interpolation(text).gsub(/(\\+)n/) do |s|
  98. escapes = $1.size
  99. next s if escapes % 2 == 0
  100. ("\\" * (escapes - 1)) + "\n"
  101. end
  102. newline if text.gsub!(/\n"\Z/, "\\n\"")
  103. push_script <<RUBY.strip, :escape_html => false
  104. find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options))
  105. RUBY
  106. return
  107. end
  108. rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, precompiler.options), precompiler.options[:preserve])
  109. if !options[:ugly]
  110. push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
  111. else
  112. push_text(rendered.rstrip)
  113. end
  114. (text.count("\n") - 1).times {newline}
  115. resolve_newlines
  116. newline
  117. end
  118. end
  119. # This becomes a class method of modules that include {Base}.
  120. # It allows the module to specify one or more Ruby files
  121. # that Haml should try to require when compiling the filter.
  122. #
  123. # The first file specified is tried first, then the second, etc.
  124. # If none are found, the compilation throws an exception.
  125. #
  126. # For example:
  127. #
  128. # module Haml::Filters::Markdown
  129. # lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth'
  130. #
  131. # ...
  132. # end
  133. #
  134. # @param reqs [Array<String>] The requires to run
  135. def lazy_require(*reqs)
  136. @lazy_requires = reqs
  137. end
  138. private
  139. def resolve_lazy_requires
  140. return unless @lazy_requires
  141. @lazy_requires[0...-1].each do |req|
  142. begin
  143. @required = req
  144. require @required
  145. return
  146. rescue LoadError; end # RCov doesn't see this, but it is run
  147. end
  148. begin
  149. @required = @lazy_requires[-1]
  150. require @required
  151. rescue LoadError => e
  152. classname = self.name.match(/\w+$/)[0]
  153. if @lazy_requires.size == 1
  154. raise Error.new("Can't run #{classname} filter; required file '#{@lazy_requires.first}' not found")
  155. else
  156. raise Error.new("Can't run #{classname} filter; required #{@lazy_requires.map { |r| "'#{r}'" }.join(' or ')}, but none were found")
  157. end
  158. end
  159. end
  160. end
  161. end
  162. end
  163. begin
  164. require 'rubygems'
  165. rescue LoadError; end
  166. module Haml
  167. module Filters
  168. # Does not parse the filtered text.
  169. # This is useful for large blocks of text without HTML tags,
  170. # when you don't want lines starting with `.` or `-`
  171. # to be parsed.
  172. module Plain
  173. include Base
  174. # @see Base#render
  175. def render(text); text; end
  176. end
  177. # Surrounds the filtered text with `<script>` and CDATA tags.
  178. # Useful for including inline Javascript.
  179. module Javascript
  180. include Base
  181. # @see Base#render_with_options
  182. def render_with_options(text, options)
  183. <<END
  184. <script type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}>
  185. //<![CDATA[
  186. #{text.rstrip.gsub("\n", "\n ")}
  187. //]]>
  188. </script>
  189. END
  190. end
  191. end
  192. # Surrounds the filtered text with `<style>` and CDATA tags.
  193. # Useful for including inline CSS.
  194. module Css
  195. include Base
  196. # @see Base#render_with_options
  197. def render_with_options(text, options)
  198. <<END
  199. <style type=#{options[:attr_wrapper]}text/css#{options[:attr_wrapper]}>
  200. /*<![CDATA[*/
  201. #{text.rstrip.gsub("\n", "\n ")}
  202. /*]]>*/
  203. </style>
  204. END
  205. end
  206. end
  207. # Surrounds the filtered text with CDATA tags.
  208. module Cdata
  209. include Base
  210. # @see Base#render
  211. def render(text)
  212. "<![CDATA[#{("\n" + text).rstrip.gsub("\n", "\n ")}\n]]>"
  213. end
  214. end
  215. # Works the same as {Plain}, but HTML-escapes the text
  216. # before placing it in the document.
  217. module Escaped
  218. include Base
  219. # @see Base#render
  220. def render(text)
  221. Haml::Helpers.html_escape text
  222. end
  223. end
  224. # Parses the filtered text with the normal Ruby interpreter.
  225. # All output sent to `$stdout`, such as with `puts`,
  226. # is output into the Haml document.
  227. # Not available if the {file:HAML_REFERENCE.md#suppress_eval-option `:suppress_eval`} option is set to true.
  228. # The Ruby code is evaluated in the same context as the Haml template.
  229. module Ruby
  230. include Base
  231. lazy_require 'stringio'
  232. # @see Base#compile
  233. def compile(precompiler, text)
  234. return if precompiler.options[:suppress_eval]
  235. precompiler.instance_eval do
  236. push_silent <<-FIRST.gsub("\n", ';') + text + <<-LAST.gsub("\n", ';')
  237. _haml_old_stdout = $stdout
  238. $stdout = StringIO.new(_hamlout.buffer, 'a')
  239. FIRST
  240. _haml_old_stdout, $stdout = $stdout, _haml_old_stdout
  241. _haml_old_stdout.close
  242. LAST
  243. end
  244. end
  245. end
  246. # Inserts the filtered text into the template with whitespace preserved.
  247. # `preserve`d blocks of text aren't indented,
  248. # and newlines are replaced with the HTML escape code for newlines,
  249. # to preserve nice-looking output.
  250. #
  251. # @see Haml::Helpers#preserve
  252. module Preserve
  253. include Base
  254. # @see Base#render
  255. def render(text)
  256. Haml::Helpers.preserve text
  257. end
  258. end
  259. # Parses the filtered text with {Sass} to produce CSS output.
  260. module Sass
  261. include Base
  262. lazy_require 'sass/plugin'
  263. # @see Base#render
  264. def render(text)
  265. ::Sass::Engine.new(text, ::Sass::Plugin.engine_options).render
  266. end
  267. end
  268. # Parses the filtered text with ERB.
  269. # Not available if the {file:HAML_REFERENCE.md#suppress_eval-option `:suppress_eval`} option is set to true.
  270. # Embedded Ruby code is evaluated in the same context as the Haml template.
  271. module ERB
  272. include Base
  273. lazy_require 'erb'
  274. # @see Base#compile
  275. def compile(precompiler, text)
  276. return if precompiler.options[:suppress_eval]
  277. src = ::ERB.new(text).src.sub(/^#coding:.*?\n/, '').
  278. sub(/^_erbout = '';/, "")
  279. precompiler.send(:push_silent, src)
  280. end
  281. end
  282. # Parses the filtered text with [Textile](http://www.textism.com/tools/textile).
  283. # Only works if [RedCloth](http://redcloth.org) is installed.
  284. module Textile
  285. include Base
  286. lazy_require 'redcloth'
  287. # @see Base#render
  288. def render(text)
  289. ::RedCloth.new(text).to_html(:textile)
  290. end
  291. end
  292. # An alias for the Textile filter,
  293. # since the only available Textile parser is RedCloth.
  294. # @api public
  295. RedCloth = Textile
  296. Filters.defined['redcloth'] = RedCloth
  297. # Parses the filtered text with [Markdown](http://daringfireball.net/projects/markdown).
  298. # Only works if [RDiscount](http://github.com/rtomayko/rdiscount),
  299. # [RPeg-Markdown](http://github.com/rtomayko/rpeg-markdown),
  300. # [Maruku](http://maruku.rubyforge.org),
  301. # or [BlueCloth](www.deveiate.org/projects/BlueCloth) are installed.
  302. module Markdown
  303. include Base
  304. lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth'
  305. # @see Base#render
  306. def render(text)
  307. engine = case @required
  308. when 'rdiscount'
  309. ::RDiscount
  310. when 'peg_markdown'
  311. ::PEGMarkdown
  312. when 'maruku'
  313. ::Maruku
  314. when 'bluecloth'
  315. ::BlueCloth
  316. end
  317. engine.new(text).to_html
  318. end
  319. end
  320. # Parses the filtered text with [Maruku](http://maruku.rubyforge.org),
  321. # which has some non-standard extensions to Markdown.
  322. module Maruku
  323. include Base
  324. lazy_require 'maruku'
  325. # @see Base#render
  326. def render(text)
  327. ::Maruku.new(text).to_html
  328. end
  329. end
  330. end
  331. end