问题
Does anyone know if it's possible to revert Sass's functionality, to prevent the "bug-fix"1 that was implemented to prevent @include recursion?
The message is:
Syntax error: An @include loop has been found: <mixin-name> includes itself
This was "fixed"1 in 3.0.5, and I'd prefer not to (read: I can't) downgrade that far. I unfortunately don't know enough Ruby to go sifting through the source, and while I'm making time to change that, it doesn't help me now.
So, is it possible2 to revert this functionality to that of pre-3.0.5 without having to downgrade; is there a re-patch floating around somewhere? I haven't been able to find one.
Edit: While I've answered this myself now, I'm still open to better answers; specifically, more portable solutions since now the Sass files will break anywhere else (anywhere that isn't pre-3.0.5)
1 Quotes used to indicate I don't think this is a fix. I think it is a break; I'll take that up with those responsible though.
2I know its possible, but I mean specifically for someone with no practical experience with Ruby. I'm learning Ruby!
回答1:
Okay, there's a cleaner way apply your hack: monkey-patching with Compass.
It will let you share your project safely and everybody else will be able to compile it without modifying their own SASS compilers.
1)
Create sass-visit-mixin-monkey-patch.rb next to compass.rb and apply your hack from there:
class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
# Runs a mixin.
def visit_mixin(node)
#include_loop = true
#handle_include_loop!(node) if @stack.any? {|e| e[:name] == node.name}
include_loop = false
@stack.push(:filename => node.filename, :line => node.line, :name => node.name)
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin = @environment.mixin(node.name)
if node.children.any? && !mixin.has_content
raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
end
args = node.args.map {|a| a.perform(@environment)}
keywords = Sass::Util.map_hash(node.keywords) {|k, v| [k, v.perform(@environment)]}
splat = node.splat.perform(@environment) if node.splat
self.class.perform_arguments(mixin, args, keywords, splat) do |env|
env.caller = Sass::Environment.new(@environment)
env.content = node.children if node.has_children
trace_node = Sass::Tree::TraceNode.from_node(node.name, node)
with_environment(env) {trace_node.children = mixin.tree.map {|c| visit(c)}.flatten}
trace_node
end
rescue Sass::SyntaxError => e
unless include_loop
e.modify_backtrace(:mixin => node.name, :line => node.line)
e.add_backtrace(:line => node.line)
end
raise e
ensure
@stack.pop unless include_loop
end
end
2)
Require the monkey patch from the config.rb:
# Enabling mixin recursion by applying a monkey patch to SASS compiler
require "./sass-visit-mixin-monkey-patch"
3)
Compile your project with compass compile.
回答2:
You know, I know enough Ruby to comment out a line or two ;)
At .\lib\sass\tree\visitors\perform.rb : 249 just comment:
# Runs a mixin.
def visit_mixin(node)
include_loop = true
handle_include_loop!(node) if @stack.any? {|e| e[:name] == node.name}
include_loop = false
Into:
# Runs a mixin.
def visit_mixin(node)
# include_loop = true
# handle_include_loop!(node) if @stack.any? {|e| e[:name] == node.name}
include_loop = false
Suddenly, rainbows of glorious recursion.
来源:https://stackoverflow.com/questions/15531004/sass-mixin-recursion-include-loop