Class: Rubyoshka::Renderer

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

Overview

A Renderer is a rendering of a Rubyoshka

Direct Known Subclasses

HTMLRenderer, XMLRenderer

Constant Summary collapse

S_TAG_METHOD_LINE =
__LINE__ + 1
S_TAG_METHOD =
<<~EOF
  S_TAG_%<TAG>s_PRE = '<%<tag>s'
  S_TAG_%<TAG>s_CLOSE = '</%<tag>s>'
  
  def %<tag>s(text = nil, **props, &block)
    @buffer << S_TAG_%<TAG>s_PRE
    emit_props(props) unless props.empty?
  
    if block
      @buffer << S_GT
      instance_eval(&block)
      @buffer << S_TAG_%<TAG>s_CLOSE
    elsif Rubyoshka === text
      @buffer << S_GT
      emit(text)
      @buffer << S_TAG_%<TAG>s_CLOSE
    elsif text
      @buffer << S_GT << escape_text(text.to_s) << S_TAG_%<TAG>s_CLOSE
    else
      @buffer << S_SLASH_GT
    end
  end
EOF
R_CONST_SYM =
/^[A-Z]/
S_LT =
'<'
S_GT =
'>'
S_LT_SLASH =
'</'
S_SPACE_LT_SLASH =
' </'
S_SLASH_GT =
'/>'
S_SPACE =
' '
S_EQUAL_QUOTE =
'="'
S_QUOTE =
'"'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, template) ⇒ void

Initializes attributes and renders the given block

Parameters:

  • context (Hash)

    rendering context

  • block (Proc)

    template block



14
15
16
17
18
# File 'lib/rubyoshka/renderer.rb', line 14

def initialize(context, template)
  @context = context
  @buffer = +''
  instance_eval(&template)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, **opts, &block) ⇒ void

This method returns an undefined value.

Catches undefined tag method call and handles them by defining the method

Parameters:

  • sym (Symbol)

    HTML tag or component identifier

  • args (Array)

    method call arguments

  • block (Proc)

    block passed to method call



66
67
68
69
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
# File 'lib/rubyoshka/renderer.rb', line 66

def method_missing(sym, *args, **opts, &block)
  value = @local && @local[sym]
  return value if value

  if sym =~ R_CONST_SYM
    # Component reference (capitalized method name)
    o = instance_eval(sym.to_s) rescue Rubyoshka.const_get(sym) \
        rescue Object.const_get(sym)
    case o
    when ::Proc
      self.class.define_method(sym) { |*a, **c, &b| emit(o.(*a, **c, &b)) }
      emit(o.(*args, **opts, &block))
    when Rubyoshka
      self.class.define_method(sym) do |**ctx|
        ctx.empty? ? emit(o) : with(**ctx) { emit(o) }
      end
      Hash === opts.empty? ? emit(o) : with(**opts) { emit(o) }
    when ::String
      @buffer << o
    else
      e = StandardError.new "Cannot render #{o.inspect}"
      e.set_backtrace(caller)
      raise e
    end
  else
    tag = sym.to_s
    code = S_TAG_METHOD % { tag: tag, TAG: tag.upcase }
    self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
    send(sym, *args, **opts, &block)
  end
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



8
9
10
# File 'lib/rubyoshka/renderer.rb', line 8

def context
  @context
end

Instance Method Details

#cache(*vary, **opts, &block) ⇒ void

This method returns an undefined value.

Caches the given block with the given arguments as cache key

Parameters:

  • vary (*Object)

    cache key

  • block (Proc)

    nested HTML block



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rubyoshka/renderer.rb', line 176

def cache(*vary, **opts, &block)
  key = [block.source_location.hash, vary.hash, opts.hash]

  if (cached = Rubyoshka.cache[key])
    @buffer << cached
    return
  end

  cache_pos = @buffer.length
  instance_eval(&block)
  diff = @buffer[cache_pos..-1]
  Rubyoshka.cache[key] = diff
end

#emit(o) ⇒ void Also known as: e

This method returns an undefined value.

Emits the given object into the rendering buffer

Parameters:

  • o (Proc, Rubyoshka, Module, String)

    emitted object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rubyoshka/renderer.rb', line 101

def emit(o)
  case o
  when ::Proc
    instance_eval(&o)
  when Rubyoshka
    instance_eval(&o.template)
  when Module
    # If module is given, the component is expected to be a const inside the module
    emit(o::Component)
  when nil
  else
    @buffer << o.to_s
  end
end

#emit_props(props) ⇒ void

This method returns an undefined value.

Emits tag attributes into the rendering buffer

Parameters:

  • props (Hash)

    tag attributes



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rubyoshka/renderer.rb', line 136

def emit_props(props)
  props.each { |k, v|
    case k
    when :src, :href
      @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE <<
        EscapeUtils.escape_uri(v) << S_QUOTE
    else
      case v
      when true
        @buffer << S_SPACE << k.to_s
      when false, nil
        # emit nothing
      else
        @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE << v << S_QUOTE
      end
    end
  }
end

#emit_yieldObject

Raises:

  • (LocalJumpError)


117
118
119
120
121
122
# File 'lib/rubyoshka/renderer.rb', line 117

def emit_yield
  block = @context[:__block__]
  raise LocalJumpError, "no block given (emit_yield)" unless block

  instance_eval(&block)
end

#escape_text(text) ⇒ Object

Raises:

  • (NotImplementedError)


26
27
28
# File 'lib/rubyoshka/renderer.rb', line 26

def escape_text(text)
  raise NotImplementedError
end

#escape_uri(uri) ⇒ Object



30
31
32
# File 'lib/rubyoshka/renderer.rb', line 30

def escape_uri(uri)
  EscapeUtils.escape_uri(v)
end

#text(data) ⇒ Object

Emits text into the rendering buffer

Parameters:

  • data (String)

    text



157
158
159
# File 'lib/rubyoshka/renderer.rb', line 157

def text(data)
  @buffer << escape_text(data)
end

#to_sString

Returns the result of the rendering

Returns:

  • (String)


22
23
24
# File 'lib/rubyoshka/renderer.rb', line 22

def to_s
  @buffer
end

#with(**ctx, &block) ⇒ void

This method returns an undefined value.

Sets a local context for the given block

Parameters:

  • ctx (Hash)

    context hash

  • block (Proc)

    nested HTML block



165
166
167
168
169
170
# File 'lib/rubyoshka/renderer.rb', line 165

def with(**ctx, &block)
  old_local, @local = @local, ctx
  instance_eval(&block)
ensure
  @local = old_local
end