Class: Haml::Engine

Inherits:
Object show all
Includes:
Precompiler
Defined in:
lib/haml/engine.rb

Overview

This is the frontend for using Haml programmatically. It can be directly used by the user by creating a new instance and calling #render to render the template. For example:

template = File.read('templates/really_cool_template.haml')
haml_engine = Haml::Engine.new(template)
output = haml_engine.render
puts output

Constant Summary

Constants included from Precompiler

Precompiler::COMMENT, Precompiler::DIV_CLASS, Precompiler::DIV_ID, Precompiler::DOCTYPE, Precompiler::DOCTYPE_REGEX, Precompiler::ELEMENT, Precompiler::ESCAPE, Precompiler::FILTER, Precompiler::FLAT_SCRIPT, Precompiler::LITERAL_VALUE_REGEX, Precompiler::MID_BLOCK_KEYWORD_REGEX, Precompiler::MULTILINE_CHAR_VALUE, Precompiler::PLAIN_TEXT, Precompiler::SANITIZE, Precompiler::SCRIPT, Precompiler::SILENT_COMMENT, Precompiler::SILENT_SCRIPT, Precompiler::SPECIAL_CHARACTERS

Constants included from Util

Util::RUBY_VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#def_static_method, #enum_with_index, #has?, #map_hash, #map_keys, #map_vals, #merge_adjacent_strings, #powerset, #ruby1_8?, #scope, #static_method_name, #to_hash

Constructor Details

#initialize(template, options = {}) ⇒ Engine

Precompiles the Haml template.

Parameters:

Raises:

  • (Haml::Error)

    if there’s a Haml syntax error in the template



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
# File 'lib/haml/engine.rb', line 70

def initialize(template, options = {})
  @options = {
    :suppress_eval => false,
    :attr_wrapper => "'",

    # Don't forget to update the docs in lib/haml.rb if you update these
    :autoclose => %w[meta img link br hr input area param col base],
    :preserve => %w[textarea pre],

    :filename => '(haml)',
    :line => 1,
    :ugly => false,
    :format => :xhtml,
    :escape_html => false,
  }
  unless ruby1_8?
    @options[:encoding] = Encoding.default_internal || "utf-8"
  end
  @options.merge! options
  @index = 0

  unless [:xhtml, :html4, :html5].include?(@options[:format])
    raise Haml::Error, "Invalid format #{@options[:format].inspect}"
  end

  if @options[:encoding] && @options[:encoding].is_a?(Encoding)
    @options[:encoding] = @options[:encoding].name
  end

  # :eod is a special end-of-document marker
  @template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
  @template_index = 0
  @to_close_stack = []
  @output_tabs = 0
  @template_tabs = 0
  @flat = false
  @newlines = 0
  @precompiled = ''
  @to_merge = []
  @tab_change  = 0
  @temp_count = 0

  precompile
rescue Haml::Error => e
  e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
  raise
end

Instance Attribute Details

#indentationString

The indentation used in the Haml document, or nil if the indentation is ambiguous (for example, for a single-level document).

Returns:

  • (String)


31
32
33
# File 'lib/haml/engine.rb', line 31

def indentation
  @indentation
end

#optionsHash<Symbol, Object>

The options hash. See the Haml options documentation.

Returns:



24
25
26
# File 'lib/haml/engine.rb', line 24

def options
  @options
end

Instance Method Details

#def_method(object, name, *local_names) ⇒ Object

Defines a method on object with the given name that renders the template and returns the result as a string.

If object is a class or module, the method will instead by defined as an instance method. For example:

t = Time.now
Haml::Engine.new("%p\n  Today's date is\n  .date= self.to_s").def_method(t, :render)
t.render #=> "<p>\n  Today's date is\n  <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"

Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
"foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"

The first argument of the defined method is a hash of local variable names to values. However, due to an unfortunate Ruby quirk, the local variables which can be assigned must be pre-declared. This is done with the local_names argument. For example:

# This works
obj = Object.new
Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"

# This doesn't
obj = Object.new
Haml::Engine.new("%p= foo").def_method(obj, :render)
obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'

Note that Haml modifies the evaluation context (either the scope object or the self object of the scope binding). It extends Helpers, and various instance variables are set (all prefixed with haml_).

Parameters:

  • object (Object, Module)

    The object on which to define the method

  • name (String, Symbol)

    The name of the method to define

  • local_names (Array<Symbol>)

    The names of the locals that can be passed to the proc



262
263
264
265
266
267
# File 'lib/haml/engine.rb', line 262

def def_method(object, name, *local_names)
  method = object.is_a?(Module) ? :module_eval : :instance_eval

  object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
              @options[:filename], @options[:line])
end

#html4?Boolean

Returns Whether or not the format is HTML4.

Returns:

  • (Boolean)

    Whether or not the format is HTML4.



44
45
46
# File 'lib/haml/engine.rb', line 44

def html4?
  @options[:format] == :html4
end

#html5?Boolean

Returns Whether or not the format is HTML5.

Returns:

  • (Boolean)

    Whether or not the format is HTML5.



49
50
51
# File 'lib/haml/engine.rb', line 49

def html5?
  @options[:format] == :html5
end

#html?Boolean

Returns Whether or not the format is any flavor of HTML.

Returns:

  • (Boolean)

    Whether or not the format is any flavor of HTML.



39
40
41
# File 'lib/haml/engine.rb', line 39

def html?
  html4? or html5?
end

#options_for_bufferHash<Symbol, Object> (protected)

Returns a subset of #options: those that Buffer cares about. All of the values here are such that when #inspect is called on the hash, it can be Kernel#evaled to get the same result back.

See the Haml options documentation.

Returns:

  • (Hash<Symbol, Object>)

    The options hash



278
279
280
281
282
283
284
285
286
287
# File 'lib/haml/engine.rb', line 278

def options_for_buffer
  {
    :autoclose => @options[:autoclose],
    :preserve => @options[:preserve],
    :attr_wrapper => @options[:attr_wrapper],
    :ugly => @options[:ugly],
    :format => @options[:format],
    :encoding => @options[:encoding],
  }
end

#precompiledString

The source code that is evaluated to produce the Haml document.

In Ruby 1.9, this is automatically converted to the correct encoding (see the :encoding option).

Returns:

  • (String)


59
60
61
62
# File 'lib/haml/engine.rb', line 59

def precompiled
  return @precompiled if ruby1_8?
  return @precompiled.encode(Encoding.find(@options[:encoding]))
end

#render(scope = Object.new, locals = {}, &block) ⇒ String Also known as: to_html

Processes the template and returns the result as a string.

scope is the context in which the template is evaluated. If it’s a Binding or Proc object, Haml uses it as the second argument to Kernel#eval; otherwise, Haml just uses its #instance_eval context.

Note that Haml modifies the evaluation context (either the scope object or the self object of the scope binding). It extends Helpers, and various instance variables are set (all prefixed with haml_). For example:

s = "foobar"
Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"

# s now extends Haml::Helpers
s.responds_to?(:html_attrs) #=> true

locals is a hash of local variables to make available to the template. For example:

Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"

If a block is passed to render, that block is run when yield is called within the template.

Due to some Ruby quirks, if scope is a Binding or Proc object and a block is given, the evaluation context may not be quite what the user expects. In particular, it’s equivalent to passing eval("self", scope) as scope. This won’t have an effect in most cases, but if you’re relying on local variables defined in the context of scope, they won’t work.

Parameters:

  • scope (Binding, Proc, Object) (defaults to: Object.new)

    The context in which the template is evaluated

  • locals (Hash<Symbol, Object>) (defaults to: {})

    Local variables that will be made available to the template

  • block (#to_proc)

    A block that can be yielded to within the template

Returns:

  • (String)

    The rendered template



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
# File 'lib/haml/engine.rb', line 159

def render(scope = Object.new, locals = {}, &block)
  buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)

  if scope.is_a?(Binding) || scope.is_a?(Proc)
    scope_object = eval("self", scope)
    scope = scope_object.instance_eval{binding} if block_given?
  else
    scope_object = scope
    scope = scope_object.instance_eval{binding}
  end

  set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)

  scope_object.instance_eval do
    extend Haml::Helpers
    @haml_buffer = buffer
  end

  eval(precompiled, scope, @options[:filename], @options[:line])

  # Get rid of the current buffer
  scope_object.instance_eval do
    @haml_buffer = buffer.upper
  end

  buffer.buffer
end

#render_proc(scope = Object.new, *local_names) ⇒ Proc

Returns a proc that, when called, renders the template and returns the result as a string.

scope works the same as it does for render.

The first argument of the returned proc is a hash of local variable names to values. However, due to an unfortunate Ruby quirk, the local variables which can be assigned must be pre-declared. This is done with the local_names argument. For example:

# This works
Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
  #=> "<p>Hello!</p>"

# This doesn't
Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
  #=> NameError: undefined local variable or method `foo'

The proc doesn’t take a block; any yields in the template will fail.

Parameters:

  • scope (Binding, Proc, Object) (defaults to: Object.new)

    The context in which the template is evaluated

  • local_names (Array<Symbol>)

    The names of the locals that can be passed to the proc

Returns:

  • (Proc)

    The proc that will run the template



212
213
214
215
216
217
218
219
220
221
222
# File 'lib/haml/engine.rb', line 212

def render_proc(scope = Object.new, *local_names)
  if scope.is_a?(Binding) || scope.is_a?(Proc)
    scope_object = eval("self", scope)
  else
    scope_object = scope
    scope = scope_object.instance_eval{binding}
  end

  eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
       precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
end

#xhtml?Boolean

Returns Whether or not the format is XHTML.

Returns:

  • (Boolean)

    Whether or not the format is XHTML.



34
35
36
# File 'lib/haml/engine.rb', line 34

def xhtml?
  not html?
end