diff --git a/lib/hamlit.rb b/lib/hamlit.rb index 29f6f0a4..441ab744 100644 --- a/lib/hamlit.rb +++ b/lib/hamlit.rb @@ -1,2 +1,3 @@ +require 'hamlit/attribute_builder' require 'hamlit/engine' require 'hamlit/version' diff --git a/lib/hamlit/attribute_builder.rb b/lib/hamlit/attribute_builder.rb new file mode 100644 index 00000000..cfc77a70 --- /dev/null +++ b/lib/hamlit/attribute_builder.rb @@ -0,0 +1,87 @@ +require 'temple/utils' + +module Hamlit + class AttributeBuilder + def self.build(quote, *args) + builder = self.new(quote) + builder.build(*args) + end + + def initialize(quote) + @quote = quote + end + + def build(*args) + result = '' + attributes = args.inject({}) do |attrs, arg| + merge_attributes(attrs, arg) + end + + attributes.each do |key, value| + if value == true + result += " #{key}" + next + end + + value = refine_joinable_value(key, value) if value.is_a?(Array) + escaped = Temple::Utils.escape_html(value) + result += " #{key}=#{@quote}#{escaped}#{@quote}" + end + result + end + + private + + def refine_joinable_value(key, value) + case key + when :id + value = value.join('_') + when :class + value = value.join(' ') + else + value + end + end + + def merge_attributes(base, target) + result = {} + base = flatten_attributes(base) + target = flatten_attributes(target) + + (base.keys | target.keys).each do |key| + result[key] = merge_attribute_value(base, target, key) + end + result + end + + def merge_attribute_value(base, target, key) + return target[key] unless base[key] + return base[key] unless target[key] + + values = [base[key], target[key]].flatten.compact + case key + when :id + values.join('_') + when :class + values.map(&:to_s).sort.uniq.join(' ') + end + end + + def flatten_attributes(attributes) + flattened = {} + + attributes.each do |key, value| + case value + when Hash + flatten_attributes(value).each do |k, v| + k = k.to_s.gsub(/_/, '-') + flattened["#{key}-#{k}"] = v if v + end + else + flattened[key] = value if value + end + end + flattened + end + end +end diff --git a/lib/hamlit/compiler.rb b/lib/hamlit/compiler.rb index 939c814c..8bb0e65a 100644 --- a/lib/hamlit/compiler.rb +++ b/lib/hamlit/compiler.rb @@ -36,6 +36,9 @@ module Hamlit def compile_tag(node) attrs = [:html, :attrs] + node.value[:attributes_hashes].each do |attribute_hash| + attrs << [:dynamic, "::Hamlit::AttributeBuilder.build(\"'\", #{attribute_hash})"] + end node.value[:attributes].each do |name, value| attrs << [:html, :attr, name, [:static, value]] end diff --git a/lib/hamlit/engine.rb b/lib/hamlit/engine.rb index 9e3795d5..7ef4c3fd 100644 --- a/lib/hamlit/engine.rb +++ b/lib/hamlit/engine.rb @@ -29,7 +29,21 @@ module Hamlit end def render(scope = Object.new, locals = {}, &block) - eval Engine.new.call(@template) + scope = wrap_binding(scope) + set_locals(locals, scope) + eval(Engine.new.call(@template), scope) + end + + private + + def wrap_binding(scope) + return scope if scope.is_a?(Binding) + scope.instance_eval { binding } + end + + def set_locals(locals, scope) + set_locals = locals.map { |k, v| "#{k} = #{v.inspect}" }.join("\n") + eval(set_locals, scope) end end end