aggtive_record 0.1.2 → 0.1.5
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.
- checksums.yaml +8 -8
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/aggtive_record.gemspec +7 -3
- data/lib/aggtive_record/egg_scopes/collation/count_by.rb +11 -0
- data/lib/aggtive_record/egg_scopes/collation/rate_per.rb +76 -0
- data/lib/aggtive_record/egg_scopes/collation.rb +1 -1
- data/lib/aggtive_record/time.rb +8 -2
- data/spec/functional/collation_spec.rb +45 -0
- data/spec/lib/rate_spec.rb +45 -28
- data/spec/spec_helper.rb +2 -0
- metadata +18 -3
- data/lib/aggtive_record/egg_scopes/collation/rate.rb +0 -35
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzM2ZGIxNTQ3MjU2MmI0ZGQ2YmJmOTJjMjQxYjQxZTJmNGYwODI1ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MmY0YmQ4ZDE1NGNkNTU2ZDZkNjFmNzg2YTczNjIyY2Q4NjIxZGFkNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MGZkMWFhMTFiMGMzODllNmY0ZDI5MmNmYWM4Zjg0NDA4MjRkZjQ4YmNhNzFm
|
10
|
+
MmQ1ODRlMWVlMjg1ZDY0MmJjNDZmOTBiMDRmMjNmMzBiZDYxOTc4NjFlNWM0
|
11
|
+
M2JhMWM3NDJhN2IxMWNkOWU5ZTNmMTJlYTg2MjU0YWFiMTZjYzg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MGQyOWZhNWMzMjgwMjVmNGM1N2RkMGJhZDA0NjI1MWEyZjNiNzk4YjJiNTNm
|
14
|
+
ZjRiMzNjNjlhZmYyMWUzODcwNTA3OWYwNzRhNzhlZWQ1NzhlMTZhMzE3Y2I1
|
15
|
+
MmI5Mzk2NWI0MzM2NGJkZmJhNGYyODkyOTNmNDAwNTlkODNjMjU=
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.5
|
data/aggtive_record.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "aggtive_record"
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Dan Nguyen"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-10-02"
|
13
13
|
s.description = "This is not even remotely finished or even started on. Please don't download."
|
14
14
|
s.email = "dansonguyen@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -35,12 +35,13 @@ Gem::Specification.new do |s|
|
|
35
35
|
"lib/aggtive_record/egg_scopes.rb",
|
36
36
|
"lib/aggtive_record/egg_scopes/collation.rb",
|
37
37
|
"lib/aggtive_record/egg_scopes/collation/count_by.rb",
|
38
|
-
"lib/aggtive_record/egg_scopes/collation/
|
38
|
+
"lib/aggtive_record/egg_scopes/collation/rate_per.rb",
|
39
39
|
"lib/aggtive_record/egg_scopes/time_bucket.rb",
|
40
40
|
"lib/aggtive_record/egg_scopes/time_span.rb",
|
41
41
|
"lib/aggtive_record/memo.rb",
|
42
42
|
"lib/aggtive_record/time.rb",
|
43
43
|
"spec/functional/basic_object_run_spec.rb",
|
44
|
+
"spec/functional/collation_spec.rb",
|
44
45
|
"spec/lib/aggable_spec.rb",
|
45
46
|
"spec/lib/count_by_spec.rb",
|
46
47
|
"spec/lib/rate_spec.rb",
|
@@ -67,6 +68,7 @@ Gem::Specification.new do |s|
|
|
67
68
|
s.add_development_dependency(%q<database_cleaner>, ["~> 1.0.1"])
|
68
69
|
s.add_development_dependency(%q<mysql2>, [">= 0"])
|
69
70
|
s.add_development_dependency(%q<activerecord>, ["~> 3.2.14"])
|
71
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
70
72
|
else
|
71
73
|
s.add_dependency(%q<groupdate>, [">= 0"])
|
72
74
|
s.add_dependency(%q<activesupport>, ["~> 3.2.14"])
|
@@ -77,6 +79,7 @@ Gem::Specification.new do |s|
|
|
77
79
|
s.add_dependency(%q<database_cleaner>, ["~> 1.0.1"])
|
78
80
|
s.add_dependency(%q<mysql2>, [">= 0"])
|
79
81
|
s.add_dependency(%q<activerecord>, ["~> 3.2.14"])
|
82
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
80
83
|
end
|
81
84
|
else
|
82
85
|
s.add_dependency(%q<groupdate>, [">= 0"])
|
@@ -88,6 +91,7 @@ Gem::Specification.new do |s|
|
|
88
91
|
s.add_dependency(%q<database_cleaner>, ["~> 1.0.1"])
|
89
92
|
s.add_dependency(%q<mysql2>, [">= 0"])
|
90
93
|
s.add_dependency(%q<activerecord>, ["~> 3.2.14"])
|
94
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
91
95
|
end
|
92
96
|
end
|
93
97
|
|
@@ -12,8 +12,19 @@ module AggtiveRecord
|
|
12
12
|
span_foo = "by_#{time_period}"
|
13
13
|
self.send(span_foo).count
|
14
14
|
end
|
15
|
+
|
16
|
+
# define dynamically
|
17
|
+
AggtiveRecord::Time.periods.each do |period_name|
|
18
|
+
foo_name = "count_by_#{period_name}".to_sym
|
19
|
+
# defining scope here, dynamically
|
20
|
+
define_method foo_name do
|
21
|
+
self.count_by(period_name)
|
22
|
+
end
|
23
|
+
end
|
15
24
|
end
|
16
25
|
|
26
|
+
|
27
|
+
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module AggtiveRecord
|
2
|
+
module EggScopes
|
3
|
+
module Collation
|
4
|
+
module Rate
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Public: a rate
|
8
|
+
# expects that ActiveRelation has a grouping
|
9
|
+
# self is a ActiveRecord scope
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Public
|
14
|
+
#
|
15
|
+
# Returns float indicating rate of records per given time period
|
16
|
+
def rate_per(time_period, timespan_in_seconds = nil)
|
17
|
+
# tk: this may be unnecessary
|
18
|
+
records = self.scoped.to_a
|
19
|
+
|
20
|
+
time_period_secs = AggtiveRecord::Time.to_seconds(time_period)
|
21
|
+
timespan_in_seconds ||= self.timespan_to_now(records)
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
return records.size.to_f * time_period_secs / timespan_in_seconds
|
26
|
+
end
|
27
|
+
|
28
|
+
# defines rate_per_year, rate_per_hour
|
29
|
+
# except that rate_per_year also accepts an optional argument
|
30
|
+
|
31
|
+
AggtiveRecord::Time.periods.each do |period_name|
|
32
|
+
foo_name = "rate_per_#{period_name}".to_sym
|
33
|
+
# defining scope here, dynamically
|
34
|
+
define_method foo_name do |*args|
|
35
|
+
|
36
|
+
|
37
|
+
if args[0].present?
|
38
|
+
# i.e: #rate_per_month(:past_year)
|
39
|
+
past_scope = args[0] # past_year
|
40
|
+
raise ArgumentError, "Must be a scope with 'past_'" unless past_scope.to_s =~ /^past_/
|
41
|
+
|
42
|
+
time_scoped_records = self.send( past_scope )
|
43
|
+
past_time_span_name = past_scope.to_s.match(/past_(\w+)/)[1]
|
44
|
+
past_period_in_seconds = AggtiveRecord::Time.to_seconds(past_time_span_name)
|
45
|
+
else
|
46
|
+
time_scoped_records = scoped
|
47
|
+
past_period_in_seconds = self.timespan_to_now(time_scoped_records)
|
48
|
+
end
|
49
|
+
|
50
|
+
# puts "Past #{past_time_span_name} in seconds: #{past_period_in_seconds}"
|
51
|
+
time_scoped_records.send( :rate_per, period_name, past_period_in_seconds )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# included do
|
58
|
+
|
59
|
+
# # singular time periods
|
60
|
+
# # e.g. scope :past_year, ->{ past_time_periods(1, :year)}
|
61
|
+
|
62
|
+
|
63
|
+
# end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
=begin
|
71
|
+
|
72
|
+
Record.rate_per :hour
|
73
|
+
.rate_per :day
|
74
|
+
|
75
|
+
|
76
|
+
=end
|
data/lib/aggtive_record/time.rb
CHANGED
@@ -21,8 +21,12 @@ module AggtiveRecord
|
|
21
21
|
SECONDS_PER_DAY = 60 * 60 * 24
|
22
22
|
|
23
23
|
# probably reinventing the wheel here...
|
24
|
-
def self.to_seconds(
|
25
|
-
|
24
|
+
def self.to_seconds(str)
|
25
|
+
|
26
|
+
num, period = str.to_s.match(/^(\d*)_?(\w+?)s?$/)[1..2]
|
27
|
+
num = num.to_i > 0 ? num.to_i : 1 # ugh
|
28
|
+
|
29
|
+
secs = case period.to_sym
|
26
30
|
when :year
|
27
31
|
SECONDS_PER_DAY * 365
|
28
32
|
when :month
|
@@ -38,6 +42,8 @@ module AggtiveRecord
|
|
38
42
|
when :second
|
39
43
|
1
|
40
44
|
end
|
45
|
+
|
46
|
+
num * secs
|
41
47
|
end
|
42
48
|
|
43
49
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe AggtiveRecord do
|
5
|
+
|
6
|
+
|
7
|
+
context 'collation methods acting in concert' do
|
8
|
+
before(:each) do
|
9
|
+
Timecop.freeze(Time.parse '2013-10-02')
|
10
|
+
MusicRecord.create(published_at: 5.days.ago)
|
11
|
+
MusicRecord.create(published_at: 1.month.ago)
|
12
|
+
MusicRecord.create(published_at: 9.months.ago)
|
13
|
+
MusicRecord.create(published_at: 14.months.ago)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it '#past_14_days' do
|
18
|
+
expect(MusicRecord.past_14_days.count).to eq 1
|
19
|
+
end
|
20
|
+
|
21
|
+
it '#rate_per_week(:past_14_days)' do
|
22
|
+
expect(MusicRecord.rate_per_week(:past_14_days)).to eq 0.5
|
23
|
+
end
|
24
|
+
|
25
|
+
it '#past_year' do
|
26
|
+
expect(MusicRecord.past_year.count).to eq 3
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it '#past_year.count_by_year' do
|
31
|
+
expect(MusicRecord.past_year.count_by_year).to eq( {Time.new(Time.now.year) => 3})
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it '#past_year.count_by_week' do
|
36
|
+
expect(MusicRecord.past_year.count_by_week).to eq(
|
37
|
+
{ Time.parse( "2012-12-30 00:00:00 -0500") =>1,
|
38
|
+
Time.parse( "2013-09-01 00:00:00 -0400") =>1,
|
39
|
+
Time.parse( "2013-09-22 00:00:00 -0400") =>1
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/spec/lib/rate_spec.rb
CHANGED
@@ -3,47 +3,34 @@ require 'spec_helper'
|
|
3
3
|
describe "AggtiveRecord::EggScopes -- .rate" do
|
4
4
|
|
5
5
|
|
6
|
-
describe '#
|
6
|
+
describe '#rate_per' do
|
7
7
|
context 'singular periods' do
|
8
8
|
it 'should get about 1 a year' do
|
9
9
|
@record = MusicRecord.create published_at: 12.months.ago
|
10
10
|
expect(MusicRecord.scoped.rate_per(:year) ).to be_within(0.1).of 1
|
11
11
|
end
|
12
|
-
|
13
|
-
|
14
|
-
context 'has two optional parameters' do
|
15
|
-
|
16
|
-
before(:each) do
|
17
|
-
MusicRecord.create(published_at: 1.day.ago )
|
18
|
-
end
|
12
|
+
|
19
13
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
expect(records.rate_per(:day, 2.days.ago)).to be_within(0.1).of 0.5
|
14
|
+
context 'meta methods' do
|
15
|
+
it 'should have #rate_per_month' do
|
16
|
+
MusicRecord.create published_at: (1.month.ago - 1.second)
|
17
|
+
MusicRecord.create published_at: 12.days.ago
|
18
|
+
expect(MusicRecord.rate_per_month ).to be_within(0.01).of 2
|
26
19
|
end
|
27
|
-
end
|
28
20
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
expect(
|
21
|
+
it 'should have #rate_per_hour' do
|
22
|
+
MusicRecord.create published_at: (59.minutes.ago)
|
23
|
+
MusicRecord.create published_at: 59.minutes.ago
|
24
|
+
expect(MusicRecord.rate_per_hour ).to be_within(0.1).of 2
|
33
25
|
end
|
34
26
|
|
35
|
-
it 'has no effect on :where' do
|
36
|
-
pending('This is troublesome. What if a user calls:
|
37
|
-
records.past_year.rate_per(:day, 10.days.ago, 3.days.ago)
|
38
|
-
-- too many surprises here!
|
39
|
-
')
|
40
|
-
end
|
41
27
|
end
|
42
28
|
|
43
|
-
|
29
|
+
|
44
30
|
it 'should raise an error when a non-time period is passed in'
|
45
|
-
|
31
|
+
|
46
32
|
end
|
33
|
+
|
47
34
|
end
|
48
35
|
|
49
36
|
describe '#timespan_of' do
|
@@ -64,6 +51,36 @@ describe "AggtiveRecord::EggScopes -- .rate" do
|
|
64
51
|
|
65
52
|
it 'should get #latest record in a set without re-querying database'
|
66
53
|
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# This is not usable
|
58
|
+
#
|
59
|
+
# context 'has two optional parameters' do
|
60
|
+
|
61
|
+
# before(:each) do
|
62
|
+
# MusicRecord.create(published_at: 1.day.ago )
|
63
|
+
# end
|
64
|
+
|
65
|
+
# let(:records){ MusicRecord.scoped }
|
66
|
+
|
67
|
+
# context 'first parameter is the :start_time' do
|
68
|
+
# it 'bounds range with :start_time and Time.now' do
|
69
|
+
# pending 'rethink'
|
70
|
+
# expect(records.rate_per(:day, 2.days.ago)).to be_within(0.1).of 0.5
|
71
|
+
# end
|
72
|
+
# end
|
67
73
|
|
74
|
+
# context 'second parameter is the end_time' do
|
75
|
+
# it 'bounds range with :start_time and :end_time' do
|
76
|
+
# pending 'rethink'
|
77
|
+
# expect(records.rate_per(:day, 2.days.ago)).to be_within(0.1).of 0.5
|
78
|
+
# end
|
68
79
|
|
69
|
-
|
80
|
+
# it 'has no effect on :where' do
|
81
|
+
# pending('This is troublesome. What if a user calls:
|
82
|
+
# records.past_year.rate_per(:day, 10.days.ago, 3.days.ago)
|
83
|
+
# -- too many surprises here!
|
84
|
+
# ')
|
85
|
+
# end
|
86
|
+
# end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,6 +9,8 @@ require 'database_cleaner'
|
|
9
9
|
require 'aggtive_record'
|
10
10
|
require 'pry'
|
11
11
|
|
12
|
+
require 'timecop'
|
13
|
+
|
12
14
|
# Requires supporting files with custom matchers and macros, etc,
|
13
15
|
# in ./support/ and its subdirectories.
|
14
16
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aggtive_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: groupdate
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ~>
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 3.2.14
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: timecop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
description: This is not even remotely finished or even started on. Please don't download.
|
140
154
|
email: dansonguyen@gmail.com
|
141
155
|
executables: []
|
@@ -162,12 +176,13 @@ files:
|
|
162
176
|
- lib/aggtive_record/egg_scopes.rb
|
163
177
|
- lib/aggtive_record/egg_scopes/collation.rb
|
164
178
|
- lib/aggtive_record/egg_scopes/collation/count_by.rb
|
165
|
-
- lib/aggtive_record/egg_scopes/collation/
|
179
|
+
- lib/aggtive_record/egg_scopes/collation/rate_per.rb
|
166
180
|
- lib/aggtive_record/egg_scopes/time_bucket.rb
|
167
181
|
- lib/aggtive_record/egg_scopes/time_span.rb
|
168
182
|
- lib/aggtive_record/memo.rb
|
169
183
|
- lib/aggtive_record/time.rb
|
170
184
|
- spec/functional/basic_object_run_spec.rb
|
185
|
+
- spec/functional/collation_spec.rb
|
171
186
|
- spec/lib/aggable_spec.rb
|
172
187
|
- spec/lib/count_by_spec.rb
|
173
188
|
- spec/lib/rate_spec.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module AggtiveRecord
|
2
|
-
module EggScopes
|
3
|
-
module Collation
|
4
|
-
module Rate
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
# Public: a rate
|
8
|
-
# expects that ActiveRelation has a grouping
|
9
|
-
# self is a ActiveRecord scope
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
|
13
|
-
# Public
|
14
|
-
#
|
15
|
-
# Returns float indicating rate of records per given time period
|
16
|
-
def rate_per(time_period)
|
17
|
-
time_period_secs = AggtiveRecord::Time.to_seconds(time_period)
|
18
|
-
records = self.scoped.to_a
|
19
|
-
|
20
|
-
return records.size.to_f * time_period_secs / self.timespan_to_now(records)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
=begin
|
30
|
-
|
31
|
-
Record.rate_per :hour
|
32
|
-
.rate_per :day
|
33
|
-
|
34
|
-
|
35
|
-
=end
|