PageRenderTime 53ms CodeModel.GetById 13ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 1ms

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