chronicle 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -51,7 +51,7 @@ module Chronicle
51
51
  "3 minutes ago",
52
52
  "2 minutes ago",
53
53
  "1 minute ago",
54
- "just now",
54
+ "right now",
55
55
  "1 minute from now",
56
56
  "2 minutes from now",
57
57
  "3 minutes from now",
@@ -98,59 +98,60 @@ module Chronicle
98
98
  def initialize(collection, options)
99
99
 
100
100
  eras = options[:eras]
101
-
102
- # Sort order, defaut is new to old
103
- order = options[:order] || :desc
104
-
101
+
105
102
  # Remove objects with nil timestamps
106
- collection = collection.reject {|obj| obj.send(options[:date_attr]).nil? }
103
+ collection.reject! {|obj| obj.send(options[:date_attr]).nil? }
104
+
105
+ # Determine whether collection contains future or past timestamps
106
+ if collection.all? { |obj| obj.send(options[:date_attr]) < Time.now }
107
+ order = :past
108
+ elsif collection.all? { |obj| obj.send(options[:date_attr]) > Time.now }
109
+ order = :future
110
+ else
111
+ raise "Chronicle collections must be entirely in the past or the future."
112
+ end
107
113
 
108
114
  # Sort collection by date
109
- collection = collection.sort_by {|obj| obj.send(options[:date_attr])}
110
- collection = collection.reverse if order == :desc
115
+ # For past collections, newest objects come first
116
+ # For future collections, oldest objects come first
117
+ collection = collection.sort_by {|obj| obj.send(options[:date_attr]) }
118
+ collection.reverse! if order == :past
119
+
120
+ # Force inclusion of 'now' era in case it's missing.
121
+ eras.push('right now').uniq!
111
122
 
123
+ # Parse era strings using Chronic
112
124
  # Ensure all eras can be parsed
113
- eras.each do |era|
114
- raise "Could not parse era: #{era}" if Chronic.parse(era).nil?
115
- end
125
+ # { "7 years ago" => 2006-01-02 23:29:05 -0800, ... }
126
+ era_date_pairs = eras.inject({}) {|h,era|
127
+ h[era] = Chronic.parse(era)
128
+ raise "Could not parse era: #{era}" if h[era].nil?
129
+ h
130
+ }
116
131
 
117
- if order == :desc && Time.now > collection.first.send(options[:date_attr])
118
- eras << "just now"
119
- end
120
-
121
- # Parse date strings
122
- # { "7 years ago"=>2006-01-02 23:29:05 -0800, ... }
123
- era_date_pairs = eras.inject({}) {|h,e| h[e] = Chronic.parse(e); h }
124
-
125
- # Sort eras oldest to newest
126
- eras = eras.sort_by {|era| Chronic.parse(era) }
127
- # .. or newest to oldest
128
- eras = eras.reverse unless order == :desc
132
+ # Sort eras by date
133
+ # For past collections, newest eras come first
134
+ # For future collections, oldest eras come first
135
+ eras = eras.sort_by {|era| era_date_pairs[era] }
136
+ eras.reverse! if order == :future
129
137
 
130
- if order == :desc
131
-
132
- # Initialize all hash keys chronologically (newest to oldest)
133
- eras.reverse.each {|era| self[era] = [] }
134
-
135
- # Find the oldest era in which each object was created
136
- collection.each do |obj|
137
- # puts ("\n #{obj.send(options[:date_attr])} < #{era_date_pairs[era]}")
138
- era = eras.find {|era| obj.send(options[:date_attr]) < era_date_pairs[era] }
139
- self[era] << obj
140
- end
141
- else
142
-
143
- # Initialize all hash keys chronologically (oldest to newest)
144
- eras.reverse.each {|era| self[era] = [] }
145
-
146
- # Find the newest era in which each object was created
147
- collection.each do |obj|
148
- era = eras.find {|era| obj.send(options[:date_attr]) > era_date_pairs[era] }
149
- self[era] << obj
138
+ # Initialize all hash keys chronologically
139
+ eras.reverse.each {|era| self[era] = [] }
140
+
141
+ collection.each do |obj|
142
+ era = eras.find do |era|
143
+ if order == :future
144
+ # Find newest possible era for the object
145
+ obj.send(options[:date_attr]) > era_date_pairs[era]
146
+ else
147
+ # Find oldest possible era for the object
148
+ obj.send(options[:date_attr]) < era_date_pairs[era]
149
+ end
150
150
  end
151
+ self[era] << obj
151
152
  end
152
153
 
153
- # Remove keys for empty eras
154
+ # Remove empty eras
154
155
  self.keys.each {|k| self.delete(k) if self[k].empty? }
155
156
 
156
157
  self
@@ -1,3 +1,3 @@
1
1
  module Chronicle
2
- VERSION = "0.0.6"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -6,54 +6,114 @@ describe Chronicle do
6
6
  @minute = 60
7
7
  @hour = @minute*60
8
8
  @day = @hour*24
9
- @things = [
10
- double("thing", :created_at => Time.now - 39*@day),
11
- double("thing", :created_at => Time.now - 8*@day),
12
- double("thing", :created_at => Time.now - 9*@day),
13
- double("thing", :created_at => Time.now - 3*@day),
14
- double("thing", :created_at => Time.now - 10*@minute),
15
- double("thing", :created_at => Time.now)
16
- ]
17
-
18
- @chronicle = Chronicle.new(@things)
19
9
  end
10
+
11
+ context "dates in the past and the future" do
12
+
13
+ before do
14
+ offsets = [@day, -@day]
15
+ @things = offsets.map do |offset|
16
+ double("thing", :created_at => Time.now+offset)
17
+ end
18
+ end
20
19
 
21
- it "doesn't have any empty eras" do
22
- @chronicle.values.all? {|v| !v.empty? }.should == true
20
+ it "raises an error" do
21
+ expect { Chronicle.new(@things) }.to raise_error("Chronicle collections must be entirely in the past or the future.")
22
+ end
23
+
23
24
  end
24
25
 
25
- it "sorts era keys from newest to oldest" do
26
- @chronicle.keys.first.should == 'just now'
27
- @chronicle.keys.last.should == '1 month ago'
28
- end
26
+ context "dates in the past" do
27
+
28
+ before do
29
+ offsets = [-39*@day, -8*@day, -9*@day, -3*@day, -10*@minute, 0]
30
+ @things = offsets.map do |offset|
31
+ double("thing", :created_at => Time.now+offset)
32
+ end
33
+ @chronicle = Chronicle.new(@things)
34
+ end
35
+
36
+ it "doesn't have any empty eras" do
37
+ @chronicle.values.all? {|v| !v.empty? }.should == true
38
+ end
29
39
 
30
- it "sorts objects in eras from newest to oldest" do
31
- era = @chronicle['1 week ago']
32
- era.size.should == 2
33
- era.last.created_at.should be < era.first.created_at
34
- end
40
+ it "sorts era keys from newest to oldest" do
41
+ @chronicle.keys.first.should == 'right now'
42
+ @chronicle.keys.last.should == '1 month ago'
43
+ end
35
44
 
36
- it "doesn't lose any items during processing" do
37
- @chronicle.values.flatten.size.should == @things.size
38
- end
45
+ it "sorts objects in eras from newest to oldest" do
46
+ era = @chronicle['1 week ago']
47
+ era.size.should == 2
48
+ era.last.created_at.should be < era.first.created_at
49
+ end
39
50
 
40
- it "accounts for objects that were just created" do
41
- now = @chronicle['just now']
42
- now.should_not be_empty
43
- now.should be_an(Array)
44
- now.first.should == @things.last
51
+ it "doesn't lose any items during processing" do
52
+ @chronicle.values.flatten.size.should == @things.size
53
+ end
54
+
55
+ it "accounts for objects that were just created" do
56
+ now = @chronicle['right now']
57
+ now.should_not be_empty
58
+ now.should be_an(Array)
59
+ now.first.should == @things.last
60
+ end
61
+
45
62
  end
46
63
 
64
+ context "dates in the future" do
65
+
66
+ before(:each) do
67
+ @things = [
68
+ double("thing", :created_at => Time.now + 39*@day),
69
+ double("thing", :created_at => Time.now + 9*@day),
70
+ double("thing", :created_at => Time.now + 8*@day),
71
+ double("thing", :created_at => Time.now + 3*@day),
72
+ double("thing", :created_at => Time.now + 9*@minute),
73
+ double("thing", :created_at => Time.now + 2),
74
+ ]
75
+ @chronicle = Chronicle.new(@things, order: :asc)
76
+ end
77
+
78
+ it "doesn't have any empty eras" do
79
+ @chronicle.values.all? {|v| !v.empty? }.should == true
80
+ end
81
+
82
+ it "sorts era keys from oldest to newest" do
83
+ @chronicle.keys.first.should == 'right now'
84
+ @chronicle.keys.last.should == '1 month from now'
85
+ end
86
+
87
+ it "sorts objects in eras from oldest to newest" do
88
+ era = @chronicle['1 week from now']
89
+ era.size.should == 2
90
+ era.last.created_at.should be > era.first.created_at
91
+ end
92
+
93
+ it "doesn't lose any items during processing" do
94
+ @chronicle.values.flatten.size.should == @things.size
95
+ end
96
+
97
+ end
98
+
47
99
  context "custom eras" do
100
+
101
+ before do
102
+ offsets = [-39*@day, -8*@day, -9*@day, -3*@day, -10*@minute, 0]
103
+ @things = offsets.map do |offset|
104
+ double("thing", :created_at => Time.now+offset)
105
+ end
106
+ @chronicle = Chronicle.new(@things)
107
+ end
48
108
 
49
- it "add 'just now' to the list of eras if it's missing, to keep from losing very new objects" do
109
+ it "add 'right now' to the list of eras if it's missing, to keep from losing very new objects" do
50
110
  @chronicle = Chronicle.new(@things, :eras => ['3 minutes ago', '35 days ago'])
51
- @chronicle.keys.first.should == 'just now'
111
+ @chronicle.keys.first.should == 'right now'
52
112
  end
53
113
 
54
114
  it "allows custom eras to be set in any order" do
55
- @chronicle = Chronicle.new(@things, :eras => ['just now', '35 days ago', '3 minutes ago'])
56
- @chronicle.keys.should == ['just now', '3 minutes ago', '35 days ago']
115
+ @chronicle = Chronicle.new(@things, :eras => ['right now', '35 days ago', '3 minutes ago'])
116
+ @chronicle.keys.should == ['right now', '3 minutes ago', '35 days ago']
57
117
  end
58
118
 
59
119
  it "raises an exception for eras that cannot be parsed" do
@@ -79,7 +139,7 @@ describe Chronicle do
79
139
  @chronicle = Chronicle.new(@things, :date_attr => :updated_at)
80
140
  @chronicle.values.flatten.size.should == @things.size
81
141
  @chronicle.keys.last.should == '1 year ago'
82
- @chronicle.keys.first.should == 'just now'
142
+ @chronicle.keys.first.should == 'right now'
83
143
  end
84
144
 
85
145
  it "gracefully ignores objects with nil timestamps" do
@@ -93,40 +153,5 @@ describe Chronicle do
93
153
  end
94
154
 
95
155
  end
96
-
97
- context "future dates" do
98
-
99
- before(:each) do
100
- @things = [
101
- double("thing", :created_at => Time.now + 39*@day),
102
- double("thing", :created_at => Time.now + 8*@day),
103
- double("thing", :created_at => Time.now + 9*@day),
104
- double("thing", :created_at => Time.now + 3*@day),
105
- double("thing", :created_at => Time.now + 9*@minute),
106
- ]
107
- @chronicle = Chronicle.new(@things, order: :asc)
108
- end
109
-
110
- it "doesn't have any empty eras" do
111
- @chronicle.values.all? {|v| !v.empty? }.should == true
112
- end
113
-
114
- it "sorts era keys from oldest to newest" do
115
- @chronicle.keys.first.should == '5 minutes from now'
116
- @chronicle.keys.last.should == '1 month from now'
117
- end
118
-
119
- it "sorts objects in eras from oldest to newest" do
120
- era = @chronicle['1 week from now']
121
- era.size.should == 2
122
- era.last.created_at.should be > era.first.created_at
123
- end
124
-
125
- it "doesn't lose any items during processing" do
126
- @chronicle.values.flatten.size.should == @things.size
127
- end
128
-
129
- end
130
-
131
156
 
132
157
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-03 00:00:00.000000000 Z
12
+ date: 2013-01-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hoe
@@ -106,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
106
  version: '0'
107
107
  segments:
108
108
  - 0
109
- hash: -4597408090393416326
109
+ hash: 408063275270650171
110
110
  required_rubygems_version: !ruby/object:Gem::Requirement
111
111
  none: false
112
112
  requirements:
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  version: '0'
116
116
  segments:
117
117
  - 0
118
- hash: -4597408090393416326
118
+ hash: 408063275270650171
119
119
  requirements: []
120
120
  rubyforge_project: chronicle
121
121
  rubygems_version: 1.8.24