From 600b03d484d8ec48878adbdf0f9fc3451e03cd72 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Tue, 31 Mar 2015 02:54:50 +0900 Subject: [PATCH] Consider about runtime attribute nesting But accepting all attribute nesting will cause performance regression. So I decided to accept runtime nesting for only 'data'. Fixes #1. --- lib/hamlit/attribute.rb | 5 +++++ lib/hamlit/compilers/old_attribute.rb | 20 +++++++++++++++++++- spec/hamlit/engine/old_attributes_spec.rb | 9 +++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/hamlit/attribute.rb b/lib/hamlit/attribute.rb index 5fdf29ba..244420ce 100644 --- a/lib/hamlit/attribute.rb +++ b/lib/hamlit/attribute.rb @@ -22,6 +22,11 @@ module Hamlit def build(attributes) result = '' flatten_attributes(attributes).each do |key, value| + if value == true + result += " #{key}" + next + end + escaped = Temple::Utils.escape_html(value) result += " #{key}=#{@quote}#{escaped}#{@quote}" end diff --git a/lib/hamlit/compilers/old_attribute.rb b/lib/hamlit/compilers/old_attribute.rb index 950591b0..1dc17dcd 100644 --- a/lib/hamlit/compilers/old_attribute.rb +++ b/lib/hamlit/compilers/old_attribute.rb @@ -6,22 +6,32 @@ require 'hamlit/concerns/ripperable' # This module compiles only old-style attribute, which is # surrounded by brackets. module Hamlit + # This error is raised when hamlit copmiler decide to + # copmile the attributes on runtime. + class RuntimeBuild < StandardError; end + module Compilers module OldAttribute include Concerns::AttributeBuilder include Concerns::Balanceable include Concerns::Ripperable + # For performance, only data can be nested. + NESTABLE_ATTRIBUTES = %w[data].freeze IGNORED_EXPRESSIONS = %w[false nil].freeze def compile_old_attribute(str) - return runtime_build(str) unless Ripper.sexp(str) + raise RuntimeBuild unless Ripper.sexp(str) attrs = parse_old_attributes(str) format_attributes(attrs).map do |key, value| next true_attribute(key) if value == 'true' + assert_static_value!(value) if NESTABLE_ATTRIBUTES.include?(key) + [:html, :attr, key, [:dynamic, value]] end + rescue RuntimeBuild + return runtime_build(str) end private @@ -38,6 +48,14 @@ module Hamlit end end + # Give up static copmile when variables are detected. + def assert_static_value!(value) + tokens = Ripper.lex(value) + tokens.each do |(row, col), type, str| + raise RuntimeBuild if type == :on_ident + end + end + # Parse brace-balanced string and return the result as hash def parse_old_attributes(str) attributes = {} diff --git a/spec/hamlit/engine/old_attributes_spec.rb b/spec/hamlit/engine/old_attributes_spec.rb index 48e5e906..31e2f560 100644 --- a/spec/hamlit/engine/old_attributes_spec.rb +++ b/spec/hamlit/engine/old_attributes_spec.rb @@ -48,6 +48,15 @@ describe Hamlit::Engine do HTML end + it 'renders nested hash whose value is variable' do + assert_render(<<-'HAML', <<-HTML) + - hash = { disable: true } + %span{ data: hash } bar + HAML + bar + HTML + end + it 'renders false or nil attributes' do assert_render(<<-'HAML', <<-HTML) - hash = { checked: false }