24 Commits

Author SHA1 Message Date
b29c232939 Merge branch 'release/v0.2.7' 2010-11-24 09:48:23 +00:00
f3b9d3751a Version bump to 0.2.7 2010-11-24 09:48:10 +00:00
a612a17c54 added a Gemfile 2010-11-24 09:47:55 +00:00
71c5421587 added i18n to dependencies as activesupport needs
it, but doesn't have it as a dependency
2010-11-24 09:47:37 +00:00
d564c31b93 updated project to rspec 2.x 2010-11-24 09:46:31 +00:00
29e1c7f500 Merge branch 'release-0.2.6' into stable 2010-09-28 19:18:09 +03:00
f49c6bd455 Version bump to 0.2.6 2010-09-28 19:17:19 +03:00
5ece10846a added spec to check for core extention method
aliases
2010-09-28 19:16:36 +03:00
5afb6bc2b9 removed last traces of Time#map method which was
causing issues with Active Record
2010-09-28 19:16:11 +03:00
9bbd974a75 fixed compatibility with Active Support 3.x 2010-09-28 19:15:39 +03:00
ca929c6ae1 Merge branch 'release-0.2.5' into stable 2010-08-23 12:41:45 +03:00
edd828bb3e Version bump to 0.2.5 2010-08-23 12:41:23 +03:00
4afd3f84d5 removed Time#map alias to Time#map_each as it was
causing issues with ActiveRecord
2010-08-23 12:40:58 +03:00
ea6d87e35f Merge branch 'release-0.2.4' into stable 2010-08-11 13:52:07 +03:00
74574beaf0 Version bump to 0.2.4 2010-08-11 13:51:50 +03:00
ba33dfec57 added min and sec aliases to minutes and seconds
methods respectively to Numeric for unit
consitency
2010-08-11 13:51:21 +03:00
c9cd80fd9e Merge branch 'release-0.2.3' into stable 2010-08-05 13:01:03 +03:00
06e167d1ab Version bump to 0.2.3 2010-08-05 13:00:05 +03:00
ac1ad2dba4 big oops, yes, I suck... 2010-08-05 12:56:26 +03:00
ab6e1e8003 Merge branch 'release-0.2.2' into stable 2010-08-05 12:50:14 +03:00
3d2b5d0b9e Version bump to 0.2.2 2010-08-05 12:49:49 +03:00
b8ba272b95 added include_end option to #iterate 2010-08-04 18:26:14 +03:00
3201485eaf Added #of_the / #of range modifier which is used
like #until and #from. Except #of_the makes the
iteration walk through each unit of time passed to
the #each / #map method, from the beginning till
end of unit passed to #of_the.

Example:
Time.now.each_hour.of_the(:month) { |t puts t }
#=> iterates over each over of the whole current month
2010-08-04 17:58:58 +03:00
77d9d67ed1 merged MethodChain and BackwardsCompatibility
modules into a single TimeExt::Support module
2010-08-04 17:28:22 +03:00
16 changed files with 173 additions and 63 deletions

2
.rspec Normal file
View File

@@ -0,0 +1,2 @@
--format documentation
--color

10
Gemfile Normal file
View File

@@ -0,0 +1,10 @@
source 'http://rubygems.org/'
gem 'activesupport', '>= 2.3.0'
gem 'i18n', '>= 0.4.2'
group :development do
gem 'jeweler', '>= 1.4.0'
gem 'rspec', '>= 2.1.0'
gem 'yard', '>= 0.6.3'
end

34
Gemfile.lock Normal file
View File

@@ -0,0 +1,34 @@
GEM
remote: http://rubygems.org/
specs:
activesupport (3.0.3)
diff-lcs (1.1.2)
gemcutter (0.6.1)
git (1.2.5)
i18n (0.4.2)
jeweler (1.4.0)
gemcutter (>= 0.1.0)
git (>= 1.2.5)
rubyforge (>= 2.0.0)
json_pure (1.4.6)
rspec (2.1.0)
rspec-core (~> 2.1.0)
rspec-expectations (~> 2.1.0)
rspec-mocks (~> 2.1.0)
rspec-core (2.1.0)
rspec-expectations (2.1.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.1.0)
rubyforge (2.0.4)
json_pure (>= 1.1.7)
yard (0.6.3)
PLATFORMS
ruby
DEPENDENCIES
activesupport (>= 2.3.0)
i18n (>= 0.4.2)
jeweler (>= 1.4.0)
rspec (>= 2.1.0)
yard (>= 0.6.3)

View File

@@ -10,23 +10,24 @@ begin
gem.email = "contact@jimeh.me" gem.email = "contact@jimeh.me"
gem.homepage = "http://github.com/jimeh/time_ext" gem.homepage = "http://github.com/jimeh/time_ext"
gem.authors = ["Jim Myhrberg"] gem.authors = ["Jim Myhrberg"]
gem.add_dependency "activesupport", ">= 2.3.0" gem.add_dependency 'activesupport', '>= 2.3.0'
gem.add_development_dependency "rspec", ">= 1.2.9" gem.add_dependency 'i18n', '>= 0.4.2'
gem.add_development_dependency "yard", ">= 0" gem.add_development_dependency 'jeweler', '>= 1.4.0'
gem.add_development_dependency 'rspec', '>= 2.1.0'
gem.add_development_dependency 'yard', '>= 0.6.3'
end end
Jeweler::GemcutterTasks.new Jeweler::GemcutterTasks.new
rescue LoadError rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
end end
require 'spec/rake/spectask' # Rspec
Spec::Rake::SpecTask.new(:spec) do |spec| require 'rspec/core/rake_task'
spec.libs << 'lib' << 'spec' RSpec::Core::RakeTask.new(:spec) do |spec|
spec.spec_files = FileList['spec/**/*_spec.rb'] spec.pattern = 'spec/**/*_spec.rb'
end end
Spec::Rake::SpecTask.new(:rcov) do |spec| RSpec::Core::RakeTask.new(:rcov) do |spec|
spec.libs << 'lib' << 'spec'
spec.pattern = 'spec/**/*_spec.rb' spec.pattern = 'spec/**/*_spec.rb'
spec.rcov = true spec.rcov = true
end end
@@ -35,9 +36,11 @@ task :spec => :check_dependencies
task :default => :spec task :default => :spec
desc "Start an irb console with TimeExt pre-loaded."
task :console do task :console do
exec "irb -r spec/spec_helper" exec "irb -r spec/spec_helper"
end end
task :c => :console
begin begin
require 'yard' require 'yard'

View File

@@ -1 +1 @@
0.2.1 0.2.7

View File

@@ -1,8 +1,11 @@
require 'rubygems' require 'rubygems'
require 'active_support' require 'active_support'
require 'time_ext/backwards_compatibility' # support both Active Support 2.x and 3.x
require 'active_support/time' if !Time.respond_to?(:days_in_month)
require 'time_ext/calculations' require 'time_ext/calculations'
require 'time_ext/iterations' require 'time_ext/iterations'
require 'time_ext/method_chain' require 'time_ext/support'
require 'time_ext/core_ext/time' require 'time_ext/core_ext/time'
require 'time_ext/core_ext/numeric'

View File

@@ -1,14 +0,0 @@
module TimeExt
# Provides helper methods used by TimeExt::Calculations for backwards compatibility with ActiveSupport.
module BackwardsCompatibility
def days_into_week
defined?(DAYS_INTO_WEEK) ? DAYS_INTO_WEEK : { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
end
def common_year_days_in_month
defined?(COMMON_YEAR_DAYS_IN_MONTH) ? COMMON_YEAR_DAYS_IN_MONTH : [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
end
end
end

View File

@@ -0,0 +1,4 @@
class Numeric
alias :sec :seconds
alias :min :minutes
end

View File

@@ -1,6 +1,5 @@
class Time class Time
include TimeExt::MethodChain include TimeExt::Support
include TimeExt::BackwardsCompatibility
include TimeExt::Calculations include TimeExt::Calculations
include TimeExt::Iterations include TimeExt::Iterations

View File

@@ -4,16 +4,23 @@ module TimeExt
# Used by #each, #map_each and similar methods to iterate over ranges of time. # Used by #each, #map_each and similar methods to iterate over ranges of time.
def iterate(unit, options = {}, &block) def iterate(unit, options = {}, &block)
options.reverse_merge!(:map_result => false, :beginning_of => false, :include_start => false) options.reverse_merge!(:map_result => false, :beginning_of => false, :include_start => false, :include_end => true)
if block_given? if block_given?
units = [:year, :month, :day, :hour, :min, :sec, :usec] units = [:year, :month, :day, :hour, :min, :sec, :usec]
parent_unit = units[units.index(unit)-1] parent_unit = units[units.index(unit)-1]
@until ||= (!parent_unit.nil?) ? self.send("#{parent_unit}s_since", 1) : self.send("#{unit}s_since", 1) if @of_the.nil?
time = self.clone 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.next(@of_the).beginning_of(@of_the)
options.merge!(:beginning_of => true, :include_start => true, :include_end => false)
end
direction = (self < @until) ? :f : :b direction = (self < @until) ? :f : :b
succ_method = (direction == :f) ? "next_#{unit}" : "prev_#{unit}" succ_method = (direction == :f) ? "next_#{unit}" : "prev_#{unit}"
time = time.beginning_of(unit) if options[:beginning_of] time = time.beginning_of(unit) if options[:beginning_of]
time = time.send(succ_method) if !options[:include_start] time = time.send(succ_method) if !options[:include_start]
@until = @until.prev(unit).end_of(unit) if !options[:include_end]
results = [] results = []
while (direction == :f && time <= @until) || (direction == :b && time >= @until) while (direction == :f && time <= @until) || (direction == :b && time >= @until)
options[:map_result] ? results << yield(time) : yield(time) options[:map_result] ? results << yield(time) : yield(time)
@@ -46,6 +53,14 @@ module TimeExt
end end
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. # 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) def each(unit, options = {}, &block)
iterate(unit, options.merge(:map_result => false), &block) iterate(unit, options.merge(:map_result => false), &block)
@@ -60,7 +75,6 @@ module TimeExt
def map_each(unit, options = {}, &block) def map_each(unit, options = {}, &block)
iterate(unit, options.merge(:map_result => true), &block) iterate(unit, options.merge(:map_result => true), &block)
end end
alias :map :map_each
# Executes passed block for each "unit" of time specified, returning an array with the return values from passed block. Additionally the time object passed into the block is set to the beginning of specified "unit". # Executes passed block for each "unit" of time specified, returning an array with the return values from passed block. Additionally the time object passed into the block is set to the beginning of specified "unit".
def map_beginning_of_each(unit, options = {}, &block) def map_beginning_of_each(unit, options = {}, &block)
@@ -69,7 +83,14 @@ module TimeExt
# Dynamically define convenience methods, like #each_hour instead of #each(:hour). # Dynamically define convenience methods, like #each_hour instead of #each(:hour).
[:year, :month, :day, :hour, :min, :sec].each do |unit| [:year, :month, :day, :hour, :min, :sec].each do |unit|
[:each, :beginning_of_each, :map_each, :map_beginning_of_each, :map].each do |method| [:each, :beginning_of_each, :map_each, :map_beginning_of_each].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
[:of_the, :of].each do |method|
define_method "#{method}_#{unit}" do |*args, &block| define_method "#{method}_#{unit}" do |*args, &block|
send(method, unit, *args, &block) send(method, unit, *args, &block)
end end

View File

@@ -1,19 +0,0 @@
module TimeExt
# Allows iterators' #until and #from methods to chain back to the parent iteration method.
module MethodChain
def add_to_chain(method, *args, &block)
@method_chain ||= []
@method_chain << [method.to_sym, args, block]
end
def call_chain(custom_block = nil, &block)
method, args, iblock = @method_chain.pop
return nil if method.nil?
iblock = custom_block if !custom_block.nil?
method, args, iblock = yield(method, args, iblock) if block_given?
self.send(method, *args, &iblock)
end
end
end

27
lib/time_ext/support.rb Normal file
View File

@@ -0,0 +1,27 @@
module TimeExt
# Provides helper methods used by TimeExt::Calculations for backwards compatibility with ActiveSupport, and method chaining helpers for TimeExt::Iterations.
module Support
def days_into_week
defined?(DAYS_INTO_WEEK) ? DAYS_INTO_WEEK : { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
end
def common_year_days_in_month
defined?(COMMON_YEAR_DAYS_IN_MONTH) ? COMMON_YEAR_DAYS_IN_MONTH : [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
end
def add_to_chain(method, *args, &block)
@method_chain ||= []
@method_chain << [method.to_sym, args, block]
end
def call_chain(custom_block = nil, &block)
method, args, iblock = @method_chain.pop
return nil if method.nil?
iblock = custom_block if !custom_block.nil?
method, args, iblock = yield(method, args, iblock) if block_given?
self.send(method, *args, &iblock)
end
end
end

19
spec/core_ext_spec.rb Normal file
View File

@@ -0,0 +1,19 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe "Core Extensions" do
it "should alias Numeric class methods" do
number = 1
number.sec.should == number.second
number.min.should == number.minute
end
it "should alias Time instance methods" do
time = Time.now
time.secs_ago(10).should == time.ago(10)
time.seconds_ago(10).should == time.ago(10)
time.secs_since(10).should == time.since(10)
time.seconds_since(10).should == time.since(10)
end
end

View File

@@ -1,2 +0,0 @@
--format specdoc
--color

View File

@@ -1,9 +1,6 @@
$LOAD_PATH.unshift(File.dirname(__FILE__)) $LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'time_ext'
require 'spec'
require 'spec/autorun'
Spec::Runner.configure do |config| require 'time_ext'
require 'rspec'
end require 'rspec/autorun'

View File

@@ -52,8 +52,6 @@ describe "Time Iterations" do
match = (1..6).map { |i| @now + i.hours } match = (1..6).map { |i| @now + i.hours }
@now.map_each_hour.until(@now + 6.hours) { |time| time }.should == match @now.map_each_hour.until(@now + 6.hours) { |time| time }.should == match
@now.until(@now + 6.hours).map_each(:hour) { |time| time }.should == match @now.until(@now + 6.hours).map_each(:hour) { |time| time }.should == match
# check so the #map alias for #map_each works
@now.map_hour.until(@now + 6.hours) { |time| time }.should == match
end end
it "should iterate over time objects backwards with #until set in the past" do it "should iterate over time objects backwards with #until set in the past" do
@@ -68,4 +66,32 @@ describe "Time Iterations" do
(@now + 6.hours).from(@now).map_each(:hour) { |time| time }.should == match (@now + 6.hours).from(@now).map_each(:hour) { |time| time }.should == match
end end
end 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, :include_end => false).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 and include_end options" do
match = (1..6).map { |i| @now + i.hours }
@now.map_each_hour.until(@now + 6.hours) { |time| time }.should == match
match = (1..6).map { |i| @now + i.hours }
@now.map_each_hour(:include_end => true).until(@now + 6.hours) { |time| time }.should == match
@now.map_each_hour(:include_start => false).until(@now + 6.hours) { |time| time }.should == match
match = (0..6).map { |i| @now + i.hours }
@now.map_each_hour(:include_start => true).until(@now + 6.hours) { |time| time }.should == match
match = (0..5).map { |i| @now + i.hours }
@now.map_each_hour(:include_start => true, :include_end => false).until(@now + 6.hours) { |time| time }.should == match
match = (0..6).map { |i| @now + i.hours }
@now.map_each_hour(:include_start => true, :include_end => 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