diff options
author | Dan DeLeo <danielsdeleo@mac.com> | 2009-11-14 17:33:38 -0700 |
---|---|---|
committer | Dan DeLeo <danielsdeleo@mac.com> | 2009-11-23 20:06:04 -0700 |
commit | f6812e0814a611f9e4548913fa76cb8b9a6c6f0e (patch) | |
tree | cf3a981398040db5f825b56b651fa68c0795b1bf /chef | |
parent | 2d03e74e0b12ef2a0f15a76033c2eee7b252a0f5 (diff) | |
download | chef-f6812e0814a611f9e4548913fa76cb8b9a6c6f0e.tar.gz |
stepable iterator gives execution control
StepableIterator iterates over an array, but also allows execution to
be paused, resumed, skipped forward and back, rewound, and stepped
through
Diffstat (limited to 'chef')
-rw-r--r-- | chef/lib/chef/resource_collection.rb | 19 | ||||
-rw-r--r-- | chef/lib/chef/resource_collection/stepable_iterator.rb | 153 | ||||
-rw-r--r-- | chef/spec/unit/resource_collection/stepable_iterator_spec.rb | 133 |
3 files changed, 296 insertions, 9 deletions
diff --git a/chef/lib/chef/resource_collection.rb b/chef/lib/chef/resource_collection.rb index 7681e630a6..8941683776 100644 --- a/chef/lib/chef/resource_collection.rb +++ b/chef/lib/chef/resource_collection.rb @@ -67,23 +67,24 @@ class Chef end def push(*args) - args.flatten.each do |a| - is_chef_resource(a) - @resources.push(a) - @resources_by_name[a.to_s] = @resources.length - 1 + args.flatten.each do |arg| + is_chef_resource(arg) + @resources.push(arg) + @resources_by_name[arg.to_s] = @resources.length - 1 end end def each - @resources.each do |r| - yield r + @resources.each do |resource| + yield resource end end - def execute_each_resource - @resources.each_with_index do |r, idx| + def execute_each_resource(&resource_exec_block) + @iterator = StepableIterator.for_collection(@resources) + @iterator.each_with_index do |resource, idx| @insert_after_idx = idx - yield r + yield resource end end diff --git a/chef/lib/chef/resource_collection/stepable_iterator.rb b/chef/lib/chef/resource_collection/stepable_iterator.rb new file mode 100644 index 0000000000..b0770977df --- /dev/null +++ b/chef/lib/chef/resource_collection/stepable_iterator.rb @@ -0,0 +1,153 @@ +# Author:: Daniel DeLeo (<dan@kallistec.com>) +# Copyright:: Copyright (c) 2009 Daniel DeLeo +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class ResourceCollection + class StepableIterator + include Singleton + + def self.for_collection(new_collection) + instance.reset! + instance.collection = new_collection + instance + end + + def self.pause + instance.pause + instance + end + + def self.resume + instance.resume + instance + end + + def self.rewind + instance.rewind + instance + end + + def self.skip_back(*args) + instance.skip_back(*args) + instance + end + + def self.skip_forward(*args) + instance.skip_forward(*args) + instance + end + + def self.step + instance.step + instance + end + + attr_accessor :collection + attr_reader :position + + def initialize + reset! + end + + def reset! + @paused = false + @collection = [] + end + + def size + collection.size + end + + def each(&block) + reset_iteration(block) + @iterator_type = :element + iterate + end + + def each_index(&block) + reset_iteration(block) + @iterator_type = :index + iterate + end + + def each_with_index(&block) + reset_iteration(block) + @iterator_type = :element_with_index + iterate + end + + def paused? + @paused + end + + def pause + @paused = true + end + + def resume + @paused = false + iterate + end + + def rewind + @position = 0 + end + + def skip_back(skips=1) + @position -= skips + end + + def skip_forward(skips=1) + @position += skips + end + + def step + call_iterator_block + @position += 1 + end + + private + + def reset_iteration(iterator_block) + @iterator_block = iterator_block + @position = 0 + @paused = false + end + + def iterate + while @position < size && !paused? + step + end + collection + end + + def call_iterator_block + case @iterator_type + when :element + @iterator_block.call(collection[@position]) + when :index + @iterator_block.call(@position) + when :element_with_index + @iterator_block.call(collection[@position], @position) + else + raise "42error: someone forgot to set @iterator_type, wtf?" + end + end + + end + end +end
\ No newline at end of file diff --git a/chef/spec/unit/resource_collection/stepable_iterator_spec.rb b/chef/spec/unit/resource_collection/stepable_iterator_spec.rb new file mode 100644 index 0000000000..03d1c4e0ed --- /dev/null +++ b/chef/spec/unit/resource_collection/stepable_iterator_spec.rb @@ -0,0 +1,133 @@ +# Author:: Daniel DeLeo (<dan@kallistec.com>) +# Copyright:: Copyright (c) 2009 Daniel DeLeo +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) + +describe Chef::ResourceCollection::StepableIterator do + CRSI = Chef::ResourceCollection::StepableIterator + + before do + CRSI.instance.reset! + end + + it "has an empty array for its collection by default" do + CRSI.instance.collection.should == [] + end + + describe "doing basic iteration" do + before do + @simple_collection = [1,2,3,4] + @iterator = CRSI.for_collection(@simple_collection) + end + + it "re-initializes the instance with a collection" do + @iterator.collection.should equal @simple_collection + @iterator.size.should == 4 + end + + it "iterates over the collection" do + sum = 0 + @iterator.each do |int| + sum += int + end + sum.should == 10 + end + + it "iterates over the collection with each_index" do + collected_by_index = [] + @iterator.each_index do |idx| + collected_by_index << @simple_collection[idx] + end + collected_by_index.should == @simple_collection + collected_by_index.should_not equal @simple_collection + end + + it "iterates over the collection with index and element" do + collected = {} + @iterator.each_with_index do |element, index| + collected[index] = element + end + collected.should == {0=>1, 1=>2, 2=>3, 3=>4} + end + + end + + describe "pausing and resuming iteration" do + + before do + @collection = [] + @snitch_var = nil + @collection << lambda { @snitch_var = 23 } + @collection << lambda { CRSI.pause } + @collection << lambda { @snitch_var = 42 } + + @iterator = CRSI.for_collection(@collection) + @iterator.each { |proc| proc.call } + end + + it "allows the iteration to be paused" do + @snitch_var.should == 23 + end + + it "allows the iteration to be resumed" do + @snitch_var.should == 23 + @iterator.resume + @snitch_var.should == 42 + end + + it "allows iteration to be rewound" do + @iterator.skip_back(2) + @iterator.resume + @snitch_var.should == 23 + @iterator.resume + @snitch_var.should == 42 + end + + it "allows iteration to be fast forwarded" do + @iterator.skip_forward + @iterator.resume + @snitch_var.should == 23 + end + + it "allows iteration to be rewound" do + @snitch_var = nil + @iterator.rewind + @iterator.position.should == 0 + @iterator.resume + @snitch_var.should == 23 + end + + it "allows iteration to be stepped" do + @snitch_var = nil + @iterator.rewind + @iterator.step + @iterator.position.should == 1 + @snitch_var.should == 23 + end + + it "should work correctly when elements are added to the collection during iteration" do + @collection.insert(2, lambda { @snitch_var = 815}) + @collection.insert(3, lambda { CRSI.pause }) + @iterator.resume + @snitch_var.should == 815 + @iterator.resume + @snitch_var.should == 42 + end + + end + +end
\ No newline at end of file |