Hrb: not as good as I thought

This commit is contained in:
2019-06-18 20:17:37 -04:00
commit 517b911eea
26 changed files with 1152 additions and 0 deletions

18
lib/hrb.rb Normal file
View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
require "hrb/version"
require "hrb/template"
require "hrb/tilt" if defined?(Tilt)
require "hrb/action_view" if defined?(ActionView::Template)
module Hrb
module_function
def render(locals: {}, scope: nil, &block)
Hrb::Template.render(locals: locals, scope: scope, &block)
end
def render_file(path, locals: {}, scope: nil)
Hrb::Template.render_file(path, locals: locals, scope: scope)
end
end

17
lib/hrb/action_view.rb Normal file
View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
module Hrb
module Rails
class TemplateHandler
def call(template)
<<-CODE
Hrb::Template.build do
#{template.source}
end.to_s
CODE
end
end
end
end
ActionView::Template.register_template_handler :hrb, Hrb::Rails::TemplateHandler

131
lib/hrb/template.rb Normal file
View File

@@ -0,0 +1,131 @@
# frozen_string_literal: true
require "erb"
module Hrb
class Template
TAGS = %i[a address article aside b bdi body button code details dialog div dd dl dt em fieldset figcaption figure
footer form h1 h2 h3 h4 h5 h6 head header html i iframe label li main mark menuitem meter nav ol option
option p pre progress rp rt ruby s script section select small span strong summary table tbody td textarea
th thead time title tr u ul video wbr].freeze
EMPTY_TAGS = %i[img br hr input link meta source].freeze
ENDINGS = Hash[TAGS.map do |tag|
[tag, "</#{tag}>"]
end].freeze
def self.render(locals: {}, scope: nil, &block)
template = Template.new(locals: locals, scope: scope)
template.instance_eval(&block)
template.to_s
end
def self.render_file(path, locals: {}, scope: nil)
template = Template.new(locals: locals, scope: scope)
template.instance_eval(File.read(path))
template.to_s
end
def initialize(locals: {}, scope: nil)
@fragments = [[]]
self.locals = locals
@scope = scope
@view = @fragments.last
end
TAGS.each do |name|
define_method(name) do |content = nil, options = {}, &block|
tag(name, content, options, &block)
end
end
EMPTY_TAGS.each do |name|
define_method(name) do |options = {}|
tag(name, nil, options, end_tag: false)
end
end
def tag(name, content = nil, options = {}, end_tag: true, &block)
output = "<#{name}#{tag_attributes(content&.is_a?(Hash) ? content : options)}>"
output += content if content&.is_a?(String)
output += capture(&block) if block
output += ENDINGS[name] if end_tag
raw output
end
def method_missing(name, *args, &block)
if @scope.respond_to?(name)
@scope.send(name, *args, &block)
elsif @locals&.key?(name) || @locals&.key?(name.to_s)
@locals.fetch(name) { @locals[name.to_s] }
else
super
end
end
def respond_to_missing?(name, include_all = false)
@scope.respond_to?(name) || @locals&.key?(name) || @locals&.key?(name.to_s) || super
end
def view
@fragments.last
end
def doctype
raw "<!DOCTYPE html>"
end
def text(output)
raw escape(output)
end
def raw(output)
view.push output.to_s
end
def capture(&block)
@fragments.push []
instance_eval(&block)
view.join.tap do
@fragments.pop
end
end
def locals=(locals)
locals.each do |key, value|
metaclass do
define_method key do
value
end
end
end
end
def to_s
@fragments.join
end
private
def metaclass(&block)
metaclass = class << self; self; end
metaclass.class_eval(&block)
end
def tag_attributes(options)
attrs = ""
options.each do |key, value|
attrs += %( #{key.to_s.tr("_", "-")}="#{escape(value)}")
end
attrs
end
def escape(value)
ERB::Util.html_escape(value.respond_to?(:join) ? value.join(" ") : value.to_s)
end
end
end

21
lib/hrb/tilt.rb Normal file
View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Tilt
class HrbTemplate < Tilt::Template
def prepare; end
def evaluate(scope, locals, &block)
builder = Hrb::Template.new(locals: locals, scope: scope)
if block
builder.capture(&block)
else
builder.instance_eval(data)
end
builder.to_s
end
end
register Tilt::HrbTemplate, "rb"
end

5
lib/hrb/version.rb Normal file
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
module Hrb
VERSION = "1.0.0-alpha.1"
end