chronological 0.0.9 → 1.0.0beta1

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/lib/chronological.rb CHANGED
@@ -1,7 +1,97 @@
1
1
  require 'chronological/version'
2
- require 'chronological/base'
3
- require 'chronological/absolute_timeframe'
4
- require 'chronological/relative_timeframe'
2
+ require 'chronological/errors'
3
+ require 'chronological/strategy_resolver'
4
+ require 'chronological/strategies'
5
5
 
6
6
  module Chronological
7
+ def timeframe(*args)
8
+ options = args.first.is_a?(Hash) ? args.pop : {}
9
+ strategy = Chronological::StrategyResolver.resolve(options)
10
+
11
+ class_eval do
12
+ columns_hash[strategy.field_names[:starting_time]] ||= ActiveRecord::ConnectionAdapters::Column.new(strategy.field_names[:starting_time], nil, 'datetime')
13
+ columns_hash[strategy.field_names[:ending_time]] ||= ActiveRecord::ConnectionAdapters::Column.new(strategy.field_names[:ending_time], nil, 'datetime')
14
+ columns_hash[strategy.field_names[:starting_date]] ||= ActiveRecord::ConnectionAdapters::Column.new(strategy.field_names[:starting_date], nil, 'date')
15
+ columns_hash[strategy.field_names[:ending_date]] ||= ActiveRecord::ConnectionAdapters::Column.new(strategy.field_names[:ending_date], nil, 'date')
16
+ end
17
+
18
+ unless strategy.has_absolute_start?
19
+ define_method(strategy.field_names[:starting_time]) do
20
+ strategy.starting_time(self)
21
+ end
22
+ end
23
+
24
+ unless strategy.has_absolute_end?
25
+ define_method(strategy.field_names[:ending_time]) do
26
+ strategy.ending_time(self)
27
+ end
28
+ end
29
+
30
+ define_method(:scheduled?) do
31
+ strategy.scheduled?(self)
32
+ end
33
+
34
+ define_method(:partially_scheduled?) do
35
+ strategy.partially_scheduled?(self)
36
+ end
37
+
38
+ define_method(:inactive?) do
39
+ strategy.inactive?(self)
40
+ end
41
+
42
+ define_method(:in_progress?) do
43
+ strategy.in_progress?(self)
44
+ end
45
+
46
+ define_method(:duration) do
47
+ strategy.duration(self)
48
+ end
49
+
50
+ define_method(strategy.field_names[:starting_date]) do
51
+ strategy.starting_date(self)
52
+ end
53
+
54
+ define_method(strategy.field_names[:ending_date]) do
55
+ strategy.ending_date(self)
56
+ end
57
+
58
+ ###
59
+ # Scopes
60
+ #
61
+ define_singleton_method(:by_date) do |direction = :asc|
62
+ strategy.class.by_date(self, strategy.field_names, direction)
63
+ end
64
+
65
+ define_singleton_method(:ended) do
66
+ strategy.class.ended(self, strategy.field_names)
67
+ end
68
+
69
+ define_singleton_method(:not_yet_ended) do
70
+ strategy.class.not_yet_ended(self, strategy.field_names)
71
+ end
72
+
73
+ define_singleton_method(:in_progress) do
74
+ strategy.class.in_progress(self, strategy.field_names)
75
+ end
76
+
77
+ define_singleton_method(:started) do
78
+ strategy.class.started(self, strategy.field_names)
79
+ end
80
+
81
+ define_singleton_method(:in_progress?) do
82
+ strategy.class.in_progress?(self, strategy.field_names)
83
+ end
84
+
85
+ ###
86
+ # Aliases
87
+ #
88
+ instance_eval do
89
+ alias active? in_progress?
90
+ alias active in_progress
91
+ end
92
+
93
+ class_eval do
94
+ alias active? in_progress?
95
+ end
96
+ end
7
97
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ class ChronologicableStrategyClass
4
+ extend Chronological
5
+ end
6
+
7
+ describe Chronological do
8
+ describe '.timeframe' do
9
+ context 'when it is called with a symbol representing a strategy' do
10
+ before do
11
+ ChronologicableStrategyClass.class_eval do
12
+ timeframe type: :absolute,
13
+ start_utc: :started_at_utc,
14
+ end_utc: :ended_at_utc
15
+ end
16
+ end
17
+
18
+ pit 'is translated properly' do
19
+ ChronologicableStrategyClass.class_variable_get(:@@chronological_strategy).should eql Chronological::AbsoluteStrategy
20
+ end
21
+ end
22
+
23
+ context 'when it is called with a symbol that does not represent a strategy' do
24
+ it 'it throws an error' do
25
+ lambda do
26
+ ChronologicableStrategyClass.class_eval do
27
+ timeframe :grey_goose
28
+ end
29
+ end.should raise_error Chronological::UndefinedStrategy
30
+ end
31
+ end
32
+ end
33
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'sqlite3'
1
+ require 'pg'
2
2
  require 'active_record'
3
3
  require 'timecop'
4
4
  require 'chronological'
@@ -6,50 +6,4 @@ require 'chronological'
6
6
  Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
7
7
 
8
8
  RSpec.configure do |config|
9
- config.before(:suite) do
10
- SQLite3::Database.new 'tmp/test.db'
11
-
12
- ActiveRecord::Base.establish_connection(
13
- :adapter => 'sqlite3',
14
- :database => 'tmp/test.db'
15
- )
16
-
17
- class SetupTests < ActiveRecord::Migration
18
- def up
19
- create_table :base_chronologicables do |t|
20
- t.datetime :started_at
21
- t.datetime :ended_at
22
- end
23
-
24
- create_table :relative_chronologicables do |t|
25
- t.integer :starting_offset
26
- t.integer :ending_offset
27
- t.datetime :base_datetime_utc
28
- end
29
-
30
- create_table :absolute_chronologicables do |t|
31
- t.datetime :started_at_utc
32
- t.datetime :ended_at_utc
33
- end
34
-
35
- create_table :chronologicable_with_time_zones do |t|
36
- t.datetime :started_at_utc
37
- t.datetime :ended_at_utc
38
- t.string :time_zone
39
- end
40
- end
41
- end
42
-
43
- SetupTests.new.migrate(:up)
44
- end
45
-
46
- config.before(:each) do
47
- ActiveRecord::Base.connection.execute 'DELETE FROM relative_chronologicables'
48
- ActiveRecord::Base.connection.execute 'DELETE FROM absolute_chronologicables'
49
- ActiveRecord::Base.connection.execute 'DELETE FROM chronologicable_with_time_zones'
50
- end
51
-
52
- config.after(:suite) do
53
- `rm -f ./tmp/test.db`
54
- end
55
9
  end
@@ -1,21 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  class AbsoluteChronologicable < ActiveRecord::Base
4
- include Chronological::AbsoluteTimeframe
4
+ extend Chronological
5
5
 
6
- absolute_timeframe start_utc: :started_at_utc,
7
- end_utc: :ended_at_utc
6
+ timeframe type: :absolute,
7
+ starting_time: :started_at_utc,
8
+ ending_time: :ended_at_utc
8
9
  end
9
10
 
10
11
  class ChronologicableWithTimeZone < ActiveRecord::Base
11
- include Chronological::AbsoluteTimeframe
12
+ extend Chronological
12
13
 
13
- absolute_timeframe start_utc: :started_at_utc,
14
- end_utc: :ended_at_utc,
15
- time_zone: :time_zone
14
+ timeframe type: :absolute,
15
+ starting_time: :started_at_utc,
16
+ ending_time: :ended_at_utc,
17
+ time_zone: :time_zone
16
18
  end
17
19
 
18
- describe Chronological::AbsoluteTimeframe, :timecop => true do
20
+ describe Chronological::AbsoluteStrategy, :timecop => true do
19
21
  let(:later) { Time.local(2012, 7, 26, 6, 0, 26) }
20
22
  let(:now) { Time.local(2012, 7, 26, 6, 0, 25) }
21
23
  let(:past) { Time.local(2012, 7, 26, 6, 0, 24) }
@@ -26,90 +28,125 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
26
28
 
27
29
  before { Timecop.freeze(now) }
28
30
 
29
- it { AbsoluteChronologicable.new.respond_to?(:starts_at_utc).should be_true }
30
- it { AbsoluteChronologicable.new.respond_to?(:starting_at_utc).should be_true }
31
- it { AbsoluteChronologicable.new.respond_to?(:ends_at_utc).should be_true }
32
- it { AbsoluteChronologicable.new.respond_to?(:ending_at_utc).should be_true }
33
- it { AbsoluteChronologicable.new.respond_to?(:active?).should be_true }
31
+ describe '.by_date' do
32
+ context 'when there are two chronologicables that start at the same time' do
33
+ context 'but end at different times' do
34
+ let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => past }
35
+ let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
34
36
 
35
- it { AbsoluteChronologicable.respond_to?(:active?).should be_true }
36
- it { AbsoluteChronologicable.respond_to?(:active).should be_true }
37
-
38
- context 'when there are two chronologicables that start at the same time' do
39
- context 'but end at different times' do
40
- let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => past }
41
- let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
37
+ context 'when no option is passed' do
38
+ it 'properly sorts them in ascending order' do
39
+ AbsoluteChronologicable.by_date.first.should eql chronologicable_1
40
+ AbsoluteChronologicable.by_date.last.should eql chronologicable_2
41
+ end
42
+ end
42
43
 
43
- describe '.by_date' do
44
- it 'properly sorts them' do
45
- AbsoluteChronologicable.by_date.first.should eql chronologicable_1
46
- AbsoluteChronologicable.by_date.last.should eql chronologicable_2
44
+ context 'when the :desc option is passed' do
45
+ it 'sorts them backwards by the start date' do
46
+ AbsoluteChronologicable.by_date(:desc).first.should eql chronologicable_2
47
+ AbsoluteChronologicable.by_date(:desc).last.should eql chronologicable_1
48
+ end
47
49
  end
48
50
  end
49
51
 
50
- describe '.by_date_reversed' do
51
- it 'sorts them backwards by the start date' do
52
- AbsoluteChronologicable.by_date_reversed.first.should eql chronologicable_2
53
- AbsoluteChronologicable.by_date_reversed.last.should eql chronologicable_1
52
+ context 'and end at the same time' do
53
+ let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
54
+ let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
55
+
56
+ describe '.by_date' do
57
+ context 'when in ascending order' do
58
+ it 'does not matter what order they are in as long as they are all there' do
59
+ AbsoluteChronologicable.by_date.should include chronologicable_1
60
+ AbsoluteChronologicable.by_date.should include chronologicable_2
61
+ end
62
+ end
63
+
64
+ context 'when in descending order' do
65
+ it 'does not matter what order they are in as long as they are all there' do
66
+ AbsoluteChronologicable.by_date(:desc).should include chronologicable_1
67
+ AbsoluteChronologicable.by_date(:desc).should include chronologicable_2
68
+ end
69
+ end
54
70
  end
55
71
  end
56
72
  end
57
73
 
58
- context 'and end at the same time' do
59
- let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
60
- let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
74
+ context 'when there are two chronologicables that start at different times' do
75
+ context 'and end at different times' do
76
+ let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
77
+ let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => now, :ended_at_utc => later }
61
78
 
62
- describe '.by_date' do
63
- it 'does not matter what order they are in as long as they are all there' do
64
- AbsoluteChronologicable.by_date.should include chronologicable_1
65
- AbsoluteChronologicable.by_date.should include chronologicable_2
79
+ context 'when in ascending order' do
80
+ it 'sorts them by the start date' do
81
+ AbsoluteChronologicable.by_date.first.should eql chronologicable_1
82
+ AbsoluteChronologicable.by_date.last.should eql chronologicable_2
83
+ end
84
+ end
85
+
86
+ context 'when in descending order' do
87
+ it 'sorts them backwards by the start date' do
88
+ AbsoluteChronologicable.by_date(:desc).first.should eql chronologicable_2
89
+ AbsoluteChronologicable.by_date(:desc).last.should eql chronologicable_1
90
+ end
66
91
  end
67
92
  end
68
93
 
69
- describe '.by_date_reversed' do
70
- it 'does not matter what order they are in as long as they are all there' do
71
- AbsoluteChronologicable.by_date.should include chronologicable_1
72
- AbsoluteChronologicable.by_date.should include chronologicable_2
94
+ context 'but end at the same time' do
95
+ let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => later }
96
+ let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => now, :ended_at_utc => later }
97
+
98
+ context 'when in ascending order' do
99
+ it 'sorts them by the start date' do
100
+ AbsoluteChronologicable.by_date.first.should eql chronologicable_1
101
+ AbsoluteChronologicable.by_date.last.should eql chronologicable_2
102
+ end
103
+ end
104
+
105
+ context 'when in descending order' do
106
+ it 'sorts them backwards by the start date' do
107
+ AbsoluteChronologicable.by_date(:desc).first.should eql chronologicable_2
108
+ AbsoluteChronologicable.by_date(:desc).last.should eql chronologicable_1
109
+ end
73
110
  end
74
111
  end
75
112
  end
76
113
  end
77
114
 
78
- context 'when there are two chronologicables that start at different times' do
79
- context 'and end at different times' do
80
- let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => now }
81
- let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => now, :ended_at_utc => later }
115
+ describe '.by_duration' do
116
+ context 'when there are two chronologicables that are different durations' do
117
+ let!(:chronologicable_1) { AbsoluteChronologicable.create(:started_at_utc => 3.seconds.ago, :ended_at_utc => 2.seconds.ago) }
118
+ let!(:chronologicable_2) { AbsoluteChronologicable.create(:started_at_utc => 3.seconds.ago, :ended_at_utc => 1.second.ago) }
82
119
 
83
- describe '.by_date' do
84
- it 'sorts them by the start date' do
120
+ context 'when no option is passed' do
121
+ it 'properly sorts them in ascending order' do
85
122
  AbsoluteChronologicable.by_date.first.should eql chronologicable_1
86
123
  AbsoluteChronologicable.by_date.last.should eql chronologicable_2
87
124
  end
88
125
  end
89
126
 
90
- describe '.by_date_reversed' do
127
+ context 'when the :desc option is passed' do
91
128
  it 'sorts them backwards by the start date' do
92
- AbsoluteChronologicable.by_date_reversed.first.should eql chronologicable_2
93
- AbsoluteChronologicable.by_date_reversed.last.should eql chronologicable_1
129
+ AbsoluteChronologicable.by_date(:desc).first.should eql chronologicable_2
130
+ AbsoluteChronologicable.by_date(:desc).last.should eql chronologicable_1
94
131
  end
95
132
  end
96
133
  end
97
134
 
98
- context 'but end at the same time' do
99
- let!(:chronologicable_1) { AbsoluteChronologicable.create :started_at_utc => past, :ended_at_utc => later }
100
- let!(:chronologicable_2) { AbsoluteChronologicable.create :started_at_utc => now, :ended_at_utc => later }
135
+ context 'when there are two chronologicables that are the same duration' do
136
+ let!(:chronologicable_1) { AbsoluteChronologicable.create(:started_at_utc => 3.seconds.ago, :ended_at_utc => 1.second.ago) }
137
+ let!(:chronologicable_2) { AbsoluteChronologicable.create(:started_at_utc => 3.seconds.ago, :ended_at_utc => 1.second.ago) }
101
138
 
102
- describe '.by_date' do
103
- it 'sorts them by the start date' do
104
- AbsoluteChronologicable.by_date.first.should eql chronologicable_1
105
- AbsoluteChronologicable.by_date.last.should eql chronologicable_2
139
+ context 'when no option is passed' do
140
+ it 'does not matter what order they are in' do
141
+ AbsoluteChronologicable.by_date.should include chronologicable_1
142
+ AbsoluteChronologicable.by_date.should include chronologicable_2
106
143
  end
107
144
  end
108
145
 
109
- describe '.by_date_reversed' do
110
- it 'sorts them backwards by the start date' do
111
- AbsoluteChronologicable.by_date_reversed.first.should eql chronologicable_2
112
- AbsoluteChronologicable.by_date_reversed.last.should eql chronologicable_1
146
+ context 'when the :desc option is passed' do
147
+ it 'does not matter what order they are in' do
148
+ AbsoluteChronologicable.by_date(:desc).should include chronologicable_1
149
+ AbsoluteChronologicable.by_date(:desc).should include chronologicable_2
113
150
  end
114
151
  end
115
152
  end
@@ -304,9 +341,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
304
341
  end
305
342
  end
306
343
 
307
- describe '.expired' do
344
+ describe '.ended' do
308
345
  it 'includes that chronologicable' do
309
- AbsoluteChronologicable.expired.should include chronologicable
346
+ AbsoluteChronologicable.ended.should include chronologicable
310
347
  end
311
348
  end
312
349
 
@@ -316,9 +353,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
316
353
  end
317
354
  end
318
355
 
319
- describe '.current' do
356
+ describe '.not_yet_ended' do
320
357
  it 'does not include that chronologicable' do
321
- AbsoluteChronologicable.current.should_not include chronologicable
358
+ AbsoluteChronologicable.not_yet_ended.should_not include chronologicable
322
359
  end
323
360
  end
324
361
 
@@ -338,9 +375,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
338
375
  end
339
376
  end
340
377
 
341
- describe '.expired' do
378
+ describe '.ended' do
342
379
  it 'does include that chronologicable' do
343
- AbsoluteChronologicable.expired.should include chronologicable
380
+ AbsoluteChronologicable.ended.should include chronologicable
344
381
  end
345
382
  end
346
383
 
@@ -350,9 +387,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
350
387
  end
351
388
  end
352
389
 
353
- describe '.current' do
390
+ describe '.not_yet_ended' do
354
391
  it 'does not include that chronologicable' do
355
- AbsoluteChronologicable.current.should_not include chronologicable
392
+ AbsoluteChronologicable.not_yet_ended.should_not include chronologicable
356
393
  end
357
394
  end
358
395
 
@@ -372,9 +409,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
372
409
  end
373
410
  end
374
411
 
375
- describe '.expired' do
412
+ describe '.ended' do
376
413
  it 'does not include that chronologicable' do
377
- AbsoluteChronologicable.expired.should_not include chronologicable
414
+ AbsoluteChronologicable.ended.should_not include chronologicable
378
415
  end
379
416
  end
380
417
 
@@ -384,9 +421,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
384
421
  end
385
422
  end
386
423
 
387
- describe '.current' do
424
+ describe '.not_yet_ended' do
388
425
  it 'includes that chronologicable' do
389
- AbsoluteChronologicable.current.should include chronologicable
426
+ AbsoluteChronologicable.not_yet_ended.should include chronologicable
390
427
  end
391
428
  end
392
429
 
@@ -410,9 +447,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
410
447
  end
411
448
  end
412
449
 
413
- describe '.expired' do
450
+ describe '.ended' do
414
451
  it 'does include that chronologicable' do
415
- AbsoluteChronologicable.expired.should include chronologicable
452
+ AbsoluteChronologicable.ended.should include chronologicable
416
453
  end
417
454
  end
418
455
 
@@ -422,9 +459,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
422
459
  end
423
460
  end
424
461
 
425
- describe '.current' do
462
+ describe '.not_yet_ended' do
426
463
  it 'does not include that chronologicable' do
427
- AbsoluteChronologicable.current.should_not include chronologicable
464
+ AbsoluteChronologicable.not_yet_ended.should_not include chronologicable
428
465
  end
429
466
  end
430
467
 
@@ -444,9 +481,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
444
481
  end
445
482
  end
446
483
 
447
- describe '.expired' do
484
+ describe '.ended' do
448
485
  it 'does not include that chronologicable' do
449
- AbsoluteChronologicable.expired.should_not include chronologicable
486
+ AbsoluteChronologicable.ended.should_not include chronologicable
450
487
  end
451
488
  end
452
489
 
@@ -456,9 +493,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
456
493
  end
457
494
  end
458
495
 
459
- describe '.current' do
496
+ describe '.not_yet_ended' do
460
497
  it 'includes that chronologicable' do
461
- AbsoluteChronologicable.current.should include chronologicable
498
+ AbsoluteChronologicable.not_yet_ended.should include chronologicable
462
499
  end
463
500
  end
464
501
 
@@ -480,9 +517,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
480
517
  end
481
518
  end
482
519
 
483
- describe '.expired' do
520
+ describe '.ended' do
484
521
  it 'does not include that chronologicable' do
485
- AbsoluteChronologicable.expired.should_not include chronologicable
522
+ AbsoluteChronologicable.ended.should_not include chronologicable
486
523
  end
487
524
  end
488
525
 
@@ -492,9 +529,9 @@ describe Chronological::AbsoluteTimeframe, :timecop => true do
492
529
  end
493
530
  end
494
531
 
495
- describe '.current' do
532
+ describe '.not_yet_ended' do
496
533
  it 'includes that chronologicable' do
497
- AbsoluteChronologicable.current.should include chronologicable
534
+ AbsoluteChronologicable.not_yet_ended.should include chronologicable
498
535
  end
499
536
  end
500
537