calculon 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.rubocop.yml +96 -0
- data/.ruby-version +1 -1
- data/calculon.gemspec +1 -0
- data/lib/calculon.rb +15 -16
- data/lib/calculon/ext.rb +1 -1
- data/lib/calculon/railtie.rb +0 -2
- data/lib/calculon/results.rb +32 -28
- data/lib/calculon/version.rb +1 -1
- data/test/calculon_test.rb +6 -6
- metadata +21 -4
data/.rubocop.yml
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- calculon.gemspec
|
4
|
+
|
5
|
+
AndOr:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
StringLiterals:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
AccessorMethodName:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
ClassLength:
|
15
|
+
Max: 300
|
16
|
+
|
17
|
+
Documentation:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Encoding:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
BracesAroundHashParameters:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Blocks:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
ClassVars:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
CollectionMethods:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
CyclomaticComplexity:
|
36
|
+
Max: 14
|
37
|
+
|
38
|
+
HandleExceptions:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
HashSyntax:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
IfUnlessModifier:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
LineLength:
|
48
|
+
Max: 183
|
49
|
+
|
50
|
+
MethodLength:
|
51
|
+
Max: 40
|
52
|
+
|
53
|
+
MultilineBlockChain:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
NestedTernaryOperator:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
Not:
|
60
|
+
Enabled: false
|
61
|
+
|
62
|
+
NumericLiterals:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
ParameterLists:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
ParenthesesAroundCondition:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
ParenthesesAsGroupedExpression:
|
72
|
+
Enabled: false
|
73
|
+
|
74
|
+
RedundantBegin:
|
75
|
+
Enabled: false
|
76
|
+
|
77
|
+
RedundantSelf:
|
78
|
+
Enabled: false
|
79
|
+
|
80
|
+
RescueException:
|
81
|
+
Enabled: false
|
82
|
+
|
83
|
+
RescueModifier:
|
84
|
+
Enabled: false
|
85
|
+
|
86
|
+
Semicolon:
|
87
|
+
Enabled: false
|
88
|
+
|
89
|
+
SignalException:
|
90
|
+
Enabled: false
|
91
|
+
|
92
|
+
SingleLineBlockParams:
|
93
|
+
Enabled: false
|
94
|
+
|
95
|
+
WordArray:
|
96
|
+
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-1.9.3
|
1
|
+
ruby-1.9.3-p392
|
data/calculon.gemspec
CHANGED
data/lib/calculon.rb
CHANGED
@@ -7,13 +7,13 @@ module Calculon
|
|
7
7
|
def self.included(base)
|
8
8
|
base.extend(ClassMethods)
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
module ClassMethods
|
12
|
-
def calculon_view(name, cols, opts=nil)
|
12
|
+
def calculon_view(name, cols, opts = nil)
|
13
13
|
metaclass = class << self; self; end
|
14
14
|
metaclass.instance_eval do
|
15
|
-
[
|
16
|
-
define_method("#{name}_by_#{window}") { |nopts=nil|
|
15
|
+
["minute", "hour", "day", "month", "year"].each do |window|
|
16
|
+
define_method("#{name}_by_#{window}") { |nopts = nil|
|
17
17
|
nopts = (opts || {}).merge(nopts || {})
|
18
18
|
# clone cols so modifications downstream don't affect our original copy here
|
19
19
|
send("by_#{window}".intern, cols.clone, nopts)
|
@@ -31,13 +31,12 @@ module Calculon
|
|
31
31
|
{ :time_column => @@calculon_time_column, :group_by => [] }
|
32
32
|
end
|
33
33
|
|
34
|
-
def on(date
|
35
|
-
opts = default_calculon_opts.merge(opts || {})
|
34
|
+
def on(date)
|
36
35
|
raise "'on' method takes a Date object as the first param" unless date.is_a?(Date)
|
37
36
|
between date.to_time, date.to_time + 86399.seconds
|
38
37
|
end
|
39
38
|
|
40
|
-
def between(starttime, endtime, opts=nil)
|
39
|
+
def between(starttime, endtime, opts = nil)
|
41
40
|
opts = default_calculon_opts.merge(opts || {})
|
42
41
|
relation = where ["#{opts[:time_column]} >= ? and #{opts[:time_column]} <= ?", starttime, endtime]
|
43
42
|
relation.calculon_opts ||= {}
|
@@ -45,28 +44,28 @@ module Calculon
|
|
45
44
|
relation
|
46
45
|
end
|
47
46
|
|
48
|
-
def by_minute(cols, opts=nil)
|
47
|
+
def by_minute(cols, opts = nil)
|
49
48
|
tcol = "concat(date(%{time_column}),' ',lpad(hour(%{time_column}),2,'0'),':',lpad(minute(%{time_column}),2,'0'),':00')"
|
50
49
|
by_bucket :minute, tcol, cols, opts
|
51
50
|
end
|
52
51
|
|
53
|
-
def by_hour(cols, opts=nil)
|
52
|
+
def by_hour(cols, opts = nil)
|
54
53
|
by_bucket :hour, "concat(date(%{time_column}),' ',lpad(hour(%{time_column}),2,'0'),':00:00')", cols, opts
|
55
54
|
end
|
56
55
|
|
57
|
-
def by_day(cols, opts=nil)
|
56
|
+
def by_day(cols, opts = nil)
|
58
57
|
by_bucket :day, "concat(date(%{time_column}),' 00:00:00')", cols, opts
|
59
58
|
end
|
60
59
|
|
61
|
-
def by_month(cols, opts=nil)
|
60
|
+
def by_month(cols, opts = nil)
|
62
61
|
by_bucket :month, "concat(year(%{time_column}),'-',lpad(month(%{time_column}),2,'0'),'-01 00:00:00')", cols, opts
|
63
62
|
end
|
64
63
|
|
65
|
-
def by_year(cols, opts=nil)
|
64
|
+
def by_year(cols, opts = nil)
|
66
65
|
by_bucket :year, "concat(year(%{time_column}),'-01-01 00:00:00')", cols, opts
|
67
66
|
end
|
68
67
|
|
69
|
-
def by_bucket(bucket_name, bucket, cols, opts=nil)
|
68
|
+
def by_bucket(bucket_name, bucket, cols, opts = nil)
|
70
69
|
opts = default_calculon_opts.merge(opts || {})
|
71
70
|
# allow group by to be either single symbol or array of symbols
|
72
71
|
opts[:group_by] = [opts[:group_by]].flatten
|
@@ -85,10 +84,10 @@ module Calculon
|
|
85
84
|
# if we're grouping by other columns, we need to select them
|
86
85
|
groupby = opts[:group_by] + ["time_bucket"]
|
87
86
|
opts[:group_by].each { |c| cols[c] = nil }
|
88
|
-
cols = cols.map { |name,method|
|
87
|
+
cols = cols.map { |name, method|
|
89
88
|
asname = name.to_s.gsub(' ', '').tr('^A-Za-z0-9', '_')
|
90
|
-
method.nil? ? name : "#{method}(#{name}) as #{asname}"
|
91
|
-
} + [
|
89
|
+
method.nil? ? name : "#{method}(#{name}) as #{asname}"
|
90
|
+
} + ["#{bucket} as time_bucket"]
|
92
91
|
|
93
92
|
relation = select(cols.join(",")).group(*groupby).order("time_bucket ASC")
|
94
93
|
relation.calculon_opts ||= {}
|
data/lib/calculon/ext.rb
CHANGED
data/lib/calculon/railtie.rb
CHANGED
data/lib/calculon/results.rb
CHANGED
@@ -11,17 +11,17 @@ module Calculon
|
|
11
11
|
@grouped_by = relation.calculon_opts[:group_by] || []
|
12
12
|
@grouped_by_values = Set.new
|
13
13
|
|
14
|
-
@start_time = relation.calculon_opts[:starttime] || keys.sort.first
|
15
|
-
@start_time = @start_time.to_time if @start_time.is_a?(Date)
|
16
|
-
|
17
|
-
@end_time = relation.calculon_opts[:endtime] || keys.sort.last
|
18
|
-
@end_time = @end_time.to_time if @end_time.is_a?(Date)
|
19
|
-
|
20
14
|
relation.to_a.each { |row|
|
21
15
|
# Keep track of all of the unique column values for the group_by cols
|
22
|
-
@grouped_by_values.add @grouped_by.inject({}) { |h,col| h[col] = row.send(col); h }
|
23
|
-
self[row.time_bucket] = fetch(row.time_bucket, []) + [
|
16
|
+
@grouped_by_values.add @grouped_by.inject({}) { |h, col| h[col] = row.send(col); h }
|
17
|
+
self[row.time_bucket] = fetch(row.time_bucket, []) + [row]
|
24
18
|
}
|
19
|
+
|
20
|
+
@start_time = relation.calculon_opts[:starttime] || Time.zone.parse(keys.sort.first)
|
21
|
+
@start_time = @start_time.to_time if @start_time.is_a?(Date)
|
22
|
+
|
23
|
+
@end_time = relation.calculon_opts[:endtime] || Time.zone.parse(keys.sort.last)
|
24
|
+
@end_time = @end_time.to_time if @end_time.is_a?(Date)
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.create(relation)
|
@@ -37,34 +37,38 @@ module Calculon
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def time_format
|
40
|
-
{
|
41
|
-
:minute => "%Y-%m-%d %H:%M:00",
|
42
|
-
:hour => "%Y-%m-%d %H:00:00",
|
43
|
-
:day => "%Y-%m-%d 00:00:00",
|
44
|
-
:month => "%Y-%m-01 00:00:00",
|
40
|
+
{
|
41
|
+
:minute => "%Y-%m-%d %H:%M:00",
|
42
|
+
:hour => "%Y-%m-%d %H:00:00",
|
43
|
+
:day => "%Y-%m-%d 00:00:00",
|
44
|
+
:month => "%Y-%m-01 00:00:00",
|
45
45
|
:year => "%Y-01-01 00:00:00"
|
46
46
|
}.fetch(@bucket_size)
|
47
47
|
end
|
48
48
|
|
49
|
-
def map_each_time
|
50
|
-
|
51
|
-
|
49
|
+
def map_each_time(&block)
|
50
|
+
@time_bucket_names ||= lambda do
|
51
|
+
increment_amounts = { :minute => 1.minute, :hour => 1.hour, :day => 1.day, :month => 1.month, :year => 1.year }
|
52
|
+
increment = increment_amounts[@bucket_size]
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
# get the "floor" of the start and end times (the "floor" bucket)
|
55
|
+
current = Time.zone.parse(@start_time.strftime(time_format + " %z"))
|
56
|
+
last_time = Time.zone.parse(@end_time.strftime(time_format + " %z"))
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
results = []
|
59
|
+
while current <= last_time
|
60
|
+
results << current.strftime(time_format)
|
61
|
+
current += increment
|
62
|
+
end
|
63
|
+
results
|
64
|
+
end.call
|
65
|
+
|
66
|
+
@time_bucket_names.map { |b| block.call(b) }
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
66
70
|
class SingleGroupingResults < Results
|
67
|
-
def to_a(default=nil)
|
71
|
+
def to_a(default = nil)
|
68
72
|
map_each_time { |key|
|
69
73
|
fetch(key, [default]).first
|
70
74
|
}
|
@@ -78,9 +82,9 @@ module Calculon
|
|
78
82
|
}
|
79
83
|
end
|
80
84
|
|
81
|
-
def values_for(grouping, default=nil)
|
85
|
+
def values_for(grouping, default = nil)
|
82
86
|
map_each_time { |key|
|
83
|
-
matches = fetch(key, []).select { |value| grouping.map { |k,v| value.send(k) == v }.all? }
|
87
|
+
matches = fetch(key, []).select { |value| grouping.map { |k, v| value.send(k) == v }.all? }
|
84
88
|
matches.length > 0 ? matches.first : default
|
85
89
|
}
|
86
90
|
end
|
data/lib/calculon/version.rb
CHANGED
data/test/calculon_test.rb
CHANGED
@@ -40,15 +40,15 @@ class CalculonTest < Test::Unit::TestCase
|
|
40
40
|
results = Game.points_by_hour.to_buckets
|
41
41
|
keys = [33.hours.ago.strftime("%Y-%m-%d %H:00:00"), 2.hours.ago.strftime("%Y-%m-%d %H:00:00")]
|
42
42
|
assert_equal keys, results.keys.sort
|
43
|
-
assert_equal results[keys.first].first.team_a_points, 10
|
44
|
-
assert_equal results[keys.last].first.team_b_points, 40
|
43
|
+
assert_equal results[keys.first].first.team_a_points, 10
|
44
|
+
assert_equal results[keys.last].first.team_b_points, 40
|
45
45
|
|
46
46
|
assert_equal Game.by_day(:team_a_points => :sum).length, 2
|
47
47
|
results = Game.points_by_day.to_buckets
|
48
48
|
keys = [33.hours.ago.strftime("%Y-%m-%d 00:00:00"), 2.hours.ago.strftime("%Y-%m-%d 00:00:00")]
|
49
49
|
assert_equal keys, results.keys.sort
|
50
|
-
assert_equal results[keys.first].first.team_a_points, 10
|
51
|
-
assert_equal results[keys.last].first.team_b_points, 40
|
50
|
+
assert_equal results[keys.first].first.team_a_points, 10
|
51
|
+
assert_equal results[keys.last].first.team_b_points, 40
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_results_hash_missing
|
@@ -56,9 +56,9 @@ class CalculonTest < Test::Unit::TestCase
|
|
56
56
|
Game.create(:team_a_points => 20, :created_at => Time.zone.now - 1.hours)
|
57
57
|
Game.create(:team_a_points => 30, :created_at => Time.zone.now - 2.hours)
|
58
58
|
Game.create(:team_a_points => 40, :created_at => Time.zone.now - 25.hours)
|
59
|
-
|
59
|
+
|
60
60
|
days = Game.points_by_day.to_a
|
61
61
|
assert_equal days.length, 2
|
62
|
-
assert_equal days.inject(0) { |s,g| s + g.team_a_points }, 100
|
62
|
+
assert_equal days.inject(0) { |s, g| s + g.team_a_points }, 100
|
63
63
|
end
|
64
64
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calculon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
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:
|
12
|
+
date: 2014-05-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -107,6 +107,22 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rubocop
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
110
126
|
description: Calculon provides aggregate time functions for ActiveRecord.
|
111
127
|
email:
|
112
128
|
- bamuller@gmail.com
|
@@ -115,6 +131,7 @@ extensions: []
|
|
115
131
|
extra_rdoc_files: []
|
116
132
|
files:
|
117
133
|
- .gitignore
|
134
|
+
- .rubocop.yml
|
118
135
|
- .ruby-gemset
|
119
136
|
- .ruby-version
|
120
137
|
- Gemfile
|
@@ -142,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
159
|
version: '0'
|
143
160
|
segments:
|
144
161
|
- 0
|
145
|
-
hash:
|
162
|
+
hash: 2649945751617820955
|
146
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
164
|
none: false
|
148
165
|
requirements:
|
@@ -151,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
168
|
version: '0'
|
152
169
|
segments:
|
153
170
|
- 0
|
154
|
-
hash:
|
171
|
+
hash: 2649945751617820955
|
155
172
|
requirements: []
|
156
173
|
rubyforge_project:
|
157
174
|
rubygems_version: 1.8.25
|