diff --git a/lib/time_ext/iterations.rb b/lib/time_ext/iterations.rb index 6cd4112..1144237 100644 --- a/lib/time_ext/iterations.rb +++ b/lib/time_ext/iterations.rb @@ -8,12 +8,19 @@ module TimeExt if block_given? units = [:year, :month, :day, :hour, :min, :sec, :usec] parent_unit = units[units.index(unit)-1] - @until ||= (!parent_unit.nil?) ? self.send("#{parent_unit}s_since", 1) : self.send("#{unit}s_since", 1) - time = self.clone + if @of_the.nil? + time = self.clone + @until ||= (!parent_unit.nil?) ? self.send("#{parent_unit}s_since", 1) : self.send("#{unit}s_since", 1) + else + time = self.beginning_of(@of_the) + @until = self.end_of(@of_the) + options.merge!(:beginning_of => true, :include_start => true) + end direction = (self < @until) ? :f : :b succ_method = (direction == :f) ? "next_#{unit}" : "prev_#{unit}" time = time.beginning_of(unit) if options[:beginning_of] time = time.send(succ_method) if !options[:include_start] + @until = @until.prev(unit).end_of(unit) if options[:include_start] && @of_the.nil? results = [] while (direction == :f && time <= @until) || (direction == :b && time >= @until) options[:map_result] ? results << yield(time) : yield(time) @@ -46,6 +53,14 @@ module TimeExt end end + # Let's you iterate over every unit specified in the #each or #map call for the specified unit. + def of_the(unit, &block) + @of_the = unit + return call_chain(block) if block_given? + self + end + alias :of :of_the + # Executes passed block for each "unit" of time specified, with a new time object for each interval passed to the block. def each(unit, options = {}, &block) iterate(unit, options.merge(:map_result => false), &block) @@ -76,6 +91,13 @@ module TimeExt class_eval { alias :"#{method}_minute" :"#{method}_min" } if unit == :min class_eval { alias :"#{method}_second" :"#{method}_sec" } if unit == :sec end + [:of_the, :of].each do |method| + define_method "#{method}_#{unit}" do |*args, &block| + send(method, unit, *args, &block) + end + class_eval { alias :"#{method}_minute" :"#{method}_min" } if unit == :min + class_eval { alias :"#{method}_second" :"#{method}_sec" } if unit == :sec + end end end diff --git a/spec/time_iterations_spec.rb b/spec/time_iterations_spec.rb index b9e0b5e..605488a 100644 --- a/spec/time_iterations_spec.rb +++ b/spec/time_iterations_spec.rb @@ -68,4 +68,23 @@ describe "Time Iterations" do (@now + 6.hours).from(@now).map_each(:hour) { |time| time }.should == match end -end \ No newline at end of file + it "should iterate over time objects with #map_each and #of_the via method chaining" do + match = (0..23).map { |i| ((@now - (@now.hour).hours) + i.hours).beginning_of_hour } + @now.map_each_hour.of_the(:day) { |time| time }.should == match + @now.map_each_hour.of_the_day { |time| time }.should == match + match = @now.beginning_of_month.map_beginning_of_each_hour(:include_start => true).until(@now.next_month.beginning_of_month) { |time| time } + @now.map_each_hour.of_the(:month) { |time| time }.should == match + end + + it "should iterate and respect the include_start option" do + match = (0..5).map { |i| @now + i.hours } + @now.map_each_hour(:include_start => true).until(@now + 6.hours) { |time| time }.should == match + end + + it "should iterate and respect the beginning_of option" do + match = (1..6).map { |i| @now.beginning_of_hour + i.hours } + @now.map_beginning_of_each_hour.until(@now.beginning_of_hour + 6.hours) { |time| time }.should == match + @now.map_each_hour(:beginning_of => true).until(@now.beginning_of_hour + 6.hours) { |time| time }.should == match + end + +end