Class: Papercraft::Renderer

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

Overview

A Renderer renders a Papercraft template into a string

Direct Known Subclasses

HTMLRenderer, JSONRenderer, XMLRenderer

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(render_fragment = nil, &template) ⇒ Renderer

Initializes the renderer and evaulates the given template in the renderer’s scope.

Parameters:

  • &template (Proc)

    template block



87
88
89
90
# File 'lib/papercraft/renderer.rb', line 87

def initialize(render_fragment = nil, &template)
  @render_fragment = render_fragment
  instance_eval(&template)
end

Class Method Details

.extension(map) ⇒ void

This method returns an undefined value.

call_seq:

Papercraft::Renderer.extension(name => mod, ...)
Papercraft.extension(name => mod, ...)

Installs the given extensions, passed in the form of a Ruby hash mapping methods to extension modules. The methods will be available to all Papercraft templates. Extension methods are executed in the context of the the renderer instance, so they can look just like normal proc components. In cases where method names in the module clash with XML tag names, you can use the ‘#tag` method to emit the relevant tag.

module ComponentLibrary
  def card(title, content)
    div(class: 'card') {
      h3 title
      div(class: 'card-content') { emit_markdown content }
    }
  end
end

Papercraft.extension(components: ComponentLibrary)
Papercraft.html { components.card('Foo', '**Bar**') }

Parameters:

  • map (Hash)

    hash mapping methods to extension modules



64
65
66
67
68
# File 'lib/papercraft/renderer.rb', line 64

def extension(map)
  map.each do |sym, mod|
    define_extension_method(sym, mod)
  end
end

.verify_proc_parameters(template, args, named_args) ⇒ Object

Verifies that the given template proc can be called with the given arguments and named arguments. If the proc demands named argument keys that do not exist in ‘named_args`, `Papercraft::Error` is raised.

Parameters:

  • template (Proc)

    proc to verify

  • args (Array<any>)

    arguments passed to proc

  • named_args (Hash)

    named arguments passed to proc



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/papercraft/renderer.rb', line 22

def verify_proc_parameters(template, args, named_args)
  param_count = 0
  template.parameters.each do |(type, name)|
    case type
    when :req
      param_count += 1
    when :keyreq
      if !named_args.has_key?(name)
        raise Papercraft::Error, "Missing template parameter #{name.inspect}"
      end
    end
  end
  if param_count > args.size
    raise Papercraft::Error, "Missing template parameters"
  end
end

Instance Method Details

#emit(o, *a, **b, &block) ⇒ void Also known as: e

This method returns an undefined value.

Emits the given object into the rendering buffer. If the given object is a proc or a component, ‘emit` will passes any additional arguments and named arguments to the object when rendering it. If the given object is nil, nothing is emitted. Otherwise, the object is converted into a string using `#to_s` which is then added to the rendering buffer, without any escaping.

greeter = proc { |name| h1 "Hello, #{name}!" }
Papercraft.html { emit(greeter, 'world') }.render #=> "<h1>Hello, world!</h1>"

Papercraft.html { emit 'hi&<bye>' }.render #=> "hi&<bye>"

Papercraft.html { emit nil }.render #=> ""

Parameters:

  • o (Proc, Papercraft::Template, String)

    emitted object

  • *a (Array<any>)

    arguments to pass to a proc

  • **b (Hash)

    named arguments to pass to a proc



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/papercraft/renderer.rb', line 109

def emit(o, *a, **b, &block)
  case o
  when ::Proc
    Renderer.verify_proc_parameters(o, a, b)
    push_emit_yield_block(block) if block
    instance_exec(*a, **b, &o)
  when nil
    # do nothing
  else
    emit_object(o)
  end
end

#emit_yield(*a, **b) ⇒ void

This method returns an undefined value.

Emits a block supplied using Template#apply or Template#render.

div_wrap = Papercraft.html { |*args| div { emit_yield(*args) } }
greeter = div_wrap.apply { |name| h1 "Hello, #{name}!" }
greeter.render('world') #=> "<div><h1>Hello, world!</h1></div>"

Parameters:

  • *a (Array<any>)

    arguments to pass to a proc

  • **b (Hash)

    named arguments to pass to a proc

Raises:



132
133
134
135
136
137
# File 'lib/papercraft/renderer.rb', line 132

def emit_yield(*a, **b)
  block = @emit_yield_stack&.pop
  raise Papercraft::Error, "No block given" unless block

  instance_exec(*a, **b, &block)
end

#fragment(name, &block) ⇒ void

This method returns an undefined value.

Defines a named template fragment. Template fragments allow rendering specific parts of the same template. A template fragment can be rendered using Template#render_fragment. See also / HTMX template fragments.

form = Papercraft.html {
  h1 'Hello'
  fragment(:buttons) {
    button 'OK'
    button 'Cancel'
  }
}
form.render_fragment(:buttons) #=> "<button>OK</button><button>Cancel</buttons>"

Parameters:

  • name (Symbol, String)

    fragment name

Raises:



155
156
157
158
159
160
161
162
163
164
# File 'lib/papercraft/renderer.rb', line 155

def fragment(name, &block)
  raise Papercraft::Error, "Already in fragment" if @fragment

  begin
    @fragment = name
    emit(block)
  ensure
    @fragment = nil
  end
end