Class: Haml::Engine

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Util
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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#balance, #check_encoding, #check_haml_encoding, #contains_interpolation?, #handle_interpolation, #html_safe, #human_indentation, #inspect_obj, #rails_xss_safe?, #silence_warnings, #unescape_interpolation

Constructor Details

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

Precompiles the Haml template.

Parameters:

Raises:

  • (Haml::Error)

    if there’s a Haml syntax error in the template

54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/haml/engine.rb', line 54

def initialize(template, options = {})
  # Reflect changes of `Haml::Options.defaults` to `Haml::TempleEngine` options, but `#initialize_encoding`
  # should be run against the arguemnt `options[:encoding]` for backward compatibility with old `Haml::Engine`.
  options = Options.defaults.dup.tap { |o| o.delete(:encoding) }.merge!(options)
  @options = Options.new(options)

  @template = check_haml_encoding(template) do |msg, line|
    raise Haml::Error.new(msg, line)
  end

  @temple_engine = TempleEngine.new(options)
  @temple_engine.compile(@template)
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)
39
40
41
# File 'lib/haml/engine.rb', line 39

def indentation
  @indentation
end

#options

The Haml::Options instance. See the Haml options documentation.

Returns:

  • Haml::Options

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

def options
  @options
end

Instance Method Details

#compiler

Deprecated API for backword compatibility

69
70
71
# File 'lib/haml/engine.rb', line 69

def compiler
  @temple_engine
end

#def_method(object, name, *local_names)

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 be 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

223
224
225
226
227
228
# File 'lib/haml/engine.rb', line 223

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

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

#options_for_buffer

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

def options_for_buffer
  @options.for_buffer
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, 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.respond_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 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, Object) (defaults to: Object.new)

    The context in which the template is evaluated

  • locals ({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

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

def render(scope = Object.new, locals = {}, &block)
  parent = scope.instance_variable_defined?(:@haml_buffer) ? scope.instance_variable_get(:@haml_buffer) : nil
  buffer = Haml::Buffer.new(parent, @options.for_buffer)

  if scope.is_a?(Binding)
    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.extend(Haml::Helpers)
  scope_object.instance_variable_set(:@haml_buffer, buffer)
  begin
    eval(@temple_engine.precompiled_with_return_value, scope, @options.filename, @options.line)
  rescue ::SyntaxError => e
    raise SyntaxError, e.message
  end
ensure
  # Get rid of the current buffer
  scope_object.instance_variable_set(:@haml_buffer, buffer.upper) if 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, 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

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/haml/engine.rb', line 164

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

  begin
    str = @temple_engine.precompiled_with_ambles(local_names)
    eval(
      "Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {}; #{str}}\n",
      scope,
      @options.filename,
      @options.line
    )
  rescue ::SyntaxError => e
    raise SyntaxError, e.message
  end
end