diff --git a/Gemfile b/Gemfile index 05cbb03e..13933d99 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,7 @@ source 'https://rubygems.org' gemspec gem 'stackprof', platforms: :mri_21 + +group :test do + gem 'spy', '0.4.1' +end diff --git a/History.md b/History.md index e56b3c55..881e8853 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,7 @@ ## 3.0.0 / not yet released / branch "master" * ... +* Optimize checking for block interrupts to reduce object allocation #380 [Jason Hiltz-Laforge, jasonhl] * Properly set context rethrow_errors on render! #349 [Thierry Joyal, tjoyal] * Fix broken rendering of variables which are equal to false, see #345 [Florian Weingarten, fw42] * Remove ActionView template handler [Dylan Thacker-Smith, dylanahsmith] diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index a35dcf2e..36ff7a84 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -73,7 +73,7 @@ module Liquid # are there any not handled interrupts? def has_interrupt? - @interrupts.any? + !@interrupts.empty? end # push an interrupt to the stack. this interrupt is considered not handled. diff --git a/test/test_helper.rb b/test/test_helper.rb index f97b51f1..3f02d427 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,6 +2,7 @@ require 'test/unit' require 'test/unit/assertions' +require 'spy/integration' $:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')) require 'liquid.rb' diff --git a/test/unit/context_unit_test.rb b/test/unit/context_unit_test.rb index 8f4d6ed0..bb5bf02c 100644 --- a/test/unit/context_unit_test.rb +++ b/test/unit/context_unit_test.rb @@ -70,6 +70,10 @@ class ContextUnitTest < Test::Unit::TestCase @context = Liquid::Context.new end + def teardown + Spy.teardown + end + def test_variables @context['string'] = 'string' assert_equal 'string', @context['string'] @@ -457,4 +461,16 @@ class ContextUnitTest < Test::Unit::TestCase assert_kind_of CategoryDrop, @context['category'] assert_equal @context, @context['category'].context end + + def test_use_empty_instead_of_any_in_interrupt_handling_to_avoid_lots_of_unnecessary_object_allocations + mock_any = Spy.on_instance_method(Array, :any?) + mock_empty = Spy.on_instance_method(Array, :empty?) + mock_has_interrupt = Spy.on(@context, :has_interrupt?).and_call_through + + @context.has_interrupt? + + refute mock_any.has_been_called? + assert mock_empty.has_been_called? + end + end # ContextTest