Add a way to make "static" methods for faster Haml::Buffer dispatch.
Rather than passing in a bunch of boolean variables at runtime, we compile the method once for each possible combination of variable values. It makes the code twisty and nasty, but Buffer needs all the speed it can get.
This commit is contained in:
parent
9b7dfe28af
commit
4f5a9b2861
|
@ -83,20 +83,21 @@ module Haml
|
|||
@real_tabs = 0
|
||||
end
|
||||
|
||||
# Renders +text+ with the proper tabulation. This also deals with
|
||||
# making a possible one-line tag one line or not.
|
||||
def push_text(text, dont_tab_up = false, tab_change = 0)
|
||||
if @tabulation > 0 && !@options[:ugly]
|
||||
# Have to push every line in by the extra user set tabulation.
|
||||
# Don't push lines with just whitespace, though,
|
||||
# because that screws up precompiled indentation.
|
||||
text.gsub!(/^(?!\s+$)/m, tabs)
|
||||
text.sub!(tabs, '') if dont_tab_up
|
||||
end
|
||||
Haml::Util.def_static_method(self, :push_text, [:text, :tab_change],
|
||||
:dont_tab_up, :ugly, <<RUBY)
|
||||
<% if !ugly %>
|
||||
if @tabulation > 0
|
||||
# Have to push every line in by the extra user set tabulation.
|
||||
# Don't push lines with just whitespace, though,
|
||||
# because that screws up precompiled indentation.
|
||||
text.gsub!(/^(?!\s+$)/m, tabs)
|
||||
<% if dont_tab_up %> text.sub!(tabs, '') <% end %>
|
||||
end
|
||||
<% end %>
|
||||
|
||||
@buffer << text
|
||||
@real_tabs += tab_change
|
||||
end
|
||||
RUBY
|
||||
|
||||
def adjust_tabs(tab_change)
|
||||
@real_tabs += tab_change
|
||||
|
|
|
@ -3,6 +3,8 @@ require 'haml/shared'
|
|||
|
||||
module Haml
|
||||
module Precompiler
|
||||
include Haml::Util
|
||||
|
||||
# Designates an XHTML/XML element.
|
||||
ELEMENT = ?%
|
||||
|
||||
|
@ -281,10 +283,8 @@ END
|
|||
end
|
||||
end
|
||||
|
||||
@precompiled << "_hamlout.push_text(#{unescape_interpolation(text)}"
|
||||
@precompiled << ", #{@dont_tab_up_next_text.inspect}" if @dont_tab_up_next_text || tab_change != 0
|
||||
@precompiled << ", #{tab_change}" if tab_change != 0
|
||||
@precompiled << ");"
|
||||
@precompiled << "_hamlout.#{static_method_name :push_text, @dont_tab_up_next_text, @options[:ugly]}"
|
||||
@precompiled << "(#{unescape_interpolation(text)}, #{tab_change});"
|
||||
@to_merge = []
|
||||
@dont_tab_up_next_text = false
|
||||
end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
require 'erb'
|
||||
require 'set'
|
||||
|
||||
module Haml
|
||||
module Util
|
||||
class << self; include Haml::Util; end
|
||||
|
@ -17,5 +20,43 @@ module Haml
|
|||
def map_hash(hash, &block)
|
||||
to_hash(hash.map(&block))
|
||||
end
|
||||
|
||||
def powerset(arr)
|
||||
arr.inject([Set.new].to_set) do |powerset, el|
|
||||
new_powerset = Set.new
|
||||
powerset.each do |subset|
|
||||
new_powerset << subset
|
||||
new_powerset << subset + [el]
|
||||
end
|
||||
new_powerset
|
||||
end
|
||||
end
|
||||
|
||||
class StaticConditionalContext
|
||||
def initialize(set)
|
||||
@set = set
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
super unless args.empty? && block.nil?
|
||||
@set.include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
def def_static_method(klass, name, args, *vars)
|
||||
erb = vars.pop
|
||||
powerset(vars).each do |set|
|
||||
context = StaticConditionalContext.new(set).instance_eval {binding}
|
||||
klass.class_eval(<<METHOD)
|
||||
def #{static_method_name(name, *vars.map {|v| set.include?(v)})}(#{args.join(', ')})
|
||||
#{ERB.new(erb).result(context)}
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
def static_method_name(name, *vars)
|
||||
"#{name}_#{vars.map {|v| !!v}.join('_')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue