Class: PatternPatch::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/pattern_patch/renderer.rb

Overview

Provides a fairly clean binding for resolving locals in Ruby < 2.5. All locals become method calls in the binding passed to ERB. A separate class (instead of a Module, e.g.) means minimal clutter in the set of methods available to the binding.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text, safe_level = nil, trim_mode = nil) ⇒ Renderer



18
19
20
21
22
23
24
25
# File 'lib/pattern_patch/renderer.rb', line 18

def initialize(text, safe_level = nil, trim_mode = nil)
  if self.class.is_ruby3?
    @template = ERB.new text, trim_mode: trim_mode
  else
    @template = ERB.new text, safe_level, trim_mode
  end
  @locals = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *args, &block) ⇒ Object



56
57
58
59
60
# File 'lib/pattern_patch/renderer.rb', line 56

def method_missing(method_sym, *args, &block)
  return super unless @locals.key?(method_sym)

  @locals[method_sym]
end

Class Method Details

.is_ruby3?Boolean



11
12
13
14
15
# File 'lib/pattern_patch/renderer.rb', line 11

def is_ruby3?
  version = Gem::Version.new RUBY_VERSION
  requirement = Gem::Requirement.new '>= 3'
  requirement =~ version
end

Instance Method Details

#render(locals_or_binding = {}) ⇒ Object

Render an ERB template with a binding or locals.

renderer = Renderer.new template_text
result = renderer.render binding
result = renderer.render a: 'foo', b: 1

Raises:

  • ArgumentError for invalid locals



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/pattern_patch/renderer.rb', line 34

def render(locals_or_binding = {})
  # Pass a Binding this way.
  return @template.result(locals_or_binding) unless locals_or_binding.kind_of?(Hash)

  @locals = locals_or_binding.symbolize_keys
  # Any local that corresponds to a method name in this class is invalid
  # because it cannot trigger method_missing. The same goes for
  # locals_or_binding, the only local variable.
  # Avoid new methods and local variables, which will be visible in the binding.
  # Could validate only for Ruby < 2.5, but better to be consistent.
  if @locals.any? { |l| respond_to?(l) || l == :locals_or_binding }
    raise ArgumentError, "Invalid locals: #{@locals.select { |l| respond_to?(l) || l == :locals_or_binding }.map(&:to_str).join ', '}"
  end

  if @template.respond_to? :result_with_hash
    # ERB#result_with_hash requires Ruby 2.5.
    @template.result_with_hash locals_or_binding
  else
    @template.result binding
  end
end