# Class: Haml::Engine

Inherits:
  Object
  - Object
  - Haml::Engine
  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

- #indentation ⇒ String

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

- #options

  The Haml::Options instance.

## Instance Method Summary collapse

- #compiler

  Deprecated API for backword compatibility.

- #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.

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

  Precompiles the Haml template.

- #options_for_buffer
- #render(scope = Object.new, locals = {}, &block) ⇒ String (also: #to_html)

  Processes the template and returns the result as a string.

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

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

### 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:

- template (`String`) —

  The Haml template

- options (`{Symbol => Object}`) (defaults to: `{}`) —

  An options hash; see the Haml options documentation

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

### #indentation ⇒ `String`

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