public
Description: HTML Abstraction Markup Language - A Markup Haiku
Homepage: http://haml.hamptoncatlin.com
Clone URL: git://github.com/nex3/haml.git
commit  e2b61eb1e399f478be77c0d045c5d0abedb8279a
tree    7d19df42a27901212a9cd052c5b1ff6f38461ba5
parent  fc3d3d48df84276cd34849580f1ea711de8f44fd
haml / lib / haml / filters.rb
100644 249 lines (212 sloc) 6.464 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# This file contains redefinitions of and wrappers around various text
# filters so they can be used as Haml filters.
 
module Haml
  # The module containing the default filters,
  # as well as the base module,
  # Haml::Filters::Base.
  module Filters
    # The base module for Haml filters.
    # User-defined filters should be modules including this module.
    #
    # A user-defined filter should override either Base#render or Base #compile.
    # Base#render is the most common.
    # It takes a string, the filter source,
    # and returns another string,
    # the result of the filter.
    # For example:
    #
    # module Haml::Filters::Sass
    # include Haml::Filters::Base
    #
    # def render(text)
    # ::Sass::Engine.new(text).render
    # end
    # end
    #
    # For details on overriding #compile, see its documentation.
    #
    module Base
      def self.included(base) # :nodoc:
        base.extend(base)
      end
 
      # Takes a string, the source text that should be passed to the filter,
      # and returns the string resulting from running the filter on <tt>text</tt>.
      #
      # This should be overridden in most individual filter modules
      # to render text with the given filter.
      # If compile is overridden, however, render doesn't need to be.
      def render(text)
        raise Error.new("#{self.inspect}#render not defined!")
      end
 
      def internal_compile(*args) # :nodoc:
        resolve_lazy_requires
        compile(*args)
      end
 
      # compile should be overridden when a filter needs to have access
      # to the Haml evaluation context.
      # Rather than applying a filter to a string at compile-time,
      # compile uses the Haml::Precompiler instance to compile the string to Ruby code
      # that will be executed in the context of the active Haml template.
      #
      # Warning: the Haml::Precompiler interface is neither well-documented
      # nor guaranteed to be stable.
      # If you want to make use of it,
      # you'll probably need to look at the source code
      # and should test your filter when upgrading to new Haml versions.
      def compile(precompiler, text)
        resolve_lazy_requires
        filter = self
        precompiler.instance_eval do
          if contains_interpolation?(text)
            return if options[:suppress_eval]
 
            push_script(<<RUBY, false)
find_and_preserve(#{filter.inspect}.render(#{unescape_interpolation(text)}))
RUBY
            return
          end
 
          rendered = Haml::Helpers::find_and_preserve(filter.render(text), precompiler.options[:preserve])
 
          if !options[:ugly]
            push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
          else
            push_text(rendered.rstrip)
          end
        end
      end
 
      # This becomes a class method of modules that include Base.
      # It allows the module to specify one or more Ruby files
      # that Haml should try to require when compiling the filter.
      #
      # The first file specified is tried first,
      # then the second, etc.
      # If none are found, the compilation throws an exception.
      #
      # For example:
      #
      # module Haml::Filters::Markdown
      # lazy_require 'bluecloth', 'redcloth'
      #
      # ...
      # end
      #
      def lazy_require(*reqs)
        @lazy_requires = reqs
      end
 
      private
 
      def resolve_lazy_requires
        return unless @lazy_requires
 
        @lazy_requires[0...-1].each do |req|
          begin
            @required = req
            require @required
            return
          rescue LoadError; end # RCov doesn't see this, but it is run
        end
 
        begin
          @required = @lazy_requires[-1]
          require @required
        rescue LoadError => e
          classname = self.class.to_s.gsub(/\w+::/, '')
 
          if @lazy_requires.size == 1
            raise Error.new("Can't run #{classname} filter; required file '#{@lazy_requires.first}' not found")
          else
            raise Error.new("Can't run #{classname} filter; required #{@lazy_requires.map { |r| "'#{r}'" }.join(' or ')}, but none were found")
          end
        end
      end
    end
  end
end
 
# :stopdoc:
 
begin
  require 'rubygems'
rescue LoadError; end
 
module Haml
  module Filters
    module Plain
      include Base
 
      def render(text); text; end
    end
 
    module Javascript
      include Base
 
      def render(text)
        <<END
<script type='text/javascript'>
//<![CDATA[
#{text.rstrip.gsub("\n", "\n ")}
//]]>
</script>
END
      end
    end
 
    module Escaped
      include Base
 
      def render(text)
        Haml::Helpers.html_escape text
      end
    end
 
    module Ruby
      include Base
      lazy_require 'stringio'
 
      def compile(precompiler, text)
        precompiler.instance_eval do
          push_silent <<-END.gsub("\n", ';')
_haml_old_stdout = $stdout
$stdout = StringIO.new(_hamlout.buffer, 'a')
#{text}
_haml_old_stdout, $stdout = $stdout, _haml_old_stdout
_haml_old_stdout.close
END
        end
      end
    end
 
    module Preserve
      include Base
 
      def render(text)
        Haml::Helpers.preserve text
      end
    end
 
    module Sass
      include Base
      lazy_require 'sass/engine'
 
      def render(text)
        ::Sass::Engine.new(text).render
      end
    end
 
    module ERB
      include Base
      lazy_require 'erb'
 
      def compile(precompiler, text)
        src = ::ERB.new(text).src.sub(/^_erbout = '';/, "").gsub("\n", ';')
        precompiler.send(:push_silent, src)
      end
    end
 
    module RedCloth
      include Base
      lazy_require 'redcloth'
 
      def render(text)
        ::RedCloth.new(text).to_html
      end
    end
 
    # Uses RedCloth to provide only Textile (not Markdown) parsing
    module Textile
      include Base
      lazy_require 'redcloth'
 
      def render(text)
        ::RedCloth.new(text).to_html(:textile)
      end
    end
 
    # Uses BlueCloth or RedCloth to provide only Markdown (not Textile) parsing
    module Markdown
      include Base
      lazy_require 'bluecloth', 'redcloth'
 
      def render(text)
        if @required == 'bluecloth'
          ::BlueCloth.new(text).to_html
        else
          ::RedCloth.new(text).to_html(:markdown)
        end
      end
    end
  end
end
 
# :startdoc: