From 7dc2360c8b98dc985f7c60842a0af2e206388d0c Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 4 Apr 2010 14:21:24 -0700 Subject: [PATCH 01/54] [Haml] Silence regexp match warnings. Closes gh-103 --- doc-src/HAML_CHANGELOG.md | 2 ++ lib/haml/helpers.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc-src/HAML_CHANGELOG.md b/doc-src/HAML_CHANGELOG.md index ba2f26aa..09f66ff0 100644 --- a/doc-src/HAML_CHANGELOG.md +++ b/doc-src/HAML_CHANGELOG.md @@ -10,6 +10,8 @@ * Don't remove `\n` in filters with interpolation. +* Silence those annoying `"regexp match /.../n against to UTF-8 string"` warnings. + ## 2.2.22 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.22). diff --git a/lib/haml/helpers.rb b/lib/haml/helpers.rb index 614b927a..c37c321d 100644 --- a/lib/haml/helpers.rb +++ b/lib/haml/helpers.rb @@ -502,7 +502,7 @@ END # @param text [String] The string to sanitize # @return [String] The sanitized string def html_escape(text) - text.to_s.gsub(/[\"><&]/n) {|s| HTML_ESCAPE[s]} + Haml::Util.silence_warnings {text.to_s.gsub(/[\"><&]/n) {|s| HTML_ESCAPE[s]}} end # Escapes HTML entities in `text`, but without escaping an ampersand From 84e7f54ffba0a81aaa3de30d30ad5bf5122835a1 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Mon, 5 Apr 2010 20:03:02 +0200 Subject: [PATCH 02/54] [Sass] Speed up Sass in development mode by caching template dependencies computation. --- lib/sass/plugin.rb | 79 ++++++++++++++++++++++++++-------------- test/sass/plugin_test.rb | 16 ++++---- 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 45eac715..45b52281 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -29,6 +29,49 @@ module Sass # #=> Compiling app/sass/print.scss to public/stylesheets/print.css # #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css module Plugin + class StalenessChecker + attr_reader :engine_options + + def initialize(engine_options) + @engine_options, @dependencies = engine_options, {} + end + + def stylesheet_needs_update?(css_file, template_file) + return true unless File.exists?(css_file) && File.exists?(template_file) + + css_mtime = File.mtime(css_file) + File.mtime(template_file) > css_mtime || + dependencies(template_file).any?(&dependency_updated?(css_mtime)) + end + + private + + def dependencies(filename) + @dependencies[filename] ||= compute_dependencies(filename) + end + + def dependency_updated?(css_mtime) + lambda do |dep| + begin + File.mtime(dep) > css_mtime || + dependencies(dep).any?(&dependency_updated?(css_mtime)) + rescue Sass::SyntaxError + # If there's an error finding depenencies, default to recompiling. + true + end + end + end + + def compute_dependencies(filename) + Files.tree_for(filename, engine_options).select {|n| n.is_a?(Tree::ImportNode)}.map do |n| + next if n.full_filename =~ /\.css$/ + n.full_filename + end.compact + rescue Sass::SyntaxError => e + [] # If the file has an error, we assume it has no dependencies + end + end + include Haml::Util include Sass::Callbacks extend self @@ -211,6 +254,8 @@ module Sass individual_files.each {|t, c| update_stylesheet(t, c)} @checked_for_updates = true + staleness_checker = make_staleness_checker + template_locations.zip(css_locations).each do |template_location, css_location| Dir.glob(File.join(template_location, "**", "*.s[ca]ss")).each do |file| @@ -219,7 +264,7 @@ module Sass css = css_filename(name, css_location) next if forbid_update?(name) - if options[:always_update] || stylesheet_needs_update?(css, file) + if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file) update_stylesheet file, css else run_not_updating_stylesheet file, css @@ -374,33 +419,13 @@ module Sass name.sub(/^.*\//, '')[0] == ?_ end + def make_staleness_checker + StalenessChecker.new(engine_options) + end + + # Compass expects this to exist def stylesheet_needs_update?(css_file, template_file) - return true unless File.exists?(css_file) && File.exists?(template_file) - - css_mtime = File.mtime(css_file) - File.mtime(template_file) > css_mtime || - dependencies(template_file).any?(&dependency_updated?(css_mtime)) - end - - def dependency_updated?(css_mtime) - lambda do |dep| - begin - File.mtime(dep) > css_mtime || - dependencies(dep).any?(&dependency_updated?(css_mtime)) - rescue Sass::SyntaxError - # If there's an error finding depenencies, default to recompiling. - true - end - end - end - - def dependencies(filename) - Files.tree_for(filename, engine_options).select {|n| n.is_a?(Tree::ImportNode)}.map do |n| - next if n.full_filename =~ /\.css$/ - n.full_filename - end.compact - rescue Sass::SyntaxError => e - [] # If the file has an error, we assume it has no dependencies + make_staleness_checker.stylesheet_needs_update?(css_file, template_file) end end end diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index d9425462..ac6a6191 100755 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -341,12 +341,14 @@ CSS end def assert_needs_update(name) - assert(Sass::Plugin.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), + checker = make_staleness_checker + assert(checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} to need an update.") end def assert_doesnt_need_update(name) - assert(!Sass::Plugin.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), + checker = make_staleness_checker + assert(!checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} not to need an update.") end @@ -389,6 +391,10 @@ CSS "#{File.dirname(__FILE__)}/#{file}" end + def make_staleness_checker + Sass::Plugin.send(:make_staleness_checker) + end + def set_plugin_opts(overrides = {}) Sass::Plugin.options = { :template_location => template_loc, @@ -401,12 +407,6 @@ CSS end end -module Sass::Plugin - class << self - public :stylesheet_needs_update? - end -end - class Sass::Engine alias_method :old_render, :render From e6b2111b5b0e632fcb16cbde1498a752968caec0 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Mon, 5 Apr 2010 20:08:20 +0200 Subject: [PATCH 03/54] [Sass] Cache mtimes in StalenessChecker. --- lib/sass/plugin.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 45b52281..49afc2c7 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -33,19 +33,23 @@ module Sass attr_reader :engine_options def initialize(engine_options) - @engine_options, @dependencies = engine_options, {} + @engine_options, @dependencies, @mtimes = engine_options, {}, {} end def stylesheet_needs_update?(css_file, template_file) return true unless File.exists?(css_file) && File.exists?(template_file) - css_mtime = File.mtime(css_file) - File.mtime(template_file) > css_mtime || + css_mtime = mtime(css_file) + mtime(template_file) > css_mtime || dependencies(template_file).any?(&dependency_updated?(css_mtime)) end private + def mtime(filename) + @mtimes[filename] ||= File.mtime(filename) + end + def dependencies(filename) @dependencies[filename] ||= compute_dependencies(filename) end @@ -53,7 +57,7 @@ module Sass def dependency_updated?(css_mtime) lambda do |dep| begin - File.mtime(dep) > css_mtime || + mtime(dep) > css_mtime || dependencies(dep).any?(&dependency_updated?(css_mtime)) rescue Sass::SyntaxError # If there's an error finding depenencies, default to recompiling. From 81be6d312fa7dca275f0f7c80be405b5b0974c91 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Mon, 5 Apr 2010 20:19:47 +0200 Subject: [PATCH 04/54] [Sass] Cache dependencies staleness checks. --- lib/sass/plugin.rb | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 49afc2c7..ae477f09 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -33,19 +33,34 @@ module Sass attr_reader :engine_options def initialize(engine_options) - @engine_options, @dependencies, @mtimes = engine_options, {}, {} + @engine_options, @dependencies, @mtimes, @dependencies_stale = engine_options, {}, {}, {} end def stylesheet_needs_update?(css_file, template_file) return true unless File.exists?(css_file) && File.exists?(template_file) css_mtime = mtime(css_file) - mtime(template_file) > css_mtime || - dependencies(template_file).any?(&dependency_updated?(css_mtime)) + mtime(template_file) > css_mtime || dependencies_stale?(template_file, css_mtime) end private + def dependencies_stale?(template_file, css_mtime) + timestamps = @dependencies_stale[template_file] ||= {} + timestamps.each_pair do |checked_css_mtime, is_stale| + if checked_css_mtime <= css_mtime && !is_stale + return false + elsif checked_css_mtime > css_mtime && is_stale + return true + end + end + timestamps[css_mtime] = run_stale_dependencies_check(template_file, css_mtime) + end + + def run_stale_dependencies_check(template_file, css_mtime) + dependencies(template_file).any?(&dependency_updated?(css_mtime)) + end + def mtime(filename) @mtimes[filename] ||= File.mtime(filename) end @@ -57,8 +72,7 @@ module Sass def dependency_updated?(css_mtime) lambda do |dep| begin - mtime(dep) > css_mtime || - dependencies(dep).any?(&dependency_updated?(css_mtime)) + mtime(dep) > css_mtime || dependencies_stale?(dep, css_mtime) rescue Sass::SyntaxError # If there's an error finding depenencies, default to recompiling. true From 821dd9622f75c7051792fd70a831216b2b0ded05 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Mon, 5 Apr 2010 20:24:30 +0200 Subject: [PATCH 05/54] [Sass] Use grep instead of select & map combo. --- lib/sass/plugin.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index ae477f09..e7155ea2 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -81,9 +81,8 @@ module Sass end def compute_dependencies(filename) - Files.tree_for(filename, engine_options).select {|n| n.is_a?(Tree::ImportNode)}.map do |n| - next if n.full_filename =~ /\.css$/ - n.full_filename + Files.tree_for(filename, engine_options).grep(Tree::ImportNode) do |n| + n.full_filename unless n.full_filename =~ /\.css$/ end.compact rescue Sass::SyntaxError => e [] # If the file has an error, we assume it has no dependencies From 138ddb4eb77bb0a39cc19e9572f5bb4a289170f4 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Mon, 5 Apr 2010 20:29:15 +0200 Subject: [PATCH 06/54] [Sass] Expand stylesheet paths to avoid doing any work twice. --- lib/sass/plugin.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index e7155ea2..2555abe5 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -37,6 +37,8 @@ module Sass end def stylesheet_needs_update?(css_file, template_file) + template_file = File.expand_path(template_file) + return true unless File.exists?(css_file) && File.exists?(template_file) css_mtime = mtime(css_file) @@ -82,7 +84,7 @@ module Sass def compute_dependencies(filename) Files.tree_for(filename, engine_options).grep(Tree::ImportNode) do |n| - n.full_filename unless n.full_filename =~ /\.css$/ + File.expand_path(n.full_filename) unless n.full_filename =~ /\.css$/ end.compact rescue Sass::SyntaxError => e [] # If the file has an error, we assume it has no dependencies From cd805682547aad704b4e1e053cde3393bfc9d555 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Fri, 9 Apr 2010 23:06:01 +0200 Subject: [PATCH 07/54] [Sass] Add cross-request persistent dependencies cache to StalenessChecker. --- lib/sass/plugin.rb | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 2555abe5..4743497d 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -33,16 +33,20 @@ module Sass attr_reader :engine_options def initialize(engine_options) - @engine_options, @dependencies, @mtimes, @dependencies_stale = engine_options, {}, {}, {} + @engine_options, @mtimes, @dependencies_stale = engine_options, {}, {} + @dependencies = Thread.current[:_sass_file_dependencies] ||= {} end def stylesheet_needs_update?(css_file, template_file) template_file = File.expand_path(template_file) - return true unless File.exists?(css_file) && File.exists?(template_file) - - css_mtime = mtime(css_file) - mtime(template_file) > css_mtime || dependencies_stale?(template_file, css_mtime) + unless File.exists?(css_file) && File.exists?(template_file) + @dependencies.delete(template_file) + true + else + css_mtime = mtime(css_file) + mtime(template_file) > css_mtime || dependencies_stale?(template_file, css_mtime) + end end private @@ -68,7 +72,13 @@ module Sass end def dependencies(filename) - @dependencies[filename] ||= compute_dependencies(filename) + stored_mtime, dependencies = @dependencies[filename] + + if !stored_mtime || stored_mtime < mtime(filename) + @dependencies[filename] = [mtime(filename), dependencies = compute_dependencies(filename)] + end + + dependencies end def dependency_updated?(css_mtime) From 708838a2bdb828ea02aebfbd1ce75c311e5795df Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 11:23:28 -0700 Subject: [PATCH 08/54] [Sass] Debug node needed to pass options to the debug expression when converting back to source. --- lib/sass/tree/debug_node.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sass/tree/debug_node.rb b/lib/sass/tree/debug_node.rb index 3804e132..158245d0 100644 --- a/lib/sass/tree/debug_node.rb +++ b/lib/sass/tree/debug_node.rb @@ -13,7 +13,7 @@ module Sass protected def to_src(tabs, opts, fmt) - "#{' ' * tabs}@debug #{@expr.to_sass}#{semi fmt}\n" + "#{' ' * tabs}@debug #{@expr.to_sass(opts)}#{semi fmt}\n" end # Prints the expression to STDERR. From 8e787b51b6ec1c562757fb470b937e602e89e17c Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 11:51:43 -0700 Subject: [PATCH 09/54] [Sass] Keep track of the runtime stack so it can be inspected without unwinding. --- lib/sass/environment.rb | 46 +++++++++++++++++++++++++++++++++++- lib/sass/tree/import_node.rb | 3 +++ lib/sass/tree/mixin_node.rb | 37 ++++++++++++++++------------- 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/lib/sass/environment.rb b/lib/sass/environment.rb index 4f0c577c..e79a4389 100644 --- a/lib/sass/environment.rb +++ b/lib/sass/environment.rb @@ -23,7 +23,8 @@ module Sass @vars = {} @mixins = {} @parent = parent - + @stack = [] + @ignore_parent_stack = false set_var("important", Script::String.new("!important")) unless @parent end @@ -35,6 +36,49 @@ module Sass @options || (parent && parent.options) || {} end + # Push lexical frame information onto the runtime stack. + # @param frame_info [{Symbol => Object}] + # Frame information has the following keys: + # + # `:filename` + # : The name of the file in which the lexical scope changed. + # + # `:mixin` + # : The name of the mixin in which the lexical scope changed, + # or `nil` if it wasn't within in a mixin. + # + # `:line` + # : The line of the file on which the lexical scope changed. Never nil. + # + # `:import` + # : Set to `true` when the lexical scope is changing due to an import. + def push(frame_info) + @stack.push frame_info + end + + # Pop runtime frame information from the stack. + def pop + @stack.pop + end + + # A list of the runtime stack frame information + # The last element in the list was pushed onto the stack most recently. + def stack + prev = (!@ignore_parent_stack && parent && parent.stack) || [] + prev + @stack + end + + # Temporarily assume the runtime stack that is passed in. + # @param stk A stack value from another environment. + def with_stack(stk) + @stack, old_stack = stk, @stack + @ignore_parent_stack = true + yield self + ensure + @ignore_parent_stack = false + @stack = old_stack + end + class << self private diff --git a/lib/sass/tree/import_node.rb b/lib/sass/tree/import_node.rb index 6378c713..0c4f2009 100644 --- a/lib/sass/tree/import_node.rb +++ b/lib/sass/tree/import_node.rb @@ -62,6 +62,7 @@ module Sass # @param environment [Sass::Environment] The lexical environment containing # variable and mixin values def perform!(environment) + environment.push(:filename => @filename, :line => @line, :import => true) root = Sass::Files.tree_for(full_filename, @options) @template = root.template self.children = root.children @@ -70,6 +71,8 @@ module Sass e.modify_backtrace(:filename => full_filename) e.add_backtrace(:filename => @filename, :line => @line) raise e + ensure + environment.pop end private diff --git a/lib/sass/tree/mixin_node.rb b/lib/sass/tree/mixin_node.rb index 8b3f4701..e2882ec2 100644 --- a/lib/sass/tree/mixin_node.rb +++ b/lib/sass/tree/mixin_node.rb @@ -50,6 +50,8 @@ module Sass::Tree # @raise [Sass::SyntaxError] if an incorrect number of arguments was passed # @see Sass::Tree def perform!(environment) + original_env = environment + original_env.push(:filename => filename, :mixin => @name, :line => line) raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.") unless mixin = environment.mixin(@name) raise Sass::SyntaxError.new(< e e.modify_backtrace(:mixin => @name, :line => @line) e.add_backtrace(:line => @line) raise e + ensure + original_env.pop end end end From 1723e10292a85b13ab0d8d527f50945bd08ddeea Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 11:52:52 -0700 Subject: [PATCH 10/54] [Sass] Add the @warn directive for emiting warnings that also provide a stylesheet trace. --- lib/sass/engine.rb | 7 ++++++ lib/sass/scss/parser.rb | 6 ++++- lib/sass/tree/warn_node.rb | 46 +++++++++++++++++++++++++++++++++++++ test/sass/engine_test.rb | 27 ++++++++++++++++++++++ test/sass/scss/scss_test.rb | 20 ++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 lib/sass/tree/warn_node.rb diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 5403ca77..4c9bbbc4 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -13,6 +13,7 @@ require 'sass/tree/if_node' require 'sass/tree/while_node' require 'sass/tree/for_node' require 'sass/tree/debug_node' +require 'sass/tree/warn_node' require 'sass/tree/import_node' require 'sass/environment' require 'sass/script' @@ -488,6 +489,12 @@ WARNING :line => @line + 1) unless line.children.empty? offset = line.offset + line.text.index(value).to_i Tree::DebugNode.new(parse_script(value, :offset => offset)) + elsif directive == "warn" + raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value + raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.", + :line => @line + 1) unless line.children.empty? + offset = line.offset + line.text.index(value).to_i + Tree::WarnNode.new(parse_script(value, :offset => offset)) else Tree::DirectiveNode.new(line.text) end diff --git a/lib/sass/scss/parser.rb b/lib/sass/scss/parser.rb index a7508cf5..d590abba 100644 --- a/lib/sass/scss/parser.rb +++ b/lib/sass/scss/parser.rb @@ -77,7 +77,7 @@ module Sass node << comment end - DIRECTIVES = Set[:mixin, :include, :debug, :for, :while, :if, :import, :media] + DIRECTIVES = Set[:mixin, :include, :debug, :warn, :for, :while, :if, :import, :media] def directive return unless tok(/@/) @@ -127,6 +127,10 @@ module Sass node(Sass::Tree::DebugNode.new(sass_script(:parse))) end + def warn + node(Sass::Tree::WarnNode.new(sass_script(:parse))) + end + def for tok!(/\$/) var = tok! IDENT diff --git a/lib/sass/tree/warn_node.rb b/lib/sass/tree/warn_node.rb new file mode 100644 index 00000000..1cd122c8 --- /dev/null +++ b/lib/sass/tree/warn_node.rb @@ -0,0 +1,46 @@ +module Sass + module Tree + # A dynamic node representing a Sass `@warn` statement. + # + # @see Sass::Tree + class WarnNode < Node + # @param expr [Script::Node] The expression to print + def initialize(expr) + @expr = expr + super() + end + + protected + + def to_src(tabs, opts, fmt) + "#{' ' * tabs}@warn #{@expr.to_sass(opts)}#{semi fmt}\n" + end + + # Prints the expression to STDERR with a stylesheet trace. + # + # @param environment [Sass::Environment] The lexical environment containing + # variable and mixin values + def _perform(environment) + environment.push(:filename => filename, :line => line) + res = @expr.perform(environment) + res = res.value if res.is_a?(Sass::Script::String) + Haml::Util.haml_warn "WARNING: #{res}" + Haml::Util.enum_with_index(environment.stack.reverse).each do |entry, i| + where = " " + if entry[:mixin] + where << "via '#{entry[:mixin]}' mixed in at line #{entry[:line]}" + elsif entry[:import] + where << "imported from line #{entry[:line]}" + else + where << "#{"issued" if i == 0} from line #{entry[:line]}" + end + where << " of #{entry[:filename] || "(sass)"}" + Haml::Util.haml_warn where + end + [] + ensure + environment.pop + end + end + end +end diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index 9f472379..e8b35fed 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -107,6 +107,9 @@ MSG '@if' => "Invalid if directive '@if': expected expression.", '@while' => "Invalid while directive '@while': expected expression.", '@debug' => "Invalid debug directive '@debug': expected expression.", + %Q{@debug "a message"\n "nested message"} => "Illegal nesting: Nothing may be nested beneath debug directives.", + '@warn' => "Invalid warn directive '@warn': expected expression.", + %Q{@warn "a message"\n "nested message"} => "Illegal nesting: Nothing may be nested beneath warn directives.", "/* foo\n bar\n baz" => "Inconsistent indentation: previous line was indented by 4 spaces, but this line was indented by 2 spaces.", # Regression tests @@ -1709,6 +1712,30 @@ SASS end end + def test_warn_directive + expected_warning = < Date: Sat, 10 Apr 2010 16:29:56 -0700 Subject: [PATCH 11/54] [Sass] Support for disabling warnings. --- lib/haml/exec.rb | 3 +++ lib/haml/util.rb | 8 ++++++++ lib/sass/engine.rb | 4 +++- lib/sass/plugin/merb.rb | 1 + lib/sass/plugin/rails.rb | 1 + test/sass/engine_test.rb | 9 +++++++++ 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/haml/exec.rb b/lib/haml/exec.rb index 3d03dba8..ef66cedc 100644 --- a/lib/haml/exec.rb +++ b/lib/haml/exec.rb @@ -276,6 +276,9 @@ END 'Output style. Can be nested (default), compact, compressed, or expanded.') do |name| @options[:for_engine][:style] = name.to_sym end + opts.on('-q', '--quiet', 'Silence warnings during compilation.') do + @options[:for_engine][:quiet] = true + end opts.on('-g', '--debug-info', 'Emit extra information in the generated CSS that can be used by the FireSass Firebug plugin.') do @options[:for_engine][:debug_info] = true diff --git a/lib/haml/util.rb b/lib/haml/util.rb index 66c09a58..3d8cc96f 100644 --- a/lib/haml/util.rb +++ b/lib/haml/util.rb @@ -180,6 +180,14 @@ module Haml @@silence_warnings = old_silence_warnings end + def with_warnings(state) + old_silence_warnings = @@silence_warnings + @@silence_warnings = !state + yield + ensure + @@silence_warnings = old_silence_warnings + end + # The same as `Kernel#warn`, but is silenced by \{#silence\_haml\_warnings}. # # @param msg [String] diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 4c9bbbc4..879dfdae 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -165,7 +165,9 @@ module Sass # @return [String] The CSS # @raise [Sass::SyntaxError] if there's an error in the document def render - to_tree.render + Haml::Util.with_warnings(!@options[:quiet]) do + to_tree.render + end end alias_method :to_css, :render diff --git a/lib/sass/plugin/merb.rb b/lib/sass/plugin/merb.rb index fb931f37..187fcf8c 100644 --- a/lib/sass/plugin/merb.rb +++ b/lib/sass/plugin/merb.rb @@ -14,6 +14,7 @@ unless defined?(Sass::MERB_LOADED) :css_location => root + '/public/stylesheets', :cache_location => root + '/tmp/sass-cache', :always_check => env != "production", + :quiet => env != "production", :full_exception => env != "production") config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {} diff --git a/lib/sass/plugin/rails.rb b/lib/sass/plugin/rails.rb index 2f03a00c..272270ab 100644 --- a/lib/sass/plugin/rails.rb +++ b/lib/sass/plugin/rails.rb @@ -5,6 +5,7 @@ unless defined?(Sass::RAILS_LOADED) :css_location => Haml::Util.rails_root + '/public/stylesheets', :cache_location => Haml::Util.rails_root + '/tmp/sass-cache', :always_check => Haml::Util.rails_env != "production", + :quiet => Haml::Util.rails_env != "production", :full_exception => Haml::Util.rails_env != "production") if defined?(Rails.configuration) && defined?(Rails.configuration.middleware) diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index e8b35fed..ba84c371 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -1736,6 +1736,15 @@ SASS end end + def test_warn_directive_when_quiet + assert_warning "" do + assert_equal < true) +CSS +@warn "this is a warning" +SASS + end + end + # Regression tests def test_parens_in_mixins From c3c7b8c7a32ad8eb8075870a370a3084b1164c56 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 16:32:14 -0700 Subject: [PATCH 12/54] [Sass] Test case for warnings across imports. --- test/sass/engine_test.rb | 16 +++++++++++ test/sass/plugin_test.rb | 38 +++++++++++++++----------- test/sass/results/warn.css | 0 test/sass/results/warn_imported.css | 0 test/sass/templates/warn.sass | 3 ++ test/sass/templates/warn_imported.sass | 4 +++ 6 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 test/sass/results/warn.css create mode 100644 test/sass/results/warn_imported.css create mode 100644 test/sass/templates/warn.sass create mode 100644 test/sass/templates/warn_imported.sass diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index ba84c371..c08079fc 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -1745,6 +1745,22 @@ SASS end end + def test_warn_with_imports + expected_warning = < :compact, :load_paths => [File.dirname(__FILE__) + "/templates"] + end + end + # Regression tests def test_parens_in_mixins diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index d9425462..d4c8cc78 100755 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -14,7 +14,7 @@ class SassPluginTest < Test::Unit::TestCase FileUtils.mkdir tempfile_loc FileUtils.mkdir tempfile_loc(nil,"more_") set_plugin_opts - Sass::Plugin.update_stylesheets + update_all_stylesheets! reset_mtimes end @@ -34,21 +34,21 @@ class SassPluginTest < Test::Unit::TestCase def test_no_update File.delete(tempfile_loc('basic')) assert_needs_update 'basic' - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_stylesheet_updated 'basic' end def test_update_needed_when_modified touch 'basic' assert_needs_update 'basic' - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_stylesheet_updated 'basic' end def test_update_needed_when_dependency_modified touch 'basic' assert_needs_update 'import' - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_stylesheet_updated 'basic' assert_stylesheet_updated 'import' end @@ -56,7 +56,7 @@ class SassPluginTest < Test::Unit::TestCase def test_update_needed_when_scss_dependency_modified touch 'scss_importee' assert_needs_update 'import' - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_stylesheet_updated 'scss_importee' assert_stylesheet_updated 'import' end @@ -64,14 +64,14 @@ class SassPluginTest < Test::Unit::TestCase def test_scss_update_needed_when_dependency_modified touch 'basic' assert_needs_update 'scss_import' - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_stylesheet_updated 'basic' assert_stylesheet_updated 'scss_import' end def test_full_exception_handling File.delete(tempfile_loc('bork1')) - Sass::Plugin.update_stylesheets + update_all_stylesheets! File.open(tempfile_loc('bork1')) do |file| assert_equal(< tempfile_loc, template_loc(nil,'more_') => tempfile_loc(nil,'more_') } - Sass::Plugin.update_stylesheets + update_all_stylesheets! ['more1', 'more_import'].each { |name| assert_renders_correctly(name, :prefix => 'more_') } end @@ -111,7 +111,7 @@ CSS template_loc => tempfile_loc, template_loc(nil,'more_') => tempfile_loc(nil,'more_') } - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_renders_correctly('more1_with_line_comments', 'more1', :prefix => 'more_') end @@ -157,7 +157,7 @@ CSS def test_updating_stylesheets_callback_with_individual_files files = [[template_loc("basic"), tempfile_loc("basic")]] - assert_callback(:updating_stylesheets, files) {Sass::Plugin.update_stylesheets(files)} + assert_callback(:updating_stylesheets, files) {Haml::Util.silence_haml_warnings{Sass::Plugin.update_stylesheets(files)}} end def test_updating_stylesheets_callback_with_never_update @@ -248,7 +248,7 @@ CSS touch 'basic', 'more_' assert_needs_update "import" - Sass::Plugin.update_stylesheets + update_all_stylesheets! assert_renders_correctly("import") ensure FileUtils.mv(template_loc("basic", "more_"), template_loc("basic")) @@ -299,7 +299,7 @@ CSS if block_given? yield else - Sass::Plugin.update_stylesheets + update_all_stylesheets! end assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}" @@ -322,17 +322,17 @@ CSS if block_given? yield else - Sass::Plugin.update_stylesheets + update_all_stylesheets! end end def assert_callbacks(*args) - return Sass::Plugin.update_stylesheets if args.empty? + return update_all_stylesheets! if args.empty? assert_callback(*args.pop) {assert_callbacks(*args)} end def assert_no_callbacks(*args) - return Sass::Plugin.update_stylesheets if args.empty? + return update_all_stylesheets! if args.empty? assert_no_callback(*args.pop) {assert_no_callbacks(*args)} end @@ -340,6 +340,12 @@ CSS Sass::Plugin.instance_variable_set('@_sass_callbacks', {}) end + def update_all_stylesheets! + Haml::Util.silence_haml_warnings do + Sass::Plugin.update_stylesheets + end + end + def assert_needs_update(name) assert(Sass::Plugin.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} to need an update.") diff --git a/test/sass/results/warn.css b/test/sass/results/warn.css new file mode 100644 index 00000000..e69de29b diff --git a/test/sass/results/warn_imported.css b/test/sass/results/warn_imported.css new file mode 100644 index 00000000..e69de29b diff --git a/test/sass/templates/warn.sass b/test/sass/templates/warn.sass new file mode 100644 index 00000000..514c44a2 --- /dev/null +++ b/test/sass/templates/warn.sass @@ -0,0 +1,3 @@ +@warn "In the main file" +@import warn_imported.sass ++emits-a-warning diff --git a/test/sass/templates/warn_imported.sass b/test/sass/templates/warn_imported.sass new file mode 100644 index 00000000..493bd8af --- /dev/null +++ b/test/sass/templates/warn_imported.sass @@ -0,0 +1,4 @@ +@warn "Imported" + +=emits-a-warning + @warn "In an imported mixin" From c42d9d93c37a511e042c31f3eebeb55f3a0cf504 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:35:06 -0700 Subject: [PATCH 13/54] [Sass] Update the docs for @warn and related functionality. --- doc-src/SASS_CHANGELOG.md | 10 ++++++++++ doc-src/SASS_REFERENCE.md | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index cba1d010..8cf914b9 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -5,6 +5,16 @@ ## 3.0.0.beta.2 (Unreleased) +### `@warn` + +A new directive `@warn` has been added that allows sass libraries to emit warnings. This can be used to issue deprecation warnings, discourage sloppy coding, etc. +`@warn` takes a single argument that is a SassScript expression that will be +displayed on the console along with a stylesheet trace. + +Warnings may be silenced with the new `--quiet` command line option, +or the corresponding `:quiet` Sass option. Warnings are off by default +in Rails and Merb production environments. + ### `sass-convert` #### `--recursive` diff --git a/doc-src/SASS_REFERENCE.md b/doc-src/SASS_REFERENCE.md index 56dce6f0..2a975e5d 100644 --- a/doc-src/SASS_REFERENCE.md +++ b/doc-src/SASS_REFERENCE.md @@ -287,6 +287,9 @@ Available options are: Currently, this just means that strings in mixin arguments are treated as though they were in [an `=` context](#sass-script-strings). +{#quiet-option} `:quiet` +: When set to true, causes warnings to be disabled. + ## CSS Extensions ### Nested Rules @@ -898,8 +901,7 @@ and `_colors.scss` would be imported. The `@debug` directive prints the value of a SassScript expression to the standard error output stream. It's useful for debugging Sass files -that have complicated SassScript going on, -or for printing warnings in libraries. +that have complicated SassScript going on. For example: @debug 10em + 12em; @@ -908,6 +910,20 @@ outputs: Line 1 DEBUG: 22em +### `@warn` + +The `@warn` directive prints the value of a SassScript expression +to the standard error output stream. +It's useful for libraries that need to warn users of deprecations +or recovering from minor coding mistakes. There are two major distinctions +between `@warn` and `@debug`: + +1. You can turn warnings off with the `--quiet` command-line option + or the `:quiet` Sass option. +2. A stylesheet trace will be printed out along with the message + so that the user being warned can see where they are calling from + their code. + ## Control Directives SassScript supports basic control directives From e427ab302eef4ea5a62e0212a8c80bf70f996f50 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:36:54 -0700 Subject: [PATCH 14/54] [Sass] Add the type-of() sass function to inspect the data type of values. --- doc-src/SASS_CHANGELOG.md | 8 ++++++++ lib/sass/script/functions.rb | 21 +++++++++++++++++++++ test/sass/functions_test.rb | 8 ++++++++ 3 files changed, 37 insertions(+) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 8cf914b9..7edca11f 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -5,6 +5,14 @@ ## 3.0.0.beta.2 (Unreleased) +### New Sass Functions for Introspection + +Several new functions were added to make it easier to have +more flexible arguments to mixins and to enable deprecation +of obsolete APIs. + +* `type-of` -- Returns the type of a value. + ### `@warn` A new directive `@warn` has been added that allows sass libraries to emit warnings. This can be used to issue deprecation warnings, discourage sloppy coding, etc. diff --git a/lib/sass/script/functions.rb b/lib/sass/script/functions.rb index 24458d9d..cb437e3a 100644 --- a/lib/sass/script/functions.rb +++ b/lib/sass/script/functions.rb @@ -105,6 +105,11 @@ module Sass::Script # \{#abs} # : Returns the absolute value of a number. # + # ## Introspection Functions + # + # \{#type_of} + # : Returns the type of a value. + # # These functions are described in more detail below. # # ## Adding Custom Functions @@ -669,6 +674,22 @@ module Sass::Script Sass::Script::String.new(str.value, :string) end + # Inspects the type of the argument, returning it as an unquoted string. + # For example: + # + # type-of(100px) => number + # type-of(asdf) => string + # type-of("asdf") => string + # type-of(true) => bool + # type-of(#fff) => color + # type-of(blue) => color + # + # @param obj [Literal] The object to inspect + # @return [String] The unquoted string value of the literal's type + def type_of(obj) + Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase) + end + # Converts a decimal number to a percentage. # For example: # diff --git a/test/sass/functions_test.rb b/test/sass/functions_test.rb index d33bd229..e2a198eb 100755 --- a/test/sass/functions_test.rb +++ b/test/sass/functions_test.rb @@ -505,6 +505,14 @@ The #options attribute is not set on this Sass::Script::String. MSG end + def test_type_of + assert_equal("string", evaluate("type-of(\"asdf\")")) + assert_equal("string", evaluate("type-of(asdf)")) + assert_equal("number", evaluate("type-of(1px)")) + assert_equal("bool", evaluate("type-of(true)")) + assert_equal("color", evaluate("type-of(#fff)")) + end + private def evaluate(value) From 4eacfa9c16743d6382f2fa903511605ea96386ed Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:39:20 -0700 Subject: [PATCH 15/54] [Sass] Add a sass function unit() to return the units of a number as a string. --- doc-src/SASS_CHANGELOG.md | 1 + lib/sass/script/functions.rb | 21 +++++++++++++++++++++ lib/sass/script/number.rb | 22 +++++++++++++--------- test/sass/functions_test.rb | 9 +++++++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 7edca11f..8190a2e3 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -12,6 +12,7 @@ more flexible arguments to mixins and to enable deprecation of obsolete APIs. * `type-of` -- Returns the type of a value. +* `unit` -- Returns the units associated with a number. ### `@warn` diff --git a/lib/sass/script/functions.rb b/lib/sass/script/functions.rb index cb437e3a..7d23a5ec 100644 --- a/lib/sass/script/functions.rb +++ b/lib/sass/script/functions.rb @@ -110,6 +110,9 @@ module Sass::Script # \{#type_of} # : Returns the type of a value. # + # \{#unit} + # : Returns the units associated with a number. + # # These functions are described in more detail below. # # ## Adding Custom Functions @@ -690,6 +693,24 @@ module Sass::Script Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase) end + # Inspects the unit of the number, returning it as a quoted string. + # Complex units are sorted in alphabetical order by numerator and denominator. + # For example: + # + # unit(100) => "" + # unit(100px) => "px" + # unit(3em) => "em" + # unit(10px * 5em) => "em*px" + # unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem" + # + # @param number [Literal] The number to inspect + # @return [String] The unit(s) of the number + # @raise [ArgumentError] if `number` isn't a number + def unit(number) + assert_type number, :Number + Sass::Script::String.new(number.unit_str, :string) + end + # Converts a decimal number to a percentage. # For example: # diff --git a/lib/sass/script/number.rb b/lib/sass/script/number.rb index e21f9296..4067ca55 100644 --- a/lib/sass/script/number.rb +++ b/lib/sass/script/number.rb @@ -299,6 +299,19 @@ module Sass::Script end, num_units, den_units) end + # Returns a human readable representation of the units in this number. + # For complex units this takes the form of: + # numerator_unit1 * numerator_unit2 / denominator_unit1 * denominator_unit2 + # @return [String] a string that represents the units in this number + def unit_str + rv = numerator_units.sort.join("*") + if denominator_units.any? + rv << "/" + rv << denominator_units.sort.join("*") + end + rv + end + protected def operate(other, operation) @@ -343,15 +356,6 @@ module Sass::Script end end - def unit_str - rv = numerator_units.join("*") - if denominator_units.any? - rv << "/" - rv << denominator_units.join("*") - end - rv - end - def normalize! return if unitless? @numerator_units, @denominator_units = sans_common_units(numerator_units, denominator_units) diff --git a/test/sass/functions_test.rb b/test/sass/functions_test.rb index e2a198eb..feec1384 100755 --- a/test/sass/functions_test.rb +++ b/test/sass/functions_test.rb @@ -513,6 +513,15 @@ MSG assert_equal("color", evaluate("type-of(#fff)")) end + def test_unit + assert_equal(%Q{""}, evaluate("unit(100)")) + assert_equal(%Q{"px"}, evaluate("unit(100px)")) + assert_equal(%Q{"em*px"}, evaluate("unit(10px * 5em)")) + assert_equal(%Q{"em*px"}, evaluate("unit(5em * 10px)")) + assert_equal(%Q{"em*px/cm*rem"}, evaluate("unit(10px * 5em / 30cm / 1rem)")) + assert_error_message("#ff0000 is not a number for `unit'", "unit(#f00)") + end + private def evaluate(value) From 8bf19c1c8acfb261141a250eae79e33bf12c3f08 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:40:36 -0700 Subject: [PATCH 16/54] [Sass] Add a sass function unitless() that returns a boolean indicating if a number is unitless. --- doc-src/SASS_CHANGELOG.md | 1 + lib/sass/script/functions.rb | 17 +++++++++++++++++ test/sass/functions_test.rb | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 8190a2e3..9ed98a23 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -13,6 +13,7 @@ of obsolete APIs. * `type-of` -- Returns the type of a value. * `unit` -- Returns the units associated with a number. +* `unitless` -- Returns whether a number has units or not. ### `@warn` diff --git a/lib/sass/script/functions.rb b/lib/sass/script/functions.rb index 7d23a5ec..6e8afa1f 100644 --- a/lib/sass/script/functions.rb +++ b/lib/sass/script/functions.rb @@ -113,6 +113,9 @@ module Sass::Script # \{#unit} # : Returns the units associated with a number. # + # \{#unitless} + # : Returns whether a number has units or not. + # # These functions are described in more detail below. # # ## Adding Custom Functions @@ -711,6 +714,20 @@ module Sass::Script Sass::Script::String.new(number.unit_str, :string) end + # Inspects the unit of the number, returning a boolean indicating if it is unitless. + # For example: + # + # unitless(100) => true + # unitless(100px) => false + # + # @param number [Literal] The number to inspect + # @return [Bool] indicating if the number is unitless + # @raise [ArgumentError] if `number` isn't a number + def unitless(number) + assert_type number, :Number + Sass::Script::Bool.new(number.unitless?) + end + # Converts a decimal number to a percentage. # For example: # diff --git a/test/sass/functions_test.rb b/test/sass/functions_test.rb index feec1384..e10281ac 100755 --- a/test/sass/functions_test.rb +++ b/test/sass/functions_test.rb @@ -522,6 +522,12 @@ MSG assert_error_message("#ff0000 is not a number for `unit'", "unit(#f00)") end + def test_unitless + assert_equal(%Q{true}, evaluate("unitless(100)")) + assert_equal(%Q{false}, evaluate("unitless(100px)")) + assert_error_message("#ff0000 is not a number for `unitless'", "unitless(#f00)") + end + private def evaluate(value) From 91480eab1c8d943e772b97369b81cf19472db2e2 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:41:47 -0700 Subject: [PATCH 17/54] [Sass] Add a sass function comparable() that indicates whether two numbers are similar enough to be compared. --- doc-src/SASS_CHANGELOG.md | 1 + lib/sass/script/functions.rb | 20 ++++++++++++++++++++ lib/sass/script/number.rb | 11 +++++++++++ test/sass/functions_test.rb | 8 ++++++++ 4 files changed, 40 insertions(+) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 9ed98a23..f8b45893 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -14,6 +14,7 @@ of obsolete APIs. * `type-of` -- Returns the type of a value. * `unit` -- Returns the units associated with a number. * `unitless` -- Returns whether a number has units or not. +* `comparable` -- Returns whether two numbers can be added or compared. ### `@warn` diff --git a/lib/sass/script/functions.rb b/lib/sass/script/functions.rb index 6e8afa1f..ed2a65fb 100644 --- a/lib/sass/script/functions.rb +++ b/lib/sass/script/functions.rb @@ -116,6 +116,9 @@ module Sass::Script # \{#unitless} # : Returns whether a number has units or not. # + # \{#comparable} + # : Returns whether two numbers can be added or compared. + # # These functions are described in more detail below. # # ## Adding Custom Functions @@ -728,6 +731,23 @@ module Sass::Script Sass::Script::Bool.new(number.unitless?) end + # Returns true if two numbers are similar enough to be added, subtracted, or compared. + # For example: + # + # comparable(2px, 1px) => true + # comparable(100px, 3em) => false + # comparable(10cm, 3mm) => true + # + # @param number1 [Number] + # @param number2 [Number] + # @return [Bool] indicating if the numbers can be compared. + # @raise [ArgumentError] if `number1` or `number2` aren't numbers + def comparable(number1, number2) + assert_type number1, :Number + assert_type number2, :Number + Sass::Script::Bool.new(number1.comparable_to?(number2)) + end + # Converts a decimal number to a percentage. # For example: # diff --git a/lib/sass/script/number.rb b/lib/sass/script/number.rb index 4067ca55..9dc0b597 100644 --- a/lib/sass/script/number.rb +++ b/lib/sass/script/number.rb @@ -299,6 +299,17 @@ module Sass::Script end, num_units, den_units) end + # @param other [Number] A number to decide if it can be compared with this number. + # @return [Boolean] Whether or not this number can be compared with the other. + def comparable_to?(other) + begin + self.operate(other, :+) + true + rescue Sass::UnitConversionError + false + end + end + # Returns a human readable representation of the units in this number. # For complex units this takes the form of: # numerator_unit1 * numerator_unit2 / denominator_unit1 * denominator_unit2 diff --git a/test/sass/functions_test.rb b/test/sass/functions_test.rb index e10281ac..31e29a3d 100755 --- a/test/sass/functions_test.rb +++ b/test/sass/functions_test.rb @@ -528,6 +528,14 @@ MSG assert_error_message("#ff0000 is not a number for `unitless'", "unitless(#f00)") end + def test_comparable + assert_equal(%Q{true}, evaluate("comparable(2px, 1px)")) + assert_equal(%Q{true}, evaluate("comparable(10cm, 3mm)")) + assert_equal(%Q{false}, evaluate("comparable(100px, 3em)")) + assert_error_message("#ff0000 is not a number for `comparable'", "comparable(#f00, 1px)") + assert_error_message("#ff0000 is not a number for `comparable'", "comparable(1px, #f00)") + end + private def evaluate(value) From dcaa55fd85022a9a1ff6b15b2dbf3fee7ddafc34 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 10 Apr 2010 22:42:18 -0700 Subject: [PATCH 18/54] [Sass] Some examples for the @warn directive. --- doc-src/SASS_REFERENCE.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc-src/SASS_REFERENCE.md b/doc-src/SASS_REFERENCE.md index 2a975e5d..fe53dc41 100644 --- a/doc-src/SASS_REFERENCE.md +++ b/doc-src/SASS_REFERENCE.md @@ -924,6 +924,33 @@ between `@warn` and `@debug`: so that the user being warned can see where they are calling from their code. +Usage Example: + + @mixin adjust-location($x, $y) { + @if unitless($x) { + @warn "Assuming #{$x} to be in pixels"; + $x: 1px * $x; + } + @if unitless($y) { + @warn "Assuming #{$y} to be in pixels"; + $y: 1px * $y; + } + position: relative; left: $x; top: $y; + } + +Indented Syntax Example: + + =adjust-location($x, $y) + @if unitless($x) + @warn "Assuming #{$x} to be in pixels" + $x: 1px * $x + @if unitless($y) + @warn "Assuming #{$y} to be in pixels" + $y: 1px * $y + position: relative + left: $x + top: $y + ## Control Directives SassScript supports basic control directives From 577c234abb272265b376ce4cf9e4c8faafb80dd4 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 11 Apr 2010 01:46:48 -0700 Subject: [PATCH 19/54] [Sass] Find files in the order of the load path irrespective of syntax. --- lib/sass/files.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/sass/files.rb b/lib/sass/files.rb index e4e1f946..cdb61c8b 100644 --- a/lib/sass/files.rb +++ b/lib/sass/files.rb @@ -76,8 +76,11 @@ module Sass return filename end - new_filename = find_full_path("#{filename}.sass", load_paths) unless was_scss - new_filename ||= find_full_path("#{filename}.scss", load_paths) unless was_sass + new_filename = nil + load_paths.each do |load_path| + new_filename ||= find_full_path("#{filename}.sass", [load_path]) unless was_scss + new_filename ||= find_full_path("#{filename}.scss", [load_path]) unless was_sass + end return new_filename if new_filename unless was_sass || was_scss From 228f6fd6b16255967de5583aa723d32cd701ddd4 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 02:58:30 -0700 Subject: [PATCH 20/54] [Sass] [Convert] Raise an error if an invalid format is given to sass-convert. --- lib/haml/exec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/haml/exec.rb b/lib/haml/exec.rb index 3d03dba8..b6fc8aba 100644 --- a/lib/haml/exec.rb +++ b/lib/haml/exec.rb @@ -591,6 +591,9 @@ END 'By default, this is inferred from the input filename.', 'If there is none, defaults to css.') do |name| @options[:from] = name.downcase.to_sym + unless [:css, :scss, :sass].include?(@options[:from]) + raise "Unknown format for sass-convert --from: #{name}" + end end opts.on('-T', '--to FORMAT', @@ -598,6 +601,9 @@ END 'By default, this is inferred from the output filename.', 'If there is none, defaults to sass.') do |name| @options[:to] = name.downcase.to_sym + unless [:scss, :sass].include?(@options[:to]) + raise "Unknown format for sass-convert --to: #{name}" + end end opts.on('-R', '--recursive', From 8462fc27b7c2b987386370d1a9ca27bc131a84ab Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 21:20:05 +0200 Subject: [PATCH 21/54] [Sass] Move StalenessChecker into its own file. --- lib/sass/plugin.rb | 73 +-------------------------- lib/sass/plugin/staleness_checker.rb | 75 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 72 deletions(-) create mode 100644 lib/sass/plugin/staleness_checker.rb diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 4743497d..2ebf57f9 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -3,6 +3,7 @@ require 'rbconfig' require 'sass' require 'sass/callbacks' +require 'sass/plugin/staleness_checker' module Sass # This module handles the compilation of Sass/SCSS files. @@ -29,78 +30,6 @@ module Sass # #=> Compiling app/sass/print.scss to public/stylesheets/print.css # #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css module Plugin - class StalenessChecker - attr_reader :engine_options - - def initialize(engine_options) - @engine_options, @mtimes, @dependencies_stale = engine_options, {}, {} - @dependencies = Thread.current[:_sass_file_dependencies] ||= {} - end - - def stylesheet_needs_update?(css_file, template_file) - template_file = File.expand_path(template_file) - - unless File.exists?(css_file) && File.exists?(template_file) - @dependencies.delete(template_file) - true - else - css_mtime = mtime(css_file) - mtime(template_file) > css_mtime || dependencies_stale?(template_file, css_mtime) - end - end - - private - - def dependencies_stale?(template_file, css_mtime) - timestamps = @dependencies_stale[template_file] ||= {} - timestamps.each_pair do |checked_css_mtime, is_stale| - if checked_css_mtime <= css_mtime && !is_stale - return false - elsif checked_css_mtime > css_mtime && is_stale - return true - end - end - timestamps[css_mtime] = run_stale_dependencies_check(template_file, css_mtime) - end - - def run_stale_dependencies_check(template_file, css_mtime) - dependencies(template_file).any?(&dependency_updated?(css_mtime)) - end - - def mtime(filename) - @mtimes[filename] ||= File.mtime(filename) - end - - def dependencies(filename) - stored_mtime, dependencies = @dependencies[filename] - - if !stored_mtime || stored_mtime < mtime(filename) - @dependencies[filename] = [mtime(filename), dependencies = compute_dependencies(filename)] - end - - dependencies - end - - def dependency_updated?(css_mtime) - lambda do |dep| - begin - mtime(dep) > css_mtime || dependencies_stale?(dep, css_mtime) - rescue Sass::SyntaxError - # If there's an error finding depenencies, default to recompiling. - true - end - end - end - - def compute_dependencies(filename) - Files.tree_for(filename, engine_options).grep(Tree::ImportNode) do |n| - File.expand_path(n.full_filename) unless n.full_filename =~ /\.css$/ - end.compact - rescue Sass::SyntaxError => e - [] # If the file has an error, we assume it has no dependencies - end - end - include Haml::Util include Sass::Callbacks extend self diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb new file mode 100644 index 00000000..9f749872 --- /dev/null +++ b/lib/sass/plugin/staleness_checker.rb @@ -0,0 +1,75 @@ +module Sass + module Plugin + class StalenessChecker + attr_reader :engine_options + + def initialize(engine_options) + @engine_options, @mtimes, @dependencies_stale = engine_options, {}, {} + @dependencies = Thread.current[:_sass_file_dependencies] ||= {} + end + + def stylesheet_needs_update?(css_file, template_file) + template_file = File.expand_path(template_file) + + unless File.exists?(css_file) && File.exists?(template_file) + @dependencies.delete(template_file) + true + else + css_mtime = mtime(css_file) + mtime(template_file) > css_mtime || dependencies_stale?(template_file, css_mtime) + end + end + + private + + def dependencies_stale?(template_file, css_mtime) + timestamps = @dependencies_stale[template_file] ||= {} + timestamps.each_pair do |checked_css_mtime, is_stale| + if checked_css_mtime <= css_mtime && !is_stale + return false + elsif checked_css_mtime > css_mtime && is_stale + return true + end + end + timestamps[css_mtime] = run_stale_dependencies_check(template_file, css_mtime) + end + + def run_stale_dependencies_check(template_file, css_mtime) + dependencies(template_file).any?(&dependency_updated?(css_mtime)) + end + + def mtime(filename) + @mtimes[filename] ||= File.mtime(filename) + end + + def dependencies(filename) + stored_mtime, dependencies = @dependencies[filename] + + if !stored_mtime || stored_mtime < mtime(filename) + @dependencies[filename] = [mtime(filename), dependencies = compute_dependencies(filename)] + end + + dependencies + end + + def dependency_updated?(css_mtime) + lambda do |dep| + begin + mtime(dep) > css_mtime || dependencies_stale?(dep, css_mtime) + rescue Sass::SyntaxError + # If there's an error finding depenencies, default to recompiling. + true + end + end + end + + def compute_dependencies(filename) + Files.tree_for(filename, engine_options).grep(Tree::ImportNode) do |n| + File.expand_path(n.full_filename) unless n.full_filename =~ /\.css$/ + end.compact + rescue Sass::SyntaxError => e + [] # If the file has an error, we assume it has no dependencies + end + end + end +end \ No newline at end of file From c53401ebd263b292a78d4017349a6b66003ac4fd Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 21:27:03 +0200 Subject: [PATCH 22/54] [Sass] Inline StalenessChecker's run_stale_dependencies_check. --- lib/sass/plugin/staleness_checker.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index 9f749872..f2a508d9 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -31,11 +31,7 @@ module Sass return true end end - timestamps[css_mtime] = run_stale_dependencies_check(template_file, css_mtime) - end - - def run_stale_dependencies_check(template_file, css_mtime) - dependencies(template_file).any?(&dependency_updated?(css_mtime)) + timestamps[css_mtime] = dependencies(template_file).any?(&dependency_updated?(css_mtime)) end def mtime(filename) From 4e9b686af8db392f9bac40f40923f2bf76ce5c14 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 21:46:47 +0200 Subject: [PATCH 23/54] [Sass] Don't expect to be given Plugin's engine_options and get rid of the factory method. --- lib/sass/plugin.rb | 8 ++------ lib/sass/plugin/staleness_checker.rb | 8 +++----- test/sass/plugin_test.rb | 8 ++------ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 2ebf57f9..6dc85286 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -212,7 +212,7 @@ module Sass individual_files.each {|t, c| update_stylesheet(t, c)} @checked_for_updates = true - staleness_checker = make_staleness_checker + staleness_checker = StalenessChecker.new template_locations.zip(css_locations).each do |template_location, css_location| @@ -377,13 +377,9 @@ module Sass name.sub(/^.*\//, '')[0] == ?_ end - def make_staleness_checker - StalenessChecker.new(engine_options) - end - # Compass expects this to exist def stylesheet_needs_update?(css_file, template_file) - make_staleness_checker.stylesheet_needs_update?(css_file, template_file) + StalenessChecker.new.stylesheet_needs_update?(css_file, template_file) end end end diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index f2a508d9..f9dfcd55 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -1,10 +1,8 @@ module Sass module Plugin class StalenessChecker - attr_reader :engine_options - - def initialize(engine_options) - @engine_options, @mtimes, @dependencies_stale = engine_options, {}, {} + def initialize + @mtimes, @dependencies_stale = {}, {} @dependencies = Thread.current[:_sass_file_dependencies] ||= {} end @@ -60,7 +58,7 @@ module Sass end def compute_dependencies(filename) - Files.tree_for(filename, engine_options).grep(Tree::ImportNode) do |n| + Files.tree_for(filename, Plugin.engine_options).grep(Tree::ImportNode) do |n| File.expand_path(n.full_filename) unless n.full_filename =~ /\.css$/ end.compact rescue Sass::SyntaxError => e diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index ac6a6191..8d2f789d 100755 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -341,13 +341,13 @@ CSS end def assert_needs_update(name) - checker = make_staleness_checker + checker = Sass::Plugin::StalenessChecker.new assert(checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} to need an update.") end def assert_doesnt_need_update(name) - checker = make_staleness_checker + checker = Sass::Plugin::StalenessChecker.new assert(!checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} not to need an update.") end @@ -391,10 +391,6 @@ CSS "#{File.dirname(__FILE__)}/#{file}" end - def make_staleness_checker - Sass::Plugin.send(:make_staleness_checker) - end - def set_plugin_opts(overrides = {}) Sass::Plugin.options = { :template_location => template_loc, From dbd0c9593722b4f5c2eb72aa6e231fcf0a87a0a6 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 21:53:22 +0200 Subject: [PATCH 24/54] [Sass] Sass::Plugin is not expected to be thread safe in development mode at this point. --- lib/sass/plugin/staleness_checker.rb | 10 ++++++++-- test/sass/plugin_test.rb | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index f9dfcd55..77fc48a5 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -1,9 +1,15 @@ module Sass module Plugin class StalenessChecker - def initialize + @dependencies_cache = {} + + class << self + attr_accessor :dependencies_cache + end + + def initialize(dependencies = self.class.dependencies_cache) + @dependencies = dependencies @mtimes, @dependencies_stale = {}, {} - @dependencies = Thread.current[:_sass_file_dependencies] ||= {} end def stylesheet_needs_update?(css_file, template_file) diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index 8d2f789d..57e07629 100755 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -357,6 +357,7 @@ CSS end def reset_mtimes + Sass::Plugin::StalenessChecker.dependencies_cache = {} atime = Time.now mtime = Time.now - 5 Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass,scss}"].each {|f| File.utime(atime, mtime, f)} From c3a52a06c8869757bbe85df3a3415a26e7a61c77 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 21:59:10 +0200 Subject: [PATCH 25/54] [Sass] Add class-level stylesheet_needs_update? method. --- lib/sass/plugin.rb | 2 +- lib/sass/plugin/staleness_checker.rb | 4 ++++ test/sass/plugin_test.rb | 6 ++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index 6dc85286..108fb893 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -379,7 +379,7 @@ module Sass # Compass expects this to exist def stylesheet_needs_update?(css_file, template_file) - StalenessChecker.new.stylesheet_needs_update?(css_file, template_file) + StalenessChecker.stylesheet_needs_update?(css_file, template_file) end end end diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index 77fc48a5..28c8fbb8 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -70,6 +70,10 @@ module Sass rescue Sass::SyntaxError => e [] # If the file has an error, we assume it has no dependencies end + + def self.stylesheet_needs_update?(css_file, template_file) + new.stylesheet_needs_update?(css_file, template_file) + end end end end \ No newline at end of file diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index 57e07629..3294d787 100755 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -341,14 +341,12 @@ CSS end def assert_needs_update(name) - checker = Sass::Plugin::StalenessChecker.new - assert(checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), + assert(Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} to need an update.") end def assert_doesnt_need_update(name) - checker = Sass::Plugin::StalenessChecker.new - assert(!checker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), + assert(!Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)), "Expected #{template_loc(name)} not to need an update.") end From e9db90afc36c898cf79bb8e3fb28191daf93db27 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 11 Apr 2010 22:30:13 +0200 Subject: [PATCH 26/54] [Sass] Add some docs for StalenessChecker. --- lib/sass/plugin/staleness_checker.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index 28c8fbb8..61354604 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -1,5 +1,18 @@ module Sass module Plugin + # The class handles .s[ca]ss file staleness checks via their mtime timestamps. + # To speed things up 2 level of caches are employed: + # * a class-level @dependencies_cache storing @import paths, this is a long lived cache + # that is being reused by every StalenessChecker instance, + # * 2 class-level short lived @mtimes, @dependencies_stale caches that are only used by a single + # StalenessChecker instance. + # Usage: + # * In case of a one-off staleness check of a single .s[ca]ss file a class level + # StalenessChecker.stylesheet_needs_update? method should be used. + # * In case of a series of checks (checking all the files for staleness) an instance should be created, + # as its caches should make the whole process significantly faster. + # WARNING: It is important that you do not hold on onto the instance for too long as its + # instance-level caches are never explicitly expired. class StalenessChecker @dependencies_cache = {} @@ -8,7 +21,11 @@ module Sass end def initialize(dependencies = self.class.dependencies_cache) - @dependencies = dependencies + @dependencies = dependencies + + # Entries in the following instance-level caches are never explicitly expired. + # Instead they are supposed to automaticaly go out of scope when a series of staleness checks + # (this instance of StalenessChecker was created for) is finished. @mtimes, @dependencies_stale = {}, {} end From a5ce4eef71bc7c938062bc24957e90794adacfb0 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 14:32:02 -0700 Subject: [PATCH 27/54] [Sass] Fix a little documentation for the stack-handling additions. --- lib/sass/environment.rb | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/sass/environment.rb b/lib/sass/environment.rb index e79a4389..e261b50a 100644 --- a/lib/sass/environment.rb +++ b/lib/sass/environment.rb @@ -38,20 +38,20 @@ module Sass # Push lexical frame information onto the runtime stack. # @param frame_info [{Symbol => Object}] - # Frame information has the following keys: + # Frame information has the following keys: # - # `:filename` - # : The name of the file in which the lexical scope changed. + # `:filename` + # : The name of the file in which the lexical scope changed. # - # `:mixin` - # : The name of the mixin in which the lexical scope changed, - # or `nil` if it wasn't within in a mixin. + # `:mixin` + # : The name of the mixin in which the lexical scope changed, + # or `nil` if it wasn't within in a mixin. # - # `:line` - # : The line of the file on which the lexical scope changed. Never nil. + # `:line` + # : The line of the file on which the lexical scope changed. Never nil. # - # `:import` - # : Set to `true` when the lexical scope is changing due to an import. + # `:import` + # : Set to `true` when the lexical scope is changing due to an import. def push(frame_info) @stack.push frame_info end @@ -63,13 +63,19 @@ module Sass # A list of the runtime stack frame information # The last element in the list was pushed onto the stack most recently. + # + # @return [Array<{Symbol => Object}>] The stack frames, + # of the form passed to \{#push}. def stack prev = (!@ignore_parent_stack && parent && parent.stack) || [] prev + @stack end # Temporarily assume the runtime stack that is passed in. - # @param stk A stack value from another environment. + # + # @param stk [Array<{Symbol => Object}>] A call stack from another environment, + # of the form returned by \{#stack}. + # @yield A block in which the stack is set to `stk`. def with_stack(stk) @stack, old_stack = stk, @stack @ignore_parent_stack = true From 11f2cf118fc79a3bda07b5deabd2c65008552d5a Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 15:24:05 -0700 Subject: [PATCH 28/54] [Sass] Modify the stack stuff so that warnings look like error messages. --- lib/sass/environment.rb | 52 +++++++++++++++++------------------- lib/sass/tree/import_node.rb | 4 +-- lib/sass/tree/mixin_node.rb | 39 +++++++++++++-------------- lib/sass/tree/warn_node.rb | 23 +++++++--------- test/sass/engine_test.rb | 19 +++++++------ test/sass/scss/scss_test.rb | 7 ++--- 6 files changed, 69 insertions(+), 75 deletions(-) diff --git a/lib/sass/environment.rb b/lib/sass/environment.rb index e261b50a..088cf172 100644 --- a/lib/sass/environment.rb +++ b/lib/sass/environment.rb @@ -23,8 +23,7 @@ module Sass @vars = {} @mixins = {} @parent = parent - @stack = [] - @ignore_parent_stack = false + @stack = [] unless parent set_var("important", Script::String.new("!important")) unless @parent end @@ -36,7 +35,8 @@ module Sass @options || (parent && parent.options) || {} end - # Push lexical frame information onto the runtime stack. + # Push a new stack frame onto the mixin/include stack. + # # @param frame_info [{Symbol => Object}] # Frame information has the following keys: # @@ -49,40 +49,36 @@ module Sass # # `:line` # : The line of the file on which the lexical scope changed. Never nil. + def push_frame(frame_info) + if stack.last && stack.last[:prepared] + stack.last.delete(:prepared) + stack.last.merge!(frame_info) + else + stack.push(frame_info) + end + end + + # Like \{#push\_frame}, but next time a stack frame is pushed, + # it will be merged with this frame. # - # `:import` - # : Set to `true` when the lexical scope is changing due to an import. - def push(frame_info) - @stack.push frame_info + # @param frame_info [{Symbol => Object}] Same as for \{#push\_frame}. + def prepare_frame(frame_info) + push_frame(frame_info.merge(:prepared => true)) end - # Pop runtime frame information from the stack. - def pop - @stack.pop + # Pop a stack frame from the mixin/include stack. + def pop_frame + stack.pop if stack.last[:prepared] + stack.pop end - # A list of the runtime stack frame information - # The last element in the list was pushed onto the stack most recently. + # A list of stack frames in the mixin/include stack. + # The last element in the list is the most deeply-nested frame. # # @return [Array<{Symbol => Object}>] The stack frames, # of the form passed to \{#push}. def stack - prev = (!@ignore_parent_stack && parent && parent.stack) || [] - prev + @stack - end - - # Temporarily assume the runtime stack that is passed in. - # - # @param stk [Array<{Symbol => Object}>] A call stack from another environment, - # of the form returned by \{#stack}. - # @yield A block in which the stack is set to `stk`. - def with_stack(stk) - @stack, old_stack = stk, @stack - @ignore_parent_stack = true - yield self - ensure - @ignore_parent_stack = false - @stack = old_stack + @stack ||= @parent.stack end class << self diff --git a/lib/sass/tree/import_node.rb b/lib/sass/tree/import_node.rb index 0c4f2009..d255ace7 100644 --- a/lib/sass/tree/import_node.rb +++ b/lib/sass/tree/import_node.rb @@ -62,7 +62,7 @@ module Sass # @param environment [Sass::Environment] The lexical environment containing # variable and mixin values def perform!(environment) - environment.push(:filename => @filename, :line => @line, :import => true) + environment.push_frame(:filename => @filename, :line => @line) root = Sass::Files.tree_for(full_filename, @options) @template = root.template self.children = root.children @@ -72,7 +72,7 @@ module Sass e.add_backtrace(:filename => @filename, :line => @line) raise e ensure - environment.pop + environment.pop_frame end private diff --git a/lib/sass/tree/mixin_node.rb b/lib/sass/tree/mixin_node.rb index e2882ec2..84235b90 100644 --- a/lib/sass/tree/mixin_node.rb +++ b/lib/sass/tree/mixin_node.rb @@ -51,38 +51,37 @@ module Sass::Tree # @see Sass::Tree def perform!(environment) original_env = environment - original_env.push(:filename => filename, :mixin => @name, :line => line) + original_env.push_frame(:filename => filename, :line => line) + original_env.prepare_frame(:mixin => @name) raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.") unless mixin = environment.mixin(@name) raise Sass::SyntaxError.new(< e e.modify_backtrace(:mixin => @name, :line => @line) e.add_backtrace(:line => @line) raise e ensure - original_env.pop + original_env.pop_frame end end end diff --git a/lib/sass/tree/warn_node.rb b/lib/sass/tree/warn_node.rb index 1cd122c8..a29ca5b7 100644 --- a/lib/sass/tree/warn_node.rb +++ b/lib/sass/tree/warn_node.rb @@ -21,25 +21,20 @@ module Sass # @param environment [Sass::Environment] The lexical environment containing # variable and mixin values def _perform(environment) - environment.push(:filename => filename, :line => line) + environment.push_frame(:filename => filename, :line => line) res = @expr.perform(environment) res = res.value if res.is_a?(Sass::Script::String) - Haml::Util.haml_warn "WARNING: #{res}" - Haml::Util.enum_with_index(environment.stack.reverse).each do |entry, i| - where = " " - if entry[:mixin] - where << "via '#{entry[:mixin]}' mixed in at line #{entry[:line]}" - elsif entry[:import] - where << "imported from line #{entry[:line]}" - else - where << "#{"issued" if i == 0} from line #{entry[:line]}" - end - where << " of #{entry[:filename] || "(sass)"}" - Haml::Util.haml_warn where + msg = "WARNING: #{res}\n" + environment.stack.reverse.each_with_index do |entry, i| + msg << " #{i == 0 ? "on" : "from"} line #{entry[:line]}" << + " of #{entry[:filename] || "an unknown file"}" + msg << ", in `#{entry[:mixin]}'" if entry[:mixin] + msg << "\n" end + Haml::Util.haml_warn msg [] ensure - environment.pop + environment.pop_frame end end end diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index c08079fc..a510c387 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -1715,10 +1715,11 @@ SASS def test_warn_directive expected_warning = < :compact, :load_paths => [File.dirname(__FILE__) + "/templates"] diff --git a/test/sass/scss/scss_test.rb b/test/sass/scss/scss_test.rb index e3eaa13c..7baecd05 100755 --- a/test/sass/scss/scss_test.rb +++ b/test/sass/scss/scss_test.rb @@ -116,10 +116,11 @@ SCSS def test_warn_directive expected_warning = < Date: Sun, 11 Apr 2010 15:34:37 -0700 Subject: [PATCH 29/54] [Sass] Get rid of Haml::Util.with_warnings, and don't un-silence warnings if :quiet isn't true. --- lib/haml/util.rb | 8 -------- lib/sass/engine.rb | 5 ++--- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/haml/util.rb b/lib/haml/util.rb index 3d8cc96f..66c09a58 100644 --- a/lib/haml/util.rb +++ b/lib/haml/util.rb @@ -180,14 +180,6 @@ module Haml @@silence_warnings = old_silence_warnings end - def with_warnings(state) - old_silence_warnings = @@silence_warnings - @@silence_warnings = !state - yield - ensure - @@silence_warnings = old_silence_warnings - end - # The same as `Kernel#warn`, but is silenced by \{#silence\_haml\_warnings}. # # @param msg [String] diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 879dfdae..97fb0511 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -165,9 +165,8 @@ module Sass # @return [String] The CSS # @raise [Sass::SyntaxError] if there's an error in the document def render - Haml::Util.with_warnings(!@options[:quiet]) do - to_tree.render - end + return to_tree.render unless @options[:quiet] + Haml::Util.silence_haml_warnings {to_tree.render} end alias_method :to_css, :render From 917b32e5792e607990e0624d6dde26002d1bb8a5 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 15:37:19 -0700 Subject: [PATCH 30/54] [Sass] Silence warnings in to_tree if :quiet is set. --- lib/sass/engine.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 97fb0511..0efa5b83 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -165,10 +165,9 @@ module Sass # @return [String] The CSS # @raise [Sass::SyntaxError] if there's an error in the document def render - return to_tree.render unless @options[:quiet] - Haml::Util.silence_haml_warnings {to_tree.render} + return _to_tree.render unless @options[:quiet] + Haml::Util.silence_haml_warnings {_to_tree.render} end - alias_method :to_css, :render # Parses the document into its parse tree. @@ -176,6 +175,13 @@ module Sass # @return [Sass::Tree::Node] The root of the parse tree. # @raise [Sass::SyntaxError] if there's an error in the document def to_tree + return _to_tree unless @options[:quiet] + Haml::Util.silence_haml_warnings {_to_tree} + end + + private + + def _to_tree @template = check_encoding(@template) {|msg, line| raise Sass::SyntaxError.new(msg, :line => line)} if @options[:syntax] == :scss @@ -193,8 +199,6 @@ module Sass raise e end - private - def tabulate(string) tab_str = nil comment_tab_str = nil From 3418c1c282e9fe1bb4f47bea68982e5d7cef43ff Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 15:46:56 -0700 Subject: [PATCH 31/54] [Sass] Expand the @warn docs. --- doc-src/SASS_CHANGELOG.md | 18 +++++++++++++----- doc-src/SASS_REFERENCE.md | 20 +++----------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index f8b45893..54089d13 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -18,13 +18,21 @@ of obsolete APIs. ### `@warn` -A new directive `@warn` has been added that allows sass libraries to emit warnings. This can be used to issue deprecation warnings, discourage sloppy coding, etc. -`@warn` takes a single argument that is a SassScript expression that will be -displayed on the console along with a stylesheet trace. +A new directive `@warn` has been added that allows Sass libraries to emit warnings. +This can be used to issue deprecation warnings, discourage sloppy use of mixins, etc. +`@warn` takes a single argument: a SassScript expression that will be +displayed on the console along with a stylesheet trace for locating the warning. +For example: + + @mixin blue-text { + @warn "The blue-text mixin is deprecated. Use new-blue-text instead."; + color: #00f; + } Warnings may be silenced with the new `--quiet` command line option, -or the corresponding `:quiet` Sass option. Warnings are off by default -in Rails and Merb production environments. +or the corresponding {file:SASS_REFERENCE.md#quiet-option `:quiey` Sass option}. +This option will also affect warnings printed by Sass itself. +Warnings are off by default in the Rails, Rack, and Merb production environments. ### `sass-convert` diff --git a/doc-src/SASS_REFERENCE.md b/doc-src/SASS_REFERENCE.md index fe53dc41..e934234b 100644 --- a/doc-src/SASS_REFERENCE.md +++ b/doc-src/SASS_REFERENCE.md @@ -915,14 +915,13 @@ outputs: The `@warn` directive prints the value of a SassScript expression to the standard error output stream. It's useful for libraries that need to warn users of deprecations -or recovering from minor coding mistakes. There are two major distinctions -between `@warn` and `@debug`: +or recovering from minor mixin usage mistakes. +There are two major distinctions between `@warn` and `@debug`: 1. You can turn warnings off with the `--quiet` command-line option or the `:quiet` Sass option. 2. A stylesheet trace will be printed out along with the message - so that the user being warned can see where they are calling from - their code. + so that the user being warned can see where their styles caused the warning. Usage Example: @@ -938,19 +937,6 @@ Usage Example: position: relative; left: $x; top: $y; } -Indented Syntax Example: - - =adjust-location($x, $y) - @if unitless($x) - @warn "Assuming #{$x} to be in pixels" - $x: 1px * $x - @if unitless($y) - @warn "Assuming #{$y} to be in pixels" - $y: 1px * $y - position: relative - left: $x - top: $y - ## Control Directives SassScript supports basic control directives From aab052c0b428c429cee56c9f3712b578097b968c Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 15:58:00 -0700 Subject: [PATCH 32/54] [Sass] A few tweaks to the introspection function docs. --- doc-src/SASS_CHANGELOG.md | 11 +++++++---- lib/sass/script/functions.rb | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 54089d13..d4f5b8df 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -11,10 +11,13 @@ Several new functions were added to make it easier to have more flexible arguments to mixins and to enable deprecation of obsolete APIs. -* `type-of` -- Returns the type of a value. -* `unit` -- Returns the units associated with a number. -* `unitless` -- Returns whether a number has units or not. -* `comparable` -- Returns whether two numbers can be added or compared. +* {Sass::Script::Functions#type_of `type-of`} -- Returns the type of a value. +* {Sass::Script::Functions#unit `unit`} -- + Returns the units associated with a number. +* {Sass::Script::Functions#unitless `unitless`} -- + Returns whether a number has units or not. +* {Sass::Script::Functions#comparable `comparable`} -- + Returns whether two numbers can be added or compared. ### `@warn` diff --git a/lib/sass/script/functions.rb b/lib/sass/script/functions.rb index ed2a65fb..100bccd5 100644 --- a/lib/sass/script/functions.rb +++ b/lib/sass/script/functions.rb @@ -694,7 +694,7 @@ module Sass::Script # type-of(blue) => color # # @param obj [Literal] The object to inspect - # @return [String] The unquoted string value of the literal's type + # @return [String] The unquoted string name of the literal's type def type_of(obj) Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase) end @@ -724,7 +724,7 @@ module Sass::Script # unitless(100px) => false # # @param number [Literal] The number to inspect - # @return [Bool] indicating if the number is unitless + # @return [Bool] Whether or not the number is unitless # @raise [ArgumentError] if `number` isn't a number def unitless(number) assert_type number, :Number From 7b00f9f3172d3db6ab49297252ca92806819d476 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 15:59:11 -0700 Subject: [PATCH 33/54] [Sass] Make Sass::Files.find_full_path take a single load_path string, because we can. --- lib/sass/files.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/sass/files.rb b/lib/sass/files.rb index cdb61c8b..c92a9dce 100644 --- a/lib/sass/files.rb +++ b/lib/sass/files.rb @@ -78,8 +78,8 @@ module Sass new_filename = nil load_paths.each do |load_path| - new_filename ||= find_full_path("#{filename}.sass", [load_path]) unless was_scss - new_filename ||= find_full_path("#{filename}.scss", [load_path]) unless was_sass + new_filename ||= find_full_path("#{filename}.sass", load_path) unless was_scss + new_filename ||= find_full_path("#{filename}.scss", load_path) unless was_sass end return new_filename if new_filename @@ -137,7 +137,7 @@ END end end - def find_full_path(filename, load_paths) + def find_full_path(filename, load_path) partial_name = File.join(File.dirname(filename), "_#{File.basename(filename)}") if Pathname.new(filename).absolute? @@ -147,13 +147,9 @@ END return nil end - load_paths.each do |path| - [partial_name, filename].each do |name| - full_path = File.join(path, name) - if File.readable?(full_path) - return full_path - end - end + [partial_name, filename].each do |name| + full_path = File.join(load_path, name) + return full_path if File.readable?(full_path) end nil end From a5afd5bb4407f8a7b6b14a09be6e0ba45c82dad5 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:29:04 -0700 Subject: [PATCH 34/54] [Sass] Do a whitespace cleanup of StalenessChecker. --- lib/sass/plugin/staleness_checker.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index 61354604..d7d9d6a0 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -19,7 +19,7 @@ module Sass class << self attr_accessor :dependencies_cache end - + def initialize(dependencies = self.class.dependencies_cache) @dependencies = dependencies @@ -87,10 +87,10 @@ module Sass rescue Sass::SyntaxError => e [] # If the file has an error, we assume it has no dependencies end - + def self.stylesheet_needs_update?(css_file, template_file) new.stylesheet_needs_update?(css_file, template_file) end end end -end \ No newline at end of file +end From 399d1835e4795aca06ec9ffff0f271ec9708ad6b Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:29:37 -0700 Subject: [PATCH 35/54] [Sass] Clean up the class docs for StalenessChecker. --- lib/sass/plugin/staleness_checker.rb | 32 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index d7d9d6a0..46583033 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -1,18 +1,26 @@ module Sass module Plugin - # The class handles .s[ca]ss file staleness checks via their mtime timestamps. - # To speed things up 2 level of caches are employed: - # * a class-level @dependencies_cache storing @import paths, this is a long lived cache - # that is being reused by every StalenessChecker instance, - # * 2 class-level short lived @mtimes, @dependencies_stale caches that are only used by a single - # StalenessChecker instance. + # The class handles `.s[ca]ss` file staleness checks via their mtime timestamps. + # + # To speed things up two level of caches are employed: + # + # * A class-level dependency cache which stores @import paths for each file. + # This is a long-lived cache that is reused by every StalenessChecker instance. + # * Two short-lived instance-level caches, one for file mtimes + # and one for whether a file is stale during this particular run. + # These are only used by a single StalenessChecker instance. + # # Usage: - # * In case of a one-off staleness check of a single .s[ca]ss file a class level - # StalenessChecker.stylesheet_needs_update? method should be used. - # * In case of a series of checks (checking all the files for staleness) an instance should be created, - # as its caches should make the whole process significantly faster. - # WARNING: It is important that you do not hold on onto the instance for too long as its - # instance-level caches are never explicitly expired. + # + # * For a one-off staleness check of a single `.s[ca]ss` file, + # the class-level {stylesheet_needs_update?} method + # should be used. + # * For a series of staleness checks (e.g. checking all files for staleness) + # a StalenessChecker instance should be created, + # and the instance-level \{#stylesheet\_needs\_update?} method should be used. + # the caches should make the whole process significantly faster. + # *WARNING*: It is important not to retain the instance for too long, + # as its instance-level caches are never explicitly expired. class StalenessChecker @dependencies_cache = {} From a059d8e1e2c21356fd15e7e05c9d4c3e8ae77db6 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:33:08 -0700 Subject: [PATCH 36/54] [Sass] Get rid of the unnecessary argument to StalenessChecker. --- lib/sass/plugin/staleness_checker.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index 46583033..edea6196 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -28,8 +28,8 @@ module Sass attr_accessor :dependencies_cache end - def initialize(dependencies = self.class.dependencies_cache) - @dependencies = dependencies + def initialize + @dependencies = self.class.dependencies_cache # Entries in the following instance-level caches are never explicitly expired. # Instead they are supposed to automaticaly go out of scope when a series of staleness checks From f1551ef81b016896c53680a00ea608348b753461 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:43:01 -0700 Subject: [PATCH 37/54] [Sass] Fully document StalenessChecker. --- lib/sass/plugin/staleness_checker.rb | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/sass/plugin/staleness_checker.rb b/lib/sass/plugin/staleness_checker.rb index edea6196..7cc0f769 100644 --- a/lib/sass/plugin/staleness_checker.rb +++ b/lib/sass/plugin/staleness_checker.rb @@ -25,9 +25,12 @@ module Sass @dependencies_cache = {} class << self + # @private attr_accessor :dependencies_cache end + # Creates a new StalenessChecker + # for checking the staleness of several stylesheets at once. def initialize @dependencies = self.class.dependencies_cache @@ -37,6 +40,12 @@ module Sass @mtimes, @dependencies_stale = {}, {} end + # Returns whether or not a given CSS file is out of date + # and needs to be regenerated. + # + # @param css_file [String] The location of the CSS file to check. + # @param template_file [String] The location of the Sass or SCSS template + # that is compiled to `css_file`. def stylesheet_needs_update?(css_file, template_file) template_file = File.expand_path(template_file) @@ -49,6 +58,20 @@ module Sass end end + # Returns whether or not a given CSS file is out of date + # and needs to be regenerated. + # + # The distinction between this method and the instance-level \{#stylesheet\_needs\_update?} + # is that the instance method preserves mtime and stale-dependency caches, + # so it's better to use when checking multiple stylesheets at once. + # + # @param css_file [String] The location of the CSS file to check. + # @param template_file [String] The location of the Sass or SCSS template + # that is compiled to `css_file`. + def self.stylesheet_needs_update?(css_file, template_file) + new.stylesheet_needs_update?(css_file, template_file) + end + private def dependencies_stale?(template_file, css_mtime) @@ -95,10 +118,6 @@ module Sass rescue Sass::SyntaxError => e [] # If the file has an error, we assume it has no dependencies end - - def self.stylesheet_needs_update?(css_file, template_file) - new.stylesheet_needs_update?(css_file, template_file) - end end end end From 80209e7faf04cf9779d9db8459a84bfc65c209f6 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:51:18 -0700 Subject: [PATCH 38/54] [Sass] Fix some documentation bugs. --- lib/sass.rb | 2 +- lib/sass/environment.rb | 2 +- lib/sass/script/lexer.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sass.rb b/lib/sass.rb index 49078d3b..43fc0417 100644 --- a/lib/sass.rb +++ b/lib/sass.rb @@ -15,7 +15,7 @@ module Sass extend Haml::Version # A string representing the version of Sass. - # A more fine-grained representation is available from {Sass.version}. + # A more fine-grained representation is available from {Haml::Version#version Sass.version}. VERSION = version[:string] unless defined?(Sass::VERSION) end diff --git a/lib/sass/environment.rb b/lib/sass/environment.rb index 088cf172..271cb579 100644 --- a/lib/sass/environment.rb +++ b/lib/sass/environment.rb @@ -76,7 +76,7 @@ module Sass # The last element in the list is the most deeply-nested frame. # # @return [Array<{Symbol => Object}>] The stack frames, - # of the form passed to \{#push}. + # of the form passed to \{#push\_frame}. def stack @stack ||= @parent.stack end diff --git a/lib/sass/script/lexer.rb b/lib/sass/script/lexer.rb index 5f994c90..03e643a8 100644 --- a/lib/sass/script/lexer.rb +++ b/lib/sass/script/lexer.rb @@ -111,7 +111,7 @@ module Sass # A hash of regular expressions that are used for tokenizing strings. # - # The key is a [Symbol, Boolean] pair. + # The key is a `[Symbol, Boolean]` pair. # The symbol represents which style of quotation to use, # while the boolean represents whether or not the string # is following an interpolated segment. From 0e6c5983c593710066138ce642c0c93290bb975f Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:53:21 -0700 Subject: [PATCH 39/54] [Haml] Fix a weird infinite-recursion bug. --- doc-src/SASS_CHANGELOG.md | 3 +++ lib/haml/helpers/action_view_mods.rb | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 175ffd92..3b92b73a 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -15,6 +15,9 @@ {file:SASS_REFERENCE.md#full_exception `:full_exception option`} is enabled, print the full exception rather than raising it. +* Fix a bug with a weird interaction with Haml, DataMapper, and Rails 3 + that caused some tag helpers to go into infinite recursion. + ## 2.2.22 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.22). diff --git a/lib/haml/helpers/action_view_mods.rb b/lib/haml/helpers/action_view_mods.rb index e6806d7b..555e3906 100644 --- a/lib/haml/helpers/action_view_mods.rb +++ b/lib/haml/helpers/action_view_mods.rb @@ -125,9 +125,8 @@ module ActionView @template_object.send :is_haml? end - unless defined?(ActionView::Helpers) && defined?(ActionView::Helpers::ActiveRecordInstanceTag) - alias_method :content_tag_without_haml, :content_tag - alias_method :content_tag, :content_tag_with_haml + def content_tag(*args) + content_tag_with_haml(*args) end end From 6448f06da10a37e2fe94e0da2fd61aeca34332f2 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 16:59:30 -0700 Subject: [PATCH 40/54] [Haml] Add an RDFa doctype shortcut. --- doc-src/HAML_CHANGELOG.md | 2 ++ doc-src/HAML_REFERENCE.md | 4 ++++ lib/haml/precompiler.rb | 1 + 3 files changed, 7 insertions(+) diff --git a/doc-src/HAML_CHANGELOG.md b/doc-src/HAML_CHANGELOG.md index 1381195f..61707ec5 100644 --- a/doc-src/HAML_CHANGELOG.md +++ b/doc-src/HAML_CHANGELOG.md @@ -7,6 +7,8 @@ * Make {Haml::Helpers#capture_haml capture\_haml} faster when using `:ugly`. +* Add an `RDFa` doctype shortcut. + ## 3.0.0.beta.1 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.1). diff --git a/doc-src/HAML_REFERENCE.md b/doc-src/HAML_REFERENCE.md index b67477dc..95880e12 100644 --- a/doc-src/HAML_REFERENCE.md +++ b/doc-src/HAML_REFERENCE.md @@ -771,6 +771,10 @@ the following doctypes are supported: : XHTML Mobile 1.2
`` +`!!! RDFa` +: XHTML+RDFa 1.0
+ `` + When the [`:format`](#format) option is set to `:html4`, the following doctypes are supported: diff --git a/lib/haml/precompiler.rb b/lib/haml/precompiler.rb index d8e3852f..9d453ed2 100644 --- a/lib/haml/precompiler.rb +++ b/lib/haml/precompiler.rb @@ -905,6 +905,7 @@ END when "strict"; '' when "frameset"; '' when "mobile"; '' + when "rdfa"; '' when "basic"; '' else '' end From 506c3c158d4eb188517e98ac269f2961f8408435 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 17:08:39 -0700 Subject: [PATCH 41/54] [Sass] [Convert] Re-allow conversion from sass2. Oops. --- lib/haml/exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/haml/exec.rb b/lib/haml/exec.rb index 3731c9a1..ba0bdfeb 100644 --- a/lib/haml/exec.rb +++ b/lib/haml/exec.rb @@ -594,7 +594,7 @@ END 'By default, this is inferred from the input filename.', 'If there is none, defaults to css.') do |name| @options[:from] = name.downcase.to_sym - unless [:css, :scss, :sass].include?(@options[:from]) + unless [:css, :scss, :sass, :sass2].include?(@options[:from]) raise "Unknown format for sass-convert --from: #{name}" end end From b7b3df8cdfd0f8e50e1df52eda420280a6ae86bb Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 17:29:07 -0700 Subject: [PATCH 42/54] [Sass] [Indented] Strip out initial ' *' in loud comment lines. --- doc-src/SASS_CHANGELOG.md | 10 ++++++++++ lib/sass/engine.rb | 1 + test/sass/engine_test.rb | 12 ++++++++++++ 3 files changed, 23 insertions(+) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 155a77fb..89bcea39 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -58,6 +58,16 @@ Note that since underscores may still be used in place of hyphens when referring to mixins and variables, this won't cause any backwards-incompatibilities. +### Minor Changes + +Indented-syntax `/*` comments may now include `*` on lines beyond the first, +which will get stripped out of the output. +This means that the following will render nicely: + + /* Foo + * Bar + * Baz + #### Bug Fixes * Include `;` when rendering nested properties. diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 0efa5b83..761687c8 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -588,6 +588,7 @@ WARNING end return silent ? "//" : "/* */" if content.empty? + content.each {|l| l.gsub!(/^\* /, '')} content.map! {|l| (l.empty? ? "" : " ") + l} content.first.gsub!(/^ /, '') unless removed_first content.last.gsub!(%r{ ?\*/ *$}, '') diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index a510c387..6dd45136 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -1304,6 +1304,18 @@ foo { CSS end + def test_loud_comments_with_starred_lines + assert_equal(< Date: Sun, 11 Apr 2010 20:58:24 -0700 Subject: [PATCH 43/54] [Sass] [Convert] Convert comments to start with // or * in the indented syntax. Closes gh-122 --- doc-src/SASS_CHANGELOG.md | 7 +++++++ lib/sass/tree/comment_node.rb | 5 +++-- test/sass/conversion_test.rb | 30 +++++++++++++++--------------- test/sass/css2sass_test.rb | 6 +++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 89bcea39..34b2e9aa 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -58,6 +58,13 @@ Note that since underscores may still be used in place of hyphens when referring to mixins and variables, this won't cause any backwards-incompatibilities. +#### Sass Comment Format + +When converting to the indented syntax, +each line of comments past the first begins with either `//` (for Sass comments) +or ` *` (for CSS comments). +This prevents some whitespace errors. + ### Minor Changes Indented-syntax `/*` comments may now include `*` on lines beyond the first, diff --git a/lib/sass/tree/comment_node.rb b/lib/sass/tree/comment_node.rb index 0eaba137..0983f6af 100644 --- a/lib/sass/tree/comment_node.rb +++ b/lib/sass/tree/comment_node.rb @@ -59,10 +59,11 @@ module Sass::Tree else content.gsub!(/\n( \*|\/\/)/, "\n ") spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min + sep = silent ? "\n//" : "\n *" if spaces >= 2 - content + content.gsub(/\n /, sep) else - content.gsub(/\n#{' ' * spaces}/, "\n ") + content.gsub(/\n#{' ' * spaces}/, sep) end end diff --git a/test/sass/conversion_test.rb b/test/sass/conversion_test.rb index a84593a9..f925b330 100755 --- a/test/sass/conversion_test.rb +++ b/test/sass/conversion_test.rb @@ -251,9 +251,9 @@ SCSS assert_renders < Date: Sun, 11 Apr 2010 21:27:47 -0700 Subject: [PATCH 44/54] [Sass] Clean up some mixin arglist parsing. Closes gh-124 --- doc-src/SASS_CHANGELOG.md | 3 +++ lib/sass/script/parser.rb | 48 ++++++++++++++++++++------------------- test/sass/engine_test.rb | 19 ++++++++++++---- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 34b2e9aa..6c5b2591 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -102,6 +102,9 @@ This means that the following will render nicely: * Prevent multiline CSS selectors from getting cut off in certain rare cases. +* Improve the parsing of mixin argument lists. + This mostly means that error messages will be clearer. + ### `@import` in Sass The Sass `@import` statement now allows non-CSS files to be specified with quotes, diff --git a/lib/sass/script/parser.rb b/lib/sass/script/parser.rb index fc38cbc8..64acc36e 100644 --- a/lib/sass/script/parser.rb +++ b/lib/sass/script/parser.rb @@ -97,12 +97,7 @@ module Sass # @return [Array] The root nodes of the arguments. # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript def parse_mixin_definition_arglist - args = [] - - if try_tok(:lparen) - args = defn_arglist(false) || args - assert_tok(:rparen) - end + args = defn_arglist!(false) assert_done args.each do |k, v| @@ -239,26 +234,33 @@ RUBY end end - def defn_arglist(must_have_default) - line = @lexer.line - offset = @lexer.offset + 1 - return unless c = try_tok(:const) - var = Script::Variable.new(c.value) - if tok = (try_tok(:colon) || try_tok(:single_eq)) - val = assert_expr(:concat) + def defn_arglist!(must_have_default) + return [] unless try_tok(:lparen) + return [] if try_tok(:rparen) + res = [] + loop do + line = @lexer.line + offset = @lexer.offset + 1 + c = assert_tok(:const) + var = Script::Variable.new(c.value) + if tok = (try_tok(:colon) || try_tok(:single_eq)) + val = assert_expr(:concat) - if tok.type == :single_eq - val.context = :equals - val.options = @options - Script.equals_warning("mixin argument defaults", "$#{c.value}", - val.to_sass, false, line, offset, @options[:filename]) + if tok.type == :single_eq + val.context = :equals + val.options = @options + Script.equals_warning("mixin argument defaults", "$#{c.value}", + val.to_sass, false, line, offset, @options[:filename]) + end + must_have_default = true + elsif must_have_default + raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.") end - elsif must_have_default - raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.") + res << [var, val] + break unless try_tok(:comma) end - - return [[var, val]] unless try_tok(:comma) - [[var, val], *defn_arglist(val)] + assert_tok(:rparen) + res end def fn_arglist diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index 6dd45136..cea6a672 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -81,10 +81,10 @@ MSG "a\n b: c\na\n d: e" => ["The line was indented 2 levels deeper than the previous line.", 4], "a\n b: c\n a\n d: e" => ["The line was indented 3 levels deeper than the previous line.", 4], "a\n \tb: c" => ["Indentation can't use both tabs and spaces.", 2], - "=a(" => 'Invalid CSS after "(": expected ")", was ""', - "=a(b)" => 'Invalid CSS after "(": expected ")", was "b)"', - "=a(,)" => 'Invalid CSS after "(": expected ")", was ",)"', - "=a(!)" => 'Invalid CSS after "(": expected ")", was "!)"', + "=a(" => 'Invalid CSS after "(": expected variable (e.g. $foo), was ""', + "=a(b)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was "b)"', + "=a(,)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was ",)"', + "=a($)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was "$)"', "=a($foo bar)" => 'Invalid CSS after "($foo ": expected ")", was "bar)"', "=foo\n bar: baz\n+foo" => ["Properties aren't allowed at the root of a document.", 2], "a-\#{$b\n c: d" => ['Invalid CSS after "a-#{$b": expected "}", was ""', 1], @@ -940,7 +940,7 @@ SASS def test_equals_warning_for_mixin_args assert_warning(< Date: Sun, 11 Apr 2010 21:37:09 -0700 Subject: [PATCH 45/54] Bump VERSION to 2.2.23. --- VERSION | 2 +- doc-src/HAML_CHANGELOG.md | 4 +++- doc-src/SASS_CHANGELOG.md | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 255642e7..2f09892d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.22 +2.2.23 diff --git a/doc-src/HAML_CHANGELOG.md b/doc-src/HAML_CHANGELOG.md index 09f66ff0..0ac7f3b3 100644 --- a/doc-src/HAML_CHANGELOG.md +++ b/doc-src/HAML_CHANGELOG.md @@ -3,7 +3,9 @@ * Table of contents {:toc} -## 2.2.23 (Unreleased) +## 2.2.23 + +[Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.23). * Don't crash when `rake gems` is run in Rails with Haml installed. Thanks to [Florian Frank](http://github.com/flori). diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 3b92b73a..7455fc29 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -3,7 +3,9 @@ * Table of contents {:toc} -## 2.2.23 (Unreleased) +## 2.2.23 + +[Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.23). * Don't crash when `rake gems` is run in Rails with Sass installed. Thanks to [Florian Frank](http://github.com/flori). From 7fe6f10cd8357949a5194c4ad99abf7b38176cc1 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 11 Apr 2010 21:43:59 -0700 Subject: [PATCH 46/54] Bump VERSION to 3.0.0.beta.2. --- VERSION | 2 +- doc-src/HAML_CHANGELOG.md | 2 ++ doc-src/SASS_CHANGELOG.md | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index a060c317..1121fd69 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0.beta.1 +3.0.0.beta.2 diff --git a/doc-src/HAML_CHANGELOG.md b/doc-src/HAML_CHANGELOG.md index 1a8fafcc..6251a82a 100644 --- a/doc-src/HAML_CHANGELOG.md +++ b/doc-src/HAML_CHANGELOG.md @@ -5,6 +5,8 @@ ## 3.0.0.beta.2 +[Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). + * Make {Haml::Helpers#capture_haml capture\_haml} faster when using `:ugly`. * Add an `RDFa` doctype shortcut. diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index f88774db..6a4bd971 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -3,7 +3,9 @@ * Table of contents {:toc} -## 3.0.0.beta.2 (Unreleased) +## 3.0.0.beta.2 + +[Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). ### New Sass Functions for Introspection From 789142f2e009fdb52ee651d6a15fe59647e75df0 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Mon, 12 Apr 2010 01:00:32 -0700 Subject: [PATCH 47/54] [Sass] Add a changelog entry for the Sass::Plugin improvements. I feel stupid for not adding this before the beta 2 release. --- doc-src/SASS_CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 6a4bd971..3b66906a 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -7,6 +7,16 @@ [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). +### Stylesheet Updating Speed + +Several caching layers were added to Sass's stylesheet updater. +This means that it should run significantly faster. +This benefit will be seen by people using Sass in development mode +with Rails, Rack, and Merb, +as well as people using `sass --watch` from the command line, +and to a lesser (but still significant) extent `sass --update`. +Thanks to [thedarkone](http://github.com/thedarkone). + ### New Sass Functions for Introspection Several new functions were added to make it easier to have From 3fadad2803ef48ddb885fdf4609d35a2b4ac968e Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Mon, 12 Apr 2010 15:03:13 -0700 Subject: [PATCH 48/54] [Sass] Get rid of the note on @import in the changelog, since it doesn't actually work. --- doc-src/SASS_CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 3b66906a..5eca8702 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -117,12 +117,6 @@ This means that the following will render nicely: * Improve the parsing of mixin argument lists. This mostly means that error messages will be clearer. -### `@import` in Sass - -The Sass `@import` statement now allows non-CSS files to be specified with quotes, -for similarity with the SCSS syntax. For example, `@import "foo.sass"` -Will now import the `foo.sass` file, rather than compiling to `@import "foo.sass";`. - ### CSS Parsing The proprietary Microsoft `alpha(opacity=20)` syntax is now correctly parsed. From f59705997cee2a10fafbd7100285c18339a9adfe Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Tue, 13 Apr 2010 10:29:59 -0700 Subject: [PATCH 49/54] [Sass] [Indented] Allow @import to import quoted files. Again. --- doc-src/SASS_CHANGELOG.md | 8 ++++++++ lib/sass/engine.rb | 6 +++++- test/sass/conversion_test.rb | 4 ++-- test/sass/templates/import.sass | 3 ++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 5eca8702..8893a201 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -3,6 +3,14 @@ * Table of contents {:toc} +## 3.0.0.beta.3 (Unreleased) + +### `@import` in Sass + +The Sass `@import` statement now allows non-CSS files to be specified with quotes, +for similarity with the SCSS syntax. For example, `@import "foo.sass"` +Will now import the `foo.sass` file, rather than compiling to `@import "foo.sass";`. + ## 3.0.0.beta.2 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 761687c8..acde61ef 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -467,9 +467,13 @@ WARNING # If value begins with url( or ", # it's a CSS @import rule and we don't want to touch it. - if directive == "import" && value !~ /^(url\(|["'])/ + if directive == "import" raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.", :line => @line + 1) unless line.children.empty? + if (match = value.match(Sass::SCSS::RX::STRING) || value.match(Sass::SCSS::RX::URI)) && + !match.post_match.strip.empty? && match.post_match.strip[0] != ?, + return Tree::DirectiveNode.new("@import #{value}") + end value.split(/,\s*/).map do |f| f = $1 || $2 || $3 if f =~ Sass::SCSS::RX::STRING || f =~ Sass::SCSS::RX::URI Tree::ImportNode.new(f) diff --git a/test/sass/conversion_test.rb b/test/sass/conversion_test.rb index f925b330..a3dad252 100755 --- a/test/sass/conversion_test.rb +++ b/test/sass/conversion_test.rb @@ -595,8 +595,8 @@ SCSS end def test_import_as_directive_in_sass - assert_sass_to_sass '@import "foo.css"' - assert_sass_to_sass '@import url(foo.css)' + assert_equal "@import foo.css\n", to_sass('@import "foo.css"') + assert_equal "@import foo.css\n", to_sass('@import url(foo.css)') end def test_import_as_directive_in_scss diff --git a/test/sass/templates/import.sass b/test/sass/templates/import.sass index e502cc7b..79646689 100644 --- a/test/sass/templates/import.sass +++ b/test/sass/templates/import.sass @@ -3,7 +3,8 @@ $preconst: hello =premixin pre-mixin: here -@import importee.sass, scss_importee, "basic.sass", basic.css, ../results/complex.css, url(partial.sass) +@import importee.sass, scss_importee, "basic.sass", basic.css, ../results/complex.css +@import url(partial.sass) nonimported :myconst $preconst From e58d7182a3f9699c433fdd45ba0b2e2e23a1c030 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Tue, 13 Apr 2010 10:56:48 -0700 Subject: [PATCH 50/54] [Sass] Fix some comment stuff. --- doc-src/SASS_CHANGELOG.md | 6 +++ lib/sass/engine.rb | 6 ++- lib/sass/tree/comment_node.rb | 2 +- test/sass/conversion_test.rb | 86 +++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 8893a201..40a4d6fe 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -11,6 +11,12 @@ The Sass `@import` statement now allows non-CSS files to be specified with quote for similarity with the SCSS syntax. For example, `@import "foo.sass"` Will now import the `foo.sass` file, rather than compiling to `@import "foo.sass";`. +### Bug Fixes + +* Make sure nested comments use the proper prefix when `sass-convert` outputs Sass. + +* Allow comments to begin with ` *` in all cases. + ## 3.0.0.beta.2 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index acde61ef..0a4bc4fb 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -234,7 +234,7 @@ module Sass end comment_tab_str ||= line_tab_str - if try_comment(line, lines.last, tab_str * (lines.last.tabs + 1), comment_tab_str, index) + if try_comment(line, lines.last, tab_str * lines.last.tabs, comment_tab_str, index) next else comment_tab_str = nil @@ -256,7 +256,9 @@ END def try_comment(line, last, tab_str, comment_tab_str, index) return unless last && last.comment? - return unless line =~ /^#{tab_str}/ + # Nested comment stuff must be at least one whitespace char deeper + # than the normal indentation + return unless line =~ /^#{tab_str}\s/ unless line =~ /^(?:#{comment_tab_str})(.*)$/ raise SyntaxError.new(< index) Inconsistent indentation: diff --git a/lib/sass/tree/comment_node.rb b/lib/sass/tree/comment_node.rb index 0983f6af..26ffcd37 100644 --- a/lib/sass/tree/comment_node.rb +++ b/lib/sass/tree/comment_node.rb @@ -67,8 +67,8 @@ module Sass::Tree end end - content.gsub!(/^/, ' ' * tabs) content.gsub!(/\A\/\*/, '//') if silent + content.gsub!(/^/, ' ' * tabs) content.rstrip + "\n" end diff --git a/test/sass/conversion_test.rb b/test/sass/conversion_test.rb index a3dad252..ce3f2529 100755 --- a/test/sass/conversion_test.rb +++ b/test/sass/conversion_test.rb @@ -286,6 +286,50 @@ foo bar SASS end + def test_nested_silent_comments + assert_renders < Date: Wed, 14 Apr 2010 14:32:46 -0700 Subject: [PATCH 51/54] Bump VERSION to 3.0.0.beta.3. --- VERSION | 2 +- doc-src/SASS_CHANGELOG.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 1121fd69..d641a714 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0.beta.2 +3.0.0.beta.3 diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 40a4d6fe..68f2dd66 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -3,7 +3,9 @@ * Table of contents {:toc} -## 3.0.0.beta.3 (Unreleased) +## 3.0.0.beta.3 + +[Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.3). ### `@import` in Sass From 0d01a698f717e9f213754ee32d72aa6d15929421 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Wed, 14 Apr 2010 14:38:00 -0700 Subject: [PATCH 52/54] [Haml] Add beta 3 to the changelog. --- doc-src/HAML_CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc-src/HAML_CHANGELOG.md b/doc-src/HAML_CHANGELOG.md index 6251a82a..4bed4419 100644 --- a/doc-src/HAML_CHANGELOG.md +++ b/doc-src/HAML_CHANGELOG.md @@ -3,6 +3,12 @@ * Table of contents {:toc} +## 3.0.0.beta.3 + +[Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.3). + +There were no changes made to Haml between beta 2 and beta 3. + ## 3.0.0.beta.2 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.2). From 45cb35a541eb4ff59cd32b2c87854edaaedd450c Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Fri, 16 Apr 2010 13:54:11 -0700 Subject: [PATCH 53/54] [Sass] Allow variables to be used in url(). Closes gh-126 --- doc-src/SASS_CHANGELOG.md | 6 ++++++ lib/sass/scss/rx.rb | 2 +- test/sass/script_test.rb | 7 +++++++ test/sass/scss/rx_test.rb | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index 68f2dd66..b4fbb6b5 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -3,6 +3,12 @@ * Table of contents {:toc} +## 3.0.0.beta.4 + +### Bug Fixes + +* Variables are now allowed as arguments to `url()`. + ## 3.0.0.beta.3 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.3). diff --git a/lib/sass/scss/rx.rb b/lib/sass/scss/rx.rb index 9612391a..0b860a64 100644 --- a/lib/sass/scss/rx.rb +++ b/lib/sass/scss/rx.rb @@ -65,7 +65,7 @@ module Sass NAME = /#{NMCHAR}+/ NUM = /[0-9]+|[0-9]*.[0-9]+/ STRING = /#{STRING1}|#{STRING2}/ - URL = /((?:[!#%$&*-~]|#{NONASCII}|#{ESCAPE})*)/ + URL = /((?:[!#%&*-~]|#{NONASCII}|#{ESCAPE})*)/ W = /[ \t\r\n\f]*/ # This is more liberal than the spec's definition, diff --git a/test/sass/script_test.rb b/test/sass/script_test.rb index 3d1e0c1b..3f0458d0 100755 --- a/test/sass/script_test.rb +++ b/test/sass/script_test.rb @@ -143,6 +143,13 @@ SASS assert_equal "Options defined!", resolve("assert_options(round(1.2))") end + def test_dynamic_url + assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => Sass::Script::String.new("foo-bar"))) + assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => Sass::Script::String.new("foo-bar"), 'bar' => Sass::Script::String.new("baz"))) + assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => Sass::Script::String.new("baz"))) + assert_equal "url(foo bar)", resolve("url(foo bar)") + end + def test_hyphenated_variables assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::String.new("a-b")))) end diff --git a/test/sass/scss/rx_test.rb b/test/sass/scss/rx_test.rb index 7b6d839d..2d017c4b 100755 --- a/test/sass/scss/rx_test.rb +++ b/test/sass/scss/rx_test.rb @@ -93,7 +93,7 @@ class ScssRxTest < Test::Unit::TestCase assert_match URI, 'url("foo bar)")' assert_match URI, "url('foo bar)')" assert_match URI, 'url( "foo bar)" )' - assert_match URI, "url(!#\$%&**+,-./0123456789~)" + assert_match URI, "url(!#\\%&**+,-./0123456789~)" end def test_invalid_uri From c2e99a09f5df9906711addc4f9b2fc478753a8a9 Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sat, 17 Apr 2010 14:27:40 -0700 Subject: [PATCH 54/54] [Sass] Allow interpolation in url(). --- doc-src/SASS_CHANGELOG.md | 2 ++ lib/sass/script/css_lexer.rb | 7 ++++++- lib/sass/script/lexer.rb | 14 +++++++++++--- lib/sass/scss/rx.rb | 3 ++- test/sass/script_test.rb | 6 ++++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/doc-src/SASS_CHANGELOG.md b/doc-src/SASS_CHANGELOG.md index b4fbb6b5..acd5cb3e 100644 --- a/doc-src/SASS_CHANGELOG.md +++ b/doc-src/SASS_CHANGELOG.md @@ -9,6 +9,8 @@ * Variables are now allowed as arguments to `url()`. +* `#{}` interpolation is now allowed within `url()`. + ## 3.0.0.beta.3 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0.beta.3). diff --git a/lib/sass/script/css_lexer.rb b/lib/sass/script/css_lexer.rb index 2ca028e6..125e30d0 100644 --- a/lib/sass/script/css_lexer.rb +++ b/lib/sass/script/css_lexer.rb @@ -5,7 +5,12 @@ module Sass important || super end - def string(*args) + def string(re, *args) + if re == :uri + return unless uri = scan(URI) + return [:string, Script::String.new(uri)] + end + return unless scan(STRING) [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)] end diff --git a/lib/sass/script/lexer.rb b/lib/sass/script/lexer.rb index 03e643a8..9297a7ec 100644 --- a/lib/sass/script/lexer.rb +++ b/lib/sass/script/lexer.rb @@ -120,6 +120,8 @@ module Sass [:single, false] => string_re("'", "'"), [:double, true] => string_re('', '"'), [:single, true] => string_re('', "'"), + [:uri, false] => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|(?=#\{))/, + [:uri, true] => /(#{URLCHAR}*?)(#{W}\)|(?=#\{))/, } # @param str [String, StringScanner] The source text to lex @@ -216,8 +218,8 @@ module Sass end variable || string(:double, false) || string(:single, false) || number || - color || bool || raw(URI) || raw(UNICODERANGE) || special_fun || - ident_op || ident || op + color || bool || string(:uri, false) || raw(UNICODERANGE) || + special_fun || ident_op || ident || op end def variable @@ -243,7 +245,13 @@ module Sass def string(re, open) return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]]) @interpolation_stack << re if @scanner[2].empty? # Started an interpolated section - [:string, Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)] + str = + if re == :uri + Script::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2].empty?}") + else + Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string) + end + [:string, str] end def number diff --git a/lib/sass/scss/rx.rb b/lib/sass/scss/rx.rb index 0b860a64..0496afcc 100644 --- a/lib/sass/scss/rx.rb +++ b/lib/sass/scss/rx.rb @@ -65,7 +65,8 @@ module Sass NAME = /#{NMCHAR}+/ NUM = /[0-9]+|[0-9]*.[0-9]+/ STRING = /#{STRING1}|#{STRING2}/ - URL = /((?:[!#%&*-~]|#{NONASCII}|#{ESCAPE})*)/ + URLCHAR = /[!#%&*-~]|#{NONASCII}|#{ESCAPE}/ + URL = /(#{URLCHAR}*)/ W = /[ \t\r\n\f]*/ # This is more liberal than the spec's definition, diff --git a/test/sass/script_test.rb b/test/sass/script_test.rb index 3f0458d0..11e7b8b2 100755 --- a/test/sass/script_test.rb +++ b/test/sass/script_test.rb @@ -150,6 +150,12 @@ SASS assert_equal "url(foo bar)", resolve("url(foo bar)") end + def test_url_with_interpolation + assert_equal "url(http://sass-lang.com/images/foo-bar)", resolve("url(http://sass-lang.com/images/\#{foo-bar})") + assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve("url('http://sass-lang.com/images/\#{foo-bar}')") + assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve('url("http://sass-lang.com/images/#{foo-bar}")') + end + def test_hyphenated_variables assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::String.new("a-b")))) end