calculon 0.0.3 → 0.0.4
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/.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
|