From b935a70694f544f0b235ed04cde4cccd0c71bc6f Mon Sep 17 00:00:00 2001 From: Nathan Weizenbaum Date: Sun, 5 Sep 2010 17:38:27 -0700 Subject: [PATCH] [Sass] Add support for dumping certain Tree::Node options. --- lib/haml/util.rb | 29 +++++++++++++++++++++++++++++ lib/sass/cache_store.rb | 5 ++--- lib/sass/files.rb | 3 ++- lib/sass/tree/node.rb | 17 +++++++++++++++++ test/haml/util_test.rb | 21 +++++++++++++++++++++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/lib/haml/util.rb b/lib/haml/util.rb index 9593a1f9..9762c9d3 100644 --- a/lib/haml/util.rb +++ b/lib/haml/util.rb @@ -269,6 +269,35 @@ module Haml version_gt(v1, v2) || !version_gt(v2, v1) end + # A wrapper for `Marshal.dump` that calls `#_before_dump` on the object + # before dumping it, `#_after_dump` afterwards. + # It also calls `#_around_dump` and passes it a block in which the object is dumped. + # + # If any of these methods are undefined, they are not called. + # + # @param obj [Object] The object to dump. + # @return [String] The dumped data. + def dump(obj) + obj._before_dump if obj.respond_to?(:_before_dump) + return Marshal.dump(obj) unless obj.respond_to?(:_around_dump) + res = nil + obj._around_dump {res = Marshal.dump(obj)} + res + ensure + obj._after_dump if obj.respond_to?(:_after_dump) + end + + # A wrapper for `Marshal.load` that calls `#_after_load` on the object + # after loading it, if it's defined. + # + # @param data [String] The data to load. + # @return [Object] The loaded object. + def load(data) + obj = Marshal.load(data) + obj._after_load if obj.respond_to?(:_after_load) + obj + end + # Silence all output to STDERR within a block. # # @yield A block in which no output will be printed to STDERR diff --git a/lib/sass/cache_store.rb b/lib/sass/cache_store.rb index 74d07012..25e05bbc 100644 --- a/lib/sass/cache_store.rb +++ b/lib/sass/cache_store.rb @@ -49,8 +49,7 @@ module Sass def store(key, sha, root) orig_options = root.options begin - root.options = {} - _store_(key, Sass::VERSION, sha, Marshal.dump(root)) + _store_(key, Sass::VERSION, sha, Haml::Util.dump(root)) ensure root.options = orig_options end @@ -63,7 +62,7 @@ module Sass # @return [Sass::Tree::RootNode] The root node. def retrieve(key, sha) contents = _retrieve_(key, Sass::VERSION, sha) - Marshal.load(contents) if contents + Haml::Util.load(contents) if contents rescue EOFError, TypeError, ArgumentError => e raise Haml::Util.haml_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}" diff --git a/lib/sass/files.rb b/lib/sass/files.rb index bc56c273..0bbbc142 100644 --- a/lib/sass/files.rb +++ b/lib/sass/files.rb @@ -29,7 +29,8 @@ module Sass sha = Digest::SHA1.hexdigest(sass_file.contents) if root = options[:cache_store].retrieve(key, sha) - root.options = options.merge(:filename => sass_file.filename) + root.options = root.options.merge( + options.merge(:filename => sass_file.filename)) return root end end diff --git a/lib/sass/tree/node.rb b/lib/sass/tree/node.rb index cf525ae1..bdf3d0a5 100644 --- a/lib/sass/tree/node.rb +++ b/lib/sass/tree/node.rb @@ -244,6 +244,23 @@ module Sass to_src(tabs, opts, :scss) end + # Names of options that are saved when the node is serialized and cached. + # + # @type [Array] + SAVED_OPTIONS = [] + + # Ensures that only {SAVED_OPTIONS} get saved. + def _around_dump + old_options = @options + @options = {} + SAVED_OPTIONS.each do |opt| + @options[opt] = old_options[opt] + end + yield + ensure + options = old_options + end + protected # Computes the CSS corresponding to this particular Sass node. diff --git a/test/haml/util_test.rb b/test/haml/util_test.rb index c3168112..e6cff556 100755 --- a/test/haml/util_test.rb +++ b/test/haml/util_test.rb @@ -5,6 +5,19 @@ require 'pathname' class UtilTest < Test::Unit::TestCase include Haml::Util + class Dumpable + attr_reader :arr + def initialize; @arr = []; end + def _before_dump; @arr << :before; end + def _after_dump; @arr << :after; end + def _around_dump + @arr << :around_before + yield + @arr << :around_after + end + def _after_load; @arr << :loaded; end + end + def test_scope assert(File.exist?(scope("Rakefile"))) end @@ -240,6 +253,14 @@ class UtilTest < Test::Unit::TestCase assert(!version_gt(v2, v1), "Expected #{v2} = #{v1}") end + def test_dump_and_load + obj = Dumpable.new + data = dump(obj) + assert_equal([:before, :around_before, :around_after, :after], obj.arr) + obj2 = load(data) + assert_equal([:before, :around_before, :loaded], obj2.arr) + end + def test_def_static_method klass = Class.new def_static_method(klass, :static_method, [:arg1, :arg2],