timeframe 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document CHANGED
@@ -1,5 +1,5 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore CHANGED
@@ -1,21 +1,21 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright (c) 2009 Andy Rossmeissl
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2009 Andy Rossmeissl
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc CHANGED
@@ -1,13 +1,15 @@
1
- = timeframe
2
-
3
- A Ruby class for describing and interacting with timeframes.
4
-
5
- == Documentation
6
-
7
- == Acknoweldgements
8
-
9
- The good parts of Timeframe all came from the gentlemen at Fingertips[http://fngtps.com].
10
-
11
- == Copyright
12
-
13
- Copyright (c) 2010 Andy Rossmeissl.
1
+ = timeframe
2
+
3
+ A Ruby class for describing and interacting with timeframes.
4
+
5
+ == Documentation
6
+
7
+ http://rdoc.info/projects/rossmeissl/timeframe
8
+
9
+ == Acknowledgements
10
+
11
+ The good parts of Timeframe all came from the gentlemen at Fingertips[http://fngtps.com].
12
+
13
+ == Copyright
14
+
15
+ Copyright (c) 2010 Andy Rossmeissl.
data/Rakefile CHANGED
@@ -1,46 +1,46 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "timeframe"
8
- gem.summary = %Q{Date intervals}
9
- gem.description = %Q{A Ruby class for describing and interacting with timeframes.}
10
- gem.email = "andy@rossmeissl.net"
11
- gem.homepage = "http://github.com/rossmeissl/timeframe"
12
- gem.authors = ["Andy Rossmeissl"]
13
- gem.add_development_dependency "rspec", ">= 1.2.9"
14
- gem.add_dependency 'activesupport', '= 3.0.0.beta4'
15
- gem.add_dependency 'andand'
16
- end
17
- Jeweler::GemcutterTasks.new
18
- rescue LoadError
19
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
- end
21
-
22
- require 'spec/rake/spectask'
23
- Spec::Rake::SpecTask.new(:spec) do |spec|
24
- spec.libs << 'lib' << 'spec'
25
- spec.spec_files = FileList['spec/**/*_spec.rb']
26
- end
27
-
28
- Spec::Rake::SpecTask.new(:rcov) do |spec|
29
- spec.libs << 'lib' << 'spec'
30
- spec.pattern = 'spec/**/*_spec.rb'
31
- spec.rcov = true
32
- end
33
-
34
- task :spec => :check_dependencies
35
-
36
- task :default => :spec
37
-
38
- require 'rake/rdoctask'
39
- Rake::RDocTask.new do |rdoc|
40
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
-
42
- rdoc.rdoc_dir = 'rdoc'
43
- rdoc.title = "timeframe #{version}"
44
- rdoc.rdoc_files.include('README*')
45
- rdoc.rdoc_files.include('lib/**/*.rb')
46
- end
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "timeframe"
8
+ gem.summary = %Q{Date intervals}
9
+ gem.description = %Q{A Ruby class for describing and interacting with timeframes.}
10
+ gem.email = "andy@rossmeissl.net"
11
+ gem.homepage = "http://github.com/rossmeissl/timeframe"
12
+ gem.authors = ["Andy Rossmeissl", "Seamus Abshere", "Derek Kastner"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency 'activesupport', '= 3.0.0.beta4'
15
+ gem.add_dependency 'andand'
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "timeframe #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -0,0 +1,5 @@
1
+ class Date
2
+ def to_json(*)
3
+ super nil
4
+ end
5
+ end
data/lib/timeframe/ykk.rb CHANGED
@@ -1,4 +1,4 @@
1
- module Ykk
1
+ module Ykk # :nodoc: all
2
2
  def ykk(*arys, &blk) # YKK: a better zipper
3
3
  return zip(*arys) unless block_given?
4
4
  zip(*arys).collect { |a| yield a }
data/lib/timeframe.rb CHANGED
@@ -6,11 +6,13 @@ require 'active_support/version'
6
6
  active_support/core_ext/date/conversions
7
7
  active_support/core_ext/integer/time
8
8
  active_support/core_ext/numeric/time
9
+ active_support/json/encoding
9
10
  }.each do |active_support_3_requirement|
10
11
  require active_support_3_requirement
11
12
  end if ActiveSupport::VERSION::MAJOR == 3
12
13
  require 'andand'
13
14
  require 'timeframe/ykk'
15
+ require 'timeframe/date_to_json'
14
16
 
15
17
  # Encapsulates a timeframe between two dates. The dates provided to the class are always until the last date. That means
16
18
  # that the last date is excluded.
@@ -77,9 +79,9 @@ class Timeframe
77
79
 
78
80
  # Returns a string representation of the timeframe
79
81
  def to_s
80
- if [from.day, from.month, to.day, to.month].uniq == [1]
82
+ if (from.year == to.year - 1) and [from.day, from.month, to.day, to.month].uniq == [1]
81
83
  from.year.to_s
82
- elsif from.day == 1 and to.day == 1 and to.month - from.month == 1
84
+ elsif from.year == to.year and from.day == 1 and to.day == 1 and to.month - from.month == 1
83
85
  "#{Date::MONTHNAMES[from.month]} #{from.year}"
84
86
  else
85
87
  "the period from #{from.strftime('%d %B')} to #{to.yesterday.strftime('%d %B %Y')}"
@@ -120,7 +122,6 @@ class Timeframe
120
122
  def hash
121
123
  from.hash + to.hash
122
124
  end
123
- alias :to_param :hash
124
125
 
125
126
  # Returns an array of month-long subtimeframes
126
127
  #--
@@ -250,6 +251,11 @@ class Timeframe
250
251
  { :from => from, :to => to }.to_json
251
252
  end
252
253
 
254
+ # URL-friendly like "2008-10-25/2009-11-12"
255
+ def to_param
256
+ "#{from}/#{to}"
257
+ end
258
+
253
259
  class << self
254
260
  # Shortcut method to return the Timeframe representing the current year (as defined by Time.now)
255
261
  def this_year
data/spec/spec.opts CHANGED
@@ -1 +1 @@
1
- --color
1
+ --color
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,10 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- require 'timeframe'
4
- require 'spec'
5
- require 'spec/autorun'
6
- require 'date'
7
-
8
- Spec::Runner.configure do |config|
9
-
10
- end
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'timeframe'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'date'
7
+
8
+ Spec::Runner.configure do |config|
9
+
10
+ end
@@ -1,248 +1,270 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'date'
3
-
4
- describe Timeframe do
5
- describe 'initialization' do
6
- it 'should create a timeframe using date strings' do
7
- tf = Timeframe.new('2008-02-14', '2008-05-10')
8
- tf.from.should == Date.parse('2008-02-14')
9
- tf.to.should == Date.parse('2008-05-10')
10
- end
11
- it 'should create a timeframe using date objects' do
12
- start = Date.parse('2008-02-14')
13
- finish = Date.parse('2008-05-10')
14
- tf = Timeframe.new(start, finish)
15
- tf.from.should == start
16
- tf.to.should == finish
17
- end
18
- it "should accept months" do
19
- timeframe = Timeframe.new(:month => 1)
20
- timeframe.from.should == Date.today.change(:month => 1, :day => 1)
21
- timeframe.to.should == Date.today.change(:month => 2, :day => 1)
22
- end
23
- it "should accept month names" do
24
- timeframe = Timeframe.new(:month => 'february')
25
- timeframe.from.should == Date.today.change(:month => 2, :day => 1)
26
- timeframe.to.should == Date.today.change(:month => 3, :day => 1)
27
- end
28
- it "should accept years" do
29
- timeframe = Timeframe.new(:year => 2004)
30
- timeframe.from.should == Date.new(2004, 1, 1)
31
- timeframe.to.should == Date.new(2005, 1, 1)
32
- end
33
- it "should accept years and months" do
34
- timeframe = Timeframe.new(:year => 2005, :month => 5)
35
- timeframe.from.should == Date.new(2005, 5, 1)
36
- timeframe.to.should == Date.new(2005, 6, 1)
37
- end
38
- it "should not accept just one date argument" do
39
- lambda {
40
- Timeframe.new Date.new(2007, 2, 1)
41
- }.should raise_error(ArgumentError, /supply/)
42
- end
43
- it "should not accept end date that is earlier than start date" do
44
- lambda {
45
- timeframe = Timeframe.new Date.new(2008, 1, 1), Date.new(2007, 1, 1)
46
- }.should raise_error(ArgumentError, /earlier/)
47
- end
48
- it "should not accept timeframes that cross year boundaries" do
49
- lambda {
50
- timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2)
51
- }.should raise_error(ArgumentError, /cross/)
52
- end
53
- it "should optionally accept timeframes that cross year boundaries" do
54
- lambda {
55
- timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2), :skip_year_boundary_crossing_check => true
56
- }.should_not raise_error
57
- end
58
- end
59
-
60
- describe '#inspect' do
61
- it 'should return the time frame in readable text' do
62
- start = Date.parse('2008-02-14')
63
- finish = Date.parse('2008-05-10')
64
- tf = Timeframe.new(start, finish)
65
- tf.inspect.should =~ /<Timeframe\(-?\d+\) 86 days starting 2008-02-14 ending 2008-05-10>/
66
- end
67
- end
68
-
69
- describe '.constrained_new' do
70
- let(:start) { Date.parse('2008-02-14') }
71
- let(:finish) { Date.parse('2008-05-10') }
72
- let(:constraint_start) { Date.parse('2008-01-01') }
73
- let(:constraint_finish) { Date.parse('2008-12-01') }
74
- let(:constraint) { Timeframe.new(constraint_start, constraint_finish) }
75
-
76
- it "should allow for constrained creation" do
77
- constraint = Timeframe.new :year => 2008
78
- may = Timeframe.new Date.new(2008,5,1), Date.new(2008,6,1)
79
- january = Timeframe.new Date.new(2008,1,1), Date.new(2008,2,1)
80
- Timeframe.constrained_new(may.from, may.to, constraint).should == may
81
- Timeframe.constrained_new(Date.new(2007,1,1), Date.new(2010,1,1), constraint).should == constraint
82
- Timeframe.constrained_new(Date.new(2007,11,1), Date.new(2008,2,1), constraint).should == january
83
- end
84
- it 'should return a timeframe spanning start and end date if within constraint' do
85
- tf = Timeframe.constrained_new(start, finish, constraint)
86
- tf.from.should == start
87
- tf.to.should == finish
88
- end
89
- it 'should return a timeframe spanning constraint start and end date if outside constraint' do
90
- constraint = Timeframe.new(start, finish)
91
- tf = Timeframe.constrained_new(constraint_start, constraint_finish, constraint)
92
- tf.from.should == start
93
- tf.to.should == finish
94
- end
95
- it 'should return a timeframe starting at constraint start' do
96
- start = Date.parse('2008-01-01')
97
- constraint_start = Date.parse('2008-01-14')
98
- constraint = Timeframe.new(constraint_start, constraint_finish)
99
- tf = Timeframe.constrained_new(start, finish, constraint)
100
- tf.from.should == constraint_start
101
- tf.to.should == finish
102
- end
103
- it 'should return a timeframe ending at constraint end' do
104
- constraint_finish = Date.parse('2008-04-14')
105
- constraint = Timeframe.new(constraint_start, constraint_finish)
106
- tf = Timeframe.constrained_new(start, finish, constraint)
107
- tf.from.should == start
108
- tf.to.should == constraint_finish
109
- end
110
- it "should return a 0-length timeframe when constraining a timeframe by a disjoint timeframe" do
111
- constraint = Timeframe.new :year => 2010
112
- timeframe = Timeframe.constrained_new(
113
- Date.new(2009,1,1), Date.new(2010,1,1), constraint)
114
- timeframe.days.should == 0
115
- end
116
- end
117
-
118
- describe '.this_year' do
119
- it "should return the current year" do
120
- Timeframe.this_year.should == Timeframe.new(:year => Time.now.year)
121
- end
122
- end
123
-
124
- describe '#days' do
125
- it "should return them number of days included" do
126
- #TODO: make these separate "it" blocks, per best practices
127
- Timeframe.new(Date.new(2007, 1, 1), Date.new(2008, 1, 1)).days.should == 365
128
- Timeframe.new(Date.new(2008, 1, 1), Date.new(2009, 1, 1)).days.should == 366 #leap year
129
- Timeframe.new(Date.new(2007, 11, 1), Date.new(2007, 12, 1)).days.should == 30
130
- Timeframe.new(Date.new(2007, 11, 1), Date.new(2008, 1, 1)).days.should == 61
131
- Timeframe.new(Date.new(2007, 2, 1), Date.new(2007, 3, 1)).days.should == 28
132
- Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 3, 1)).days.should == 29
133
- Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 2, 1)).days.should == 0
134
- end
135
- end
136
-
137
- describe '#include?' do
138
- it "should know if a certain date is included in the Timeframe" do
139
- #TODO: make these separate "it" blocks, per best practices
140
- timeframe = Timeframe.new :year => 2008, :month => 2
141
- [
142
- Date.new(2008, 2, 1),
143
- Date.new(2008, 2, 5),
144
- Date.new(2008, 2, 29)
145
- ].each do |date|
146
- timeframe.include?(date).should == true
147
- end
148
- [
149
- Date.new(2008, 1, 1),
150
- Date.new(2007, 2, 1),
151
- Date.new(2008, 3, 1)
152
- ].each do |date|
153
- timeframe.include?(date).should == false
154
- end
155
- end
156
- end
157
-
158
- describe '#==' do
159
- it "should be able to know if it's equal to another Timeframe object" do
160
- Timeframe.new(:year => 2007).should == Timeframe.new(:year => 2007)
161
- Timeframe.new(:year => 2004, :month => 1).should == Timeframe.new(:year => 2004, :month => 1)
162
- end
163
-
164
- it "should hash equal hash values when the timeframe is equal" do
165
- Timeframe.new(:year => 2007).hash.should == Timeframe.new(:year => 2007).hash
166
- Timeframe.new(:year => 2004, :month => 1).hash.should == Timeframe.new(:year => 2004, :month => 1).hash
167
- end
168
- end
169
-
170
- describe '#months' do
171
- it "should return an array of month-long subtimeframes" do
172
- Timeframe.new(:year => 2009).months.length.should == 12
173
- end
174
- it "should not return an array of month-long subtimeframes if provided an inappropriate range" do
175
- lambda {
176
- Timeframe.new(Date.new(2009, 3, 2), Date.new(2009, 3, 5)).months
177
- }.should raise_error(ArgumentError, /whole/)
178
- lambda {
179
- Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1), :skip_year_boundary_crossing_check => true).months
180
- }.should raise_error(ArgumentError, /dangerous during/)
181
- end
182
- end
183
-
184
- describe '#year' do
185
- it "should return the relevant year of a timeframe" do
186
- Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 4, 1)).year.should == Timeframe.new(:year => 2009)
187
- end
188
- it "should not return the relevant year of a timeframe if provided an inappropriate range" do
189
- lambda {
190
- Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1), :skip_year_boundary_crossing_check => true).year
191
- }.should raise_error(ArgumentError, /dangerous during/)
192
- end
193
- end
194
-
195
- describe '#&' do
196
- it "should return its intersection with another timeframe" do
197
- #TODO: make these separate "it" blocks, per best practices
198
- (Timeframe.new(:month => 4) & Timeframe.new(:month => 6)).should be_nil
199
- (Timeframe.new(:month => 4) & Timeframe.new(:month => 5)).should be_nil
200
- (Timeframe.new(:month => 4) & Timeframe.new(:month => 4)).should == Timeframe.new(:month => 4)
201
- (Timeframe.new(:year => Time.now.year) & Timeframe.new(:month => 4)).should == Timeframe.new(:month => 4)
202
- (Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 6, 1)) & Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 8, 1))).should == Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 6, 1))
203
- end
204
- end
205
-
206
- describe '#/' do
207
- it "should return a fraction of another timeframe" do
208
- (Timeframe.new(:month => 4, :year => 2009) / Timeframe.new(:year => 2009)).should == (30.0 / 365.0)
209
- end
210
- end
211
-
212
- describe '#gaps_left_by' do
213
- it "should be able to ascertain gaps left by a list of other Timeframes" do
214
- Timeframe.new(:year => 2009).gaps_left_by(
215
- Timeframe.new(:year => 2009, :month => 3),
216
- Timeframe.new(:year => 2009, :month => 5),
217
- Timeframe.new(Date.new(2009, 8, 1), Date.new(2009, 11, 1)),
218
- Timeframe.new(Date.new(2009, 9, 1), Date.new(2009, 10, 1))
219
- ).should ==
220
- [ Timeframe.new(Date.new(2009, 1, 1), Date.new(2009, 3, 1)),
221
- Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 5, 1)),
222
- Timeframe.new(Date.new(2009, 6, 1), Date.new(2009, 8, 1)),
223
- Timeframe.new(Date.new(2009, 11, 1), Date.new(2010, 1, 1)) ]
224
- end
225
- end
226
-
227
- describe '#covered_by?' do
228
- it "should be able to ascertain gaps left by a list of other Timeframes" do
229
- Timeframe.new(:year => 2009).covered_by?(
230
- Timeframe.new(:month => 1, :year => 2009),
231
- Timeframe.new(Date.new(2009, 2, 1), Date.new(2010, 1, 1))
232
- ).should be_true
233
- end
234
- end
235
-
236
- describe '#last_year' do
237
- it "should return its predecessor in a previous year" do
238
- Timeframe.this_year.last_year.should ==
239
- Timeframe.new(Date.new(Date.today.year - 1, 1, 1), Date.new(Date.today.year, 1, 1))
240
- end
241
- end
242
-
243
- describe 'Timeframe:class#interval' do
244
- it 'should parse ISO 8601 interval format' do
245
- Timeframe.interval('2009-01-01/2010-01-01').should == Timeframe.new(:year => 2009)
246
- end
247
- end
248
- end
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'date'
3
+
4
+ describe Timeframe do
5
+ describe 'initialization' do
6
+ it 'should create a timeframe using date strings' do
7
+ tf = Timeframe.new('2008-02-14', '2008-05-10')
8
+ tf.from.should == Date.parse('2008-02-14')
9
+ tf.to.should == Date.parse('2008-05-10')
10
+ end
11
+ it 'should create a timeframe using date objects' do
12
+ start = Date.parse('2008-02-14')
13
+ finish = Date.parse('2008-05-10')
14
+ tf = Timeframe.new(start, finish)
15
+ tf.from.should == start
16
+ tf.to.should == finish
17
+ end
18
+ it "should accept months" do
19
+ timeframe = Timeframe.new(:month => 1)
20
+ timeframe.from.should == Date.today.change(:month => 1, :day => 1)
21
+ timeframe.to.should == Date.today.change(:month => 2, :day => 1)
22
+ end
23
+ it "should accept month names" do
24
+ timeframe = Timeframe.new(:month => 'february')
25
+ timeframe.from.should == Date.today.change(:month => 2, :day => 1)
26
+ timeframe.to.should == Date.today.change(:month => 3, :day => 1)
27
+ end
28
+ it "should accept years" do
29
+ timeframe = Timeframe.new(:year => 2004)
30
+ timeframe.from.should == Date.new(2004, 1, 1)
31
+ timeframe.to.should == Date.new(2005, 1, 1)
32
+ end
33
+ it "should accept years and months" do
34
+ timeframe = Timeframe.new(:year => 2005, :month => 5)
35
+ timeframe.from.should == Date.new(2005, 5, 1)
36
+ timeframe.to.should == Date.new(2005, 6, 1)
37
+ end
38
+ it "should not accept just one date argument" do
39
+ lambda {
40
+ Timeframe.new Date.new(2007, 2, 1)
41
+ }.should raise_error(ArgumentError, /supply/)
42
+ end
43
+ it "should not accept end date that is earlier than start date" do
44
+ lambda {
45
+ timeframe = Timeframe.new Date.new(2008, 1, 1), Date.new(2007, 1, 1)
46
+ }.should raise_error(ArgumentError, /earlier/)
47
+ end
48
+ it "should not accept timeframes that cross year boundaries" do
49
+ lambda {
50
+ timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2)
51
+ }.should raise_error(ArgumentError, /cross/)
52
+ end
53
+ it "should optionally accept timeframes that cross year boundaries" do
54
+ lambda {
55
+ timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2), :skip_year_boundary_crossing_check => true
56
+ }.should_not raise_error
57
+ end
58
+ end
59
+
60
+ describe '#inspect' do
61
+ it 'should return the time frame in readable text' do
62
+ start = Date.parse('2008-02-14')
63
+ finish = Date.parse('2008-05-10')
64
+ tf = Timeframe.new(start, finish)
65
+ tf.inspect.should =~ /<Timeframe\(-?\d+\) 86 days starting 2008-02-14 ending 2008-05-10>/
66
+ end
67
+ end
68
+
69
+ describe '.constrained_new' do
70
+ let(:start) { Date.parse('2008-02-14') }
71
+ let(:finish) { Date.parse('2008-05-10') }
72
+ let(:constraint_start) { Date.parse('2008-01-01') }
73
+ let(:constraint_finish) { Date.parse('2008-12-01') }
74
+ let(:constraint) { Timeframe.new(constraint_start, constraint_finish) }
75
+
76
+ it "should allow for constrained creation" do
77
+ constraint = Timeframe.new :year => 2008
78
+ may = Timeframe.new Date.new(2008,5,1), Date.new(2008,6,1)
79
+ january = Timeframe.new Date.new(2008,1,1), Date.new(2008,2,1)
80
+ Timeframe.constrained_new(may.from, may.to, constraint).should == may
81
+ Timeframe.constrained_new(Date.new(2007,1,1), Date.new(2010,1,1), constraint).should == constraint
82
+ Timeframe.constrained_new(Date.new(2007,11,1), Date.new(2008,2,1), constraint).should == january
83
+ end
84
+ it 'should return a timeframe spanning start and end date if within constraint' do
85
+ tf = Timeframe.constrained_new(start, finish, constraint)
86
+ tf.from.should == start
87
+ tf.to.should == finish
88
+ end
89
+ it 'should return a timeframe spanning constraint start and end date if outside constraint' do
90
+ constraint = Timeframe.new(start, finish)
91
+ tf = Timeframe.constrained_new(constraint_start, constraint_finish, constraint)
92
+ tf.from.should == start
93
+ tf.to.should == finish
94
+ end
95
+ it 'should return a timeframe starting at constraint start' do
96
+ start = Date.parse('2008-01-01')
97
+ constraint_start = Date.parse('2008-01-14')
98
+ constraint = Timeframe.new(constraint_start, constraint_finish)
99
+ tf = Timeframe.constrained_new(start, finish, constraint)
100
+ tf.from.should == constraint_start
101
+ tf.to.should == finish
102
+ end
103
+ it 'should return a timeframe ending at constraint end' do
104
+ constraint_finish = Date.parse('2008-04-14')
105
+ constraint = Timeframe.new(constraint_start, constraint_finish)
106
+ tf = Timeframe.constrained_new(start, finish, constraint)
107
+ tf.from.should == start
108
+ tf.to.should == constraint_finish
109
+ end
110
+ it "should return a 0-length timeframe when constraining a timeframe by a disjoint timeframe" do
111
+ constraint = Timeframe.new :year => 2010
112
+ timeframe = Timeframe.constrained_new(
113
+ Date.new(2009,1,1), Date.new(2010,1,1), constraint)
114
+ timeframe.days.should == 0
115
+ end
116
+ end
117
+
118
+ describe '.this_year' do
119
+ it "should return the current year" do
120
+ Timeframe.this_year.should == Timeframe.new(:year => Time.now.year)
121
+ end
122
+ end
123
+
124
+ describe '#days' do
125
+ it "should return them number of days included" do
126
+ #TODO: make these separate "it" blocks, per best practices
127
+ Timeframe.new(Date.new(2007, 1, 1), Date.new(2008, 1, 1)).days.should == 365
128
+ Timeframe.new(Date.new(2008, 1, 1), Date.new(2009, 1, 1)).days.should == 366 #leap year
129
+ Timeframe.new(Date.new(2007, 11, 1), Date.new(2007, 12, 1)).days.should == 30
130
+ Timeframe.new(Date.new(2007, 11, 1), Date.new(2008, 1, 1)).days.should == 61
131
+ Timeframe.new(Date.new(2007, 2, 1), Date.new(2007, 3, 1)).days.should == 28
132
+ Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 3, 1)).days.should == 29
133
+ Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 2, 1)).days.should == 0
134
+ end
135
+ end
136
+
137
+ describe '#include?' do
138
+ it "should know if a certain date is included in the Timeframe" do
139
+ #TODO: make these separate "it" blocks, per best practices
140
+ timeframe = Timeframe.new :year => 2008, :month => 2
141
+ [
142
+ Date.new(2008, 2, 1),
143
+ Date.new(2008, 2, 5),
144
+ Date.new(2008, 2, 29)
145
+ ].each do |date|
146
+ timeframe.include?(date).should == true
147
+ end
148
+ [
149
+ Date.new(2008, 1, 1),
150
+ Date.new(2007, 2, 1),
151
+ Date.new(2008, 3, 1)
152
+ ].each do |date|
153
+ timeframe.include?(date).should == false
154
+ end
155
+ end
156
+ end
157
+
158
+ describe '#==' do
159
+ it "should be able to know if it's equal to another Timeframe object" do
160
+ Timeframe.new(:year => 2007).should == Timeframe.new(:year => 2007)
161
+ Timeframe.new(:year => 2004, :month => 1).should == Timeframe.new(:year => 2004, :month => 1)
162
+ end
163
+
164
+ it "should hash equal hash values when the timeframe is equal" do
165
+ Timeframe.new(:year => 2007).hash.should == Timeframe.new(:year => 2007).hash
166
+ Timeframe.new(:year => 2004, :month => 1).hash.should == Timeframe.new(:year => 2004, :month => 1).hash
167
+ end
168
+ end
169
+
170
+ describe '#months' do
171
+ it "should return an array of month-long subtimeframes" do
172
+ Timeframe.new(:year => 2009).months.length.should == 12
173
+ end
174
+ it "should not return an array of month-long subtimeframes if provided an inappropriate range" do
175
+ lambda {
176
+ Timeframe.new(Date.new(2009, 3, 2), Date.new(2009, 3, 5)).months
177
+ }.should raise_error(ArgumentError, /whole/)
178
+ lambda {
179
+ Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1), :skip_year_boundary_crossing_check => true).months
180
+ }.should raise_error(ArgumentError, /dangerous during/)
181
+ end
182
+ end
183
+
184
+ describe '#year' do
185
+ it "should return the relevant year of a timeframe" do
186
+ Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 4, 1)).year.should == Timeframe.new(:year => 2009)
187
+ end
188
+ it "should not return the relevant year of a timeframe if provided an inappropriate range" do
189
+ lambda {
190
+ Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1), :skip_year_boundary_crossing_check => true).year
191
+ }.should raise_error(ArgumentError, /dangerous during/)
192
+ end
193
+ end
194
+
195
+ describe '#&' do
196
+ it "should return its intersection with another timeframe" do
197
+ #TODO: make these separate "it" blocks, per best practices
198
+ (Timeframe.new(:month => 4) & Timeframe.new(:month => 6)).should be_nil
199
+ (Timeframe.new(:month => 4) & Timeframe.new(:month => 5)).should be_nil
200
+ (Timeframe.new(:month => 4) & Timeframe.new(:month => 4)).should == Timeframe.new(:month => 4)
201
+ (Timeframe.new(:year => Time.now.year) & Timeframe.new(:month => 4)).should == Timeframe.new(:month => 4)
202
+ (Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 6, 1)) & Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 8, 1))).should == Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 6, 1))
203
+ end
204
+ end
205
+
206
+ describe '#/' do
207
+ it "should return a fraction of another timeframe" do
208
+ (Timeframe.new(:month => 4, :year => 2009) / Timeframe.new(:year => 2009)).should == (30.0 / 365.0)
209
+ end
210
+ end
211
+
212
+ describe '#gaps_left_by' do
213
+ it "should be able to ascertain gaps left by a list of other Timeframes" do
214
+ Timeframe.new(:year => 2009).gaps_left_by(
215
+ Timeframe.new(:year => 2009, :month => 3),
216
+ Timeframe.new(:year => 2009, :month => 5),
217
+ Timeframe.new(Date.new(2009, 8, 1), Date.new(2009, 11, 1)),
218
+ Timeframe.new(Date.new(2009, 9, 1), Date.new(2009, 10, 1))
219
+ ).should ==
220
+ [ Timeframe.new(Date.new(2009, 1, 1), Date.new(2009, 3, 1)),
221
+ Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 5, 1)),
222
+ Timeframe.new(Date.new(2009, 6, 1), Date.new(2009, 8, 1)),
223
+ Timeframe.new(Date.new(2009, 11, 1), Date.new(2010, 1, 1)) ]
224
+ end
225
+ end
226
+
227
+ describe '#covered_by?' do
228
+ it "should be able to ascertain gaps left by a list of other Timeframes" do
229
+ Timeframe.new(:year => 2009).covered_by?(
230
+ Timeframe.new(:month => 1, :year => 2009),
231
+ Timeframe.new(Date.new(2009, 2, 1), Date.new(2010, 1, 1))
232
+ ).should be_true
233
+ end
234
+ end
235
+
236
+ describe '#last_year' do
237
+ it "should return its predecessor in a previous year" do
238
+ Timeframe.this_year.last_year.should ==
239
+ Timeframe.new(Date.new(Date.today.year - 1, 1, 1), Date.new(Date.today.year, 1, 1))
240
+ end
241
+ end
242
+
243
+ describe 'Timeframe:class#interval' do
244
+ it 'should parse ISO 8601 interval format' do
245
+ Timeframe.interval('2009-01-01/2010-01-01').should == Timeframe.new(:year => 2009)
246
+ end
247
+ it 'should understand its own #to_param' do
248
+ t = Timeframe.new(:year => 2009)
249
+ Timeframe.interval(t.to_param).should == t
250
+ end
251
+ end
252
+
253
+ describe '#to_json' do
254
+ it 'should generate JSON' do
255
+ Timeframe.new(:year => 2009).to_json.should == "{\"from\":\"2009-01-01\",\"to\":\"2010-01-01\"}"
256
+ end
257
+ end
258
+
259
+ describe '#to_param' do
260
+ it 'should generate a URL-friendly parameter' do
261
+ Timeframe.new(:year => 2009).to_param.should == "2009-01-01/2010-01-01"
262
+ end
263
+ end
264
+
265
+ describe '#to_s' do
266
+ it 'should not only look at month numbers when describing multi-year timeframes' do
267
+ Timeframe.multiyear(Date.parse('2008-01-01'), Date.parse('2010-01-01')).to_s.should == "the period from 01 January to 31 December 2009"
268
+ end
269
+ end
270
+ end
data/timeframe.gemspec ADDED
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{timeframe}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andy Rossmeissl", "Seamus Abshere", "Derek Kastner"]
12
+ s.date = %q{2010-07-16}
13
+ s.description = %q{A Ruby class for describing and interacting with timeframes.}
14
+ s.email = %q{andy@rossmeissl.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/timeframe.rb",
27
+ "lib/timeframe/date_to_json.rb",
28
+ "lib/timeframe/ykk.rb",
29
+ "spec/spec.opts",
30
+ "spec/spec_helper.rb",
31
+ "spec/timeframe_spec.rb",
32
+ "timeframe.gemspec"
33
+ ]
34
+ s.homepage = %q{http://github.com/rossmeissl/timeframe}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{Date intervals}
39
+ s.test_files = [
40
+ "spec/spec_helper.rb",
41
+ "spec/timeframe_spec.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
50
+ s.add_runtime_dependency(%q<activesupport>, ["= 3.0.0.beta4"])
51
+ s.add_runtime_dependency(%q<andand>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
54
+ s.add_dependency(%q<activesupport>, ["= 3.0.0.beta4"])
55
+ s.add_dependency(%q<andand>, [">= 0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ s.add_dependency(%q<activesupport>, ["= 3.0.0.beta4"])
60
+ s.add_dependency(%q<andand>, [">= 0"])
61
+ end
62
+ end
63
+
metadata CHANGED
@@ -1,29 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timeframe
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 27
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 0
8
- - 1
9
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
10
11
  platform: ruby
11
12
  authors:
12
13
  - Andy Rossmeissl
14
+ - Seamus Abshere
15
+ - Derek Kastner
13
16
  autorequire:
14
17
  bindir: bin
15
18
  cert_chain: []
16
19
 
17
- date: 2010-07-15 00:00:00 -04:00
20
+ date: 2010-07-16 00:00:00 -05:00
18
21
  default_executable:
19
22
  dependencies:
20
23
  - !ruby/object:Gem::Dependency
21
24
  name: rspec
22
25
  prerelease: false
23
26
  requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
24
28
  requirements:
25
29
  - - ">="
26
30
  - !ruby/object:Gem::Version
31
+ hash: 13
27
32
  segments:
28
33
  - 1
29
34
  - 2
@@ -35,9 +40,11 @@ dependencies:
35
40
  name: activesupport
36
41
  prerelease: false
37
42
  requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
38
44
  requirements:
39
45
  - - "="
40
46
  - !ruby/object:Gem::Version
47
+ hash: 299253624
41
48
  segments:
42
49
  - 3
43
50
  - 0
@@ -50,9 +57,11 @@ dependencies:
50
57
  name: andand
51
58
  prerelease: false
52
59
  requirement: &id003 !ruby/object:Gem::Requirement
60
+ none: false
53
61
  requirements:
54
62
  - - ">="
55
63
  - !ruby/object:Gem::Version
64
+ hash: 3
56
65
  segments:
57
66
  - 0
58
67
  version: "0"
@@ -75,10 +84,12 @@ files:
75
84
  - Rakefile
76
85
  - VERSION
77
86
  - lib/timeframe.rb
87
+ - lib/timeframe/date_to_json.rb
78
88
  - lib/timeframe/ykk.rb
79
89
  - spec/spec.opts
80
90
  - spec/spec_helper.rb
81
91
  - spec/timeframe_spec.rb
92
+ - timeframe.gemspec
82
93
  has_rdoc: true
83
94
  homepage: http://github.com/rossmeissl/timeframe
84
95
  licenses: []
@@ -89,23 +100,27 @@ rdoc_options:
89
100
  require_paths:
90
101
  - lib
91
102
  required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
92
104
  requirements:
93
105
  - - ">="
94
106
  - !ruby/object:Gem::Version
107
+ hash: 3
95
108
  segments:
96
109
  - 0
97
110
  version: "0"
98
111
  required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
99
113
  requirements:
100
114
  - - ">="
101
115
  - !ruby/object:Gem::Version
116
+ hash: 3
102
117
  segments:
103
118
  - 0
104
119
  version: "0"
105
120
  requirements: []
106
121
 
107
122
  rubyforge_project:
108
- rubygems_version: 1.3.6
123
+ rubygems_version: 1.3.7
109
124
  signing_key:
110
125
  specification_version: 3
111
126
  summary: Date intervals