chronicle 0.0.6 → 0.1.0

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.
@@ -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