1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 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
|
# frozen_string_literal: true
require 'erubi'
module Erubi
# An engine class that supports capturing blocks via the <tt><%=</tt> and <tt><%==</tt> tags:
#
# <%= upcase_form do %>
# <%= 'foo' %>
# <% end %>
#
# Where +upcase_form+ is defined like:
#
# def upcase_form(&block)
# "<form>#{@bufvar.capture(&block).upcase}</form>"
# end
#
# With output being:
#
# <form>
# FOO
# </form>
#
# This requires using a string subclass as the buffer value, provided by the
# CaptureBlockEngine::Buffer class.
#
# This engine does not support the :escapefunc option. To change the escaping function,
# use a subclass of CaptureBlockEngine::Buffer and override the #| method.
#
# This engine does not support the :chain_appends option, and ignores it if present.
class CaptureBlockEngine < Engine
class Buffer < ::String
# Convert argument to string when concatening
def <<(v)
concat(v.to_s)
end
# Escape argument using Erubi.h then then concatenate it to the receiver.
def |(v)
concat(h(v))
end
# Temporarily clear the receiver before yielding to the block, yield the
# given args to the block, return any data captured by the receiver, and
# restore the original data the receiver contained before returning.
def capture(*args)
prev = dup
replace("") # 1.8 support!
yield(*args)
dup
ensure
replace(prev)
end
private
if RUBY_VERSION >= '2'
define_method(:h, ::Erubi.instance_method(:h))
# :nocov:
else
def h(v)
::Erubi.h(v)
end
end
# :nocov:
end
def initialize(input, properties={})
properties = Hash[properties]
properties[:bufval] ||= '::Erubi::CaptureBlockEngine::Buffer.new'
properties[:chain_appends] = false
super
end
private
def add_expression_result(code)
add_expression_op(' <<= ', code)
end
def add_expression_result_escaped(code)
add_expression_op(' |= ', code)
end
def add_expression_op(op, code)
check = /\A\s*\z/.send(MATCH_METHOD, code) ? "''" : ''
with_buffer{@src << op << check << code}
end
end
end
|