sleek 0.0.1 → 0.0.2
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/README.md +95 -20
- data/lib/sleek.rb +4 -2
- data/lib/sleek/core_ext/range.rb +6 -7
- data/lib/sleek/event.rb +4 -1
- data/lib/sleek/filter.rb +11 -0
- data/lib/sleek/group_by_criteria.rb +144 -0
- data/lib/sleek/interval.rb +21 -20
- data/lib/sleek/{base.rb → namespace.rb} +13 -8
- data/lib/sleek/queries.rb +0 -1
- data/lib/sleek/queries/average.rb +1 -1
- data/lib/sleek/queries/count_unique.rb +1 -1
- data/lib/sleek/queries/maximum.rb +1 -1
- data/lib/sleek/queries/minimum.rb +1 -1
- data/lib/sleek/queries/query.rb +70 -37
- data/lib/sleek/queries/sum.rb +1 -1
- data/lib/sleek/query_collection.rb +3 -3
- data/lib/sleek/query_command.rb +71 -0
- data/lib/sleek/timeframe.rb +45 -52
- data/lib/sleek/version.rb +1 -1
- data/spec/lib/sleek/event_spec.rb +3 -3
- data/spec/lib/sleek/filter_spec.rb +3 -3
- data/spec/lib/sleek/group_by_criteria_spec.rb +139 -0
- data/spec/lib/sleek/interval_spec.rb +6 -5
- data/spec/lib/sleek/{base_spec.rb → namespace_spec.rb} +15 -8
- data/spec/lib/sleek/queries/average_spec.rb +1 -1
- data/spec/lib/sleek/queries/count_spec.rb +1 -1
- data/spec/lib/sleek/queries/count_unique_spec.rb +1 -1
- data/spec/lib/sleek/queries/maximum_spec.rb +1 -1
- data/spec/lib/sleek/queries/minimum_spec.rb +1 -1
- data/spec/lib/sleek/queries/query_spec.rb +58 -84
- data/spec/lib/sleek/queries/sum_spec.rb +1 -1
- data/spec/lib/sleek/query_collection_spec.rb +11 -9
- data/spec/lib/sleek/query_command_spec.rb +171 -0
- data/spec/lib/sleek/timeframe_spec.rb +70 -36
- data/spec/lib/sleek_spec.rb +2 -2
- metadata +11 -8
- data/lib/sleek/queries/targetable.rb +0 -13
- data/spec/lib/sleek/queries/targetable_spec.rb +0 -29
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Sleek::Queries::Sum do
|
4
|
-
subject(:query) {
|
4
|
+
subject(:query) { described_class.new(:default, :purchases, target_property: "total") }
|
5
5
|
|
6
6
|
describe "#perform" do
|
7
7
|
it "counts the events" do
|
@@ -1,25 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Sleek::QueryCollection do
|
4
|
-
|
4
|
+
let(:namespace) { stub('namespace', name: :default) }
|
5
|
+
subject(:collection) { described_class.new(namespace) }
|
5
6
|
|
6
7
|
describe "#initialize" do
|
7
8
|
it "sets the namespace" do
|
8
|
-
|
9
|
-
|
9
|
+
my_namespace = stub('my_namespace', name: :my_namespace)
|
10
|
+
collection = described_class.new(my_namespace)
|
11
|
+
expect(collection.namespace).to eq my_namespace
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
15
|
describe "query methods" do
|
14
|
-
it "creates query
|
15
|
-
Sleek::
|
16
|
+
it "creates query command" do
|
17
|
+
Sleek::QueryCommand.should_receive(:new).with(Sleek::Queries::Count, namespace, :purchases, { some: :opts }).and_return(stub.as_null_object)
|
16
18
|
collection.count(:purchases, { some: :opts })
|
17
19
|
end
|
18
20
|
|
19
|
-
it "runs the query" do
|
20
|
-
|
21
|
-
Sleek::
|
22
|
-
|
21
|
+
it "runs the query command" do
|
22
|
+
query_command = stub('query_command')
|
23
|
+
Sleek::QueryCommand.should_receive(:new).and_return(query_command)
|
24
|
+
query_command.should_receive(:run)
|
23
25
|
|
24
26
|
collection.count(:purchases)
|
25
27
|
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sleek::QueryCommand do
|
4
|
+
let(:query_class) { double('query_class') }
|
5
|
+
let(:namespace) { double('namespace', name: :default) }
|
6
|
+
let(:bucket) { :purchases }
|
7
|
+
let(:options) { {} }
|
8
|
+
subject(:command) { described_class.new(query_class, namespace, bucket, options) }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
context "when no timeframe is provided" do
|
12
|
+
context "when interval is not provided" do
|
13
|
+
let(:command) { described_class.new(query_class, namespace, bucket, { some: :opts }) }
|
14
|
+
|
15
|
+
it "sets class" do
|
16
|
+
expect(command.klass).to eq query_class
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets namespace" do
|
20
|
+
expect(command.namespace).to eq namespace
|
21
|
+
end
|
22
|
+
|
23
|
+
it "sets bucket" do
|
24
|
+
expect(command.bucket).to eq bucket
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sets options" do
|
28
|
+
expect(command.options).to eq some: :opts
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when interval is provided" do
|
33
|
+
it "raises an exception" do
|
34
|
+
expect {
|
35
|
+
described_class.new(query_class, namespace, bucket, interval: :daily)
|
36
|
+
}.to raise_exception ArgumentError, "interval requires timeframe"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when timeframe is provided" do
|
42
|
+
context "when interval is not provided" do
|
43
|
+
let(:options) { { some: :opts, timeframe: :this_day } }
|
44
|
+
|
45
|
+
it "deletes timeframe from options" do
|
46
|
+
expect(command.options).to eq some: :opts
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when interval is provided" do
|
51
|
+
let(:options) { { some: :opts, timeframe: :this_day, interval: :hourly } }
|
52
|
+
|
53
|
+
it "deletes timeframe and interval from options" do
|
54
|
+
expect(command.options).to eq some: :opts
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#timeframe" do
|
61
|
+
context "when initialized with timeframe" do
|
62
|
+
context "when initialized without timezone" do
|
63
|
+
let(:options) { { timeframe: :this_day } }
|
64
|
+
|
65
|
+
it "constructs timeframe" do
|
66
|
+
tf = double('timeframe')
|
67
|
+
Sleek::Timeframe.stub(:to_range).with(:this_day, nil).and_return(tf)
|
68
|
+
expect(command.timeframe).to eq tf
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when initialized with timezone" do
|
73
|
+
let(:options) { { timeframe: :this_day, timezone: 'US/Pacific' } }
|
74
|
+
|
75
|
+
it "constructs timeframe with time zone" do
|
76
|
+
tf = double('timeframe')
|
77
|
+
Sleek::Timeframe.stub(:to_range).with(:this_day, 'US/Pacific').and_return(tf)
|
78
|
+
expect(command.timeframe).to eq tf
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#series" do
|
85
|
+
context "when initialized with timeframe and interval" do
|
86
|
+
let(:tf) { double('timeframe') }
|
87
|
+
let(:interval) { double('interval', timeframes: []) }
|
88
|
+
let(:options) { { timeframe: :this_day, interval: :hourly } }
|
89
|
+
|
90
|
+
before do
|
91
|
+
Sleek::Interval.stub(:new).and_return(interval)
|
92
|
+
command.stub(:timeframe).and_return(tf)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "creates a Sleek::Interval" do
|
96
|
+
Sleek::Interval.should_receive(:new).with(:hourly, tf).and_return(double.as_null_object)
|
97
|
+
command.series
|
98
|
+
end
|
99
|
+
|
100
|
+
it "returns sub-timeframes" do
|
101
|
+
expect(command.series).to eq interval.timeframes
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#new_query" do
|
107
|
+
it "adds timeframe to options and creates a query instance with them" do
|
108
|
+
command.stub(:options).and_return(some: :opts)
|
109
|
+
query = double('query')
|
110
|
+
query_class.should_receive(:new).with(namespace, bucket, { some: :opts, timeframe: :my_tf }).and_return(query)
|
111
|
+
expect(command.new_query(:my_tf)).to eq query
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#run" do
|
116
|
+
context "when series do not need to be computed" do
|
117
|
+
let(:result) { double('result') }
|
118
|
+
let(:query) { mock('query', run: result) }
|
119
|
+
let(:tf) { double('timeframe') }
|
120
|
+
before { command.stub(series?: false, new_query: query, timeframe: tf) }
|
121
|
+
|
122
|
+
it "creates a query" do
|
123
|
+
command.should_receive(:new_query).with(tf)
|
124
|
+
command.run
|
125
|
+
end
|
126
|
+
|
127
|
+
it "runs the query" do
|
128
|
+
query.should_receive(:run)
|
129
|
+
command.run
|
130
|
+
end
|
131
|
+
|
132
|
+
it "returns query result" do
|
133
|
+
expect(command.run).to eq result
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when series need to be computes" do
|
138
|
+
let(:result1) { double('result1') }
|
139
|
+
let(:result2) { double('result2') }
|
140
|
+
let(:query1) { double('query1', run: result1) }
|
141
|
+
let(:query2) { double('query2', run: result2) }
|
142
|
+
let(:tf1) { stub('tf1') }
|
143
|
+
let(:tf2) { stub('tf2') }
|
144
|
+
let(:series) { [tf1, tf2] }
|
145
|
+
|
146
|
+
before do
|
147
|
+
command.stub(series?: true, series: series)
|
148
|
+
command.stub(:new_query) { |tf| tf == tf1 ? query1 : query2 }
|
149
|
+
end
|
150
|
+
|
151
|
+
it "creates a query for each series item" do
|
152
|
+
command.should_receive(:new_query).with(tf1)
|
153
|
+
command.should_receive(:new_query).with(tf2)
|
154
|
+
command.run
|
155
|
+
end
|
156
|
+
|
157
|
+
it "runs the query for each series item" do
|
158
|
+
query1.should_receive(:run)
|
159
|
+
query2.should_receive(:run)
|
160
|
+
command.run
|
161
|
+
end
|
162
|
+
|
163
|
+
it "returns combined result" do
|
164
|
+
expect(command.run).to eq [
|
165
|
+
{ timeframe: tf1, value: result1 },
|
166
|
+
{ timeframe: tf2, value: result2 }
|
167
|
+
]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -4,38 +4,18 @@ describe Sleek::Timeframe do
|
|
4
4
|
let(:start_time) { 1.day.ago }
|
5
5
|
let(:end_time) { Time.now }
|
6
6
|
let(:range) { start_time..end_time }
|
7
|
-
subject(:timeframe) { Sleek::Timeframe.new(range) }
|
8
|
-
|
9
|
-
describe "#start" do
|
10
|
-
it "returns timeframe start" do
|
11
|
-
expect(timeframe.start).to eq start_time
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "#end" do
|
16
|
-
it "returns timeframe end" do
|
17
|
-
expect(timeframe.end).to eq end_time
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#to_time_range" do
|
22
|
-
it "transforms passed timeframe to range" do
|
23
|
-
Sleek::Timeframe.should_receive(:to_range).with(range)
|
24
|
-
timeframe.to_time_range
|
25
|
-
end
|
26
|
-
end
|
27
7
|
|
28
8
|
describe ".to_range" do
|
29
9
|
context "when passed a range" do
|
30
10
|
context "when the range is of Time objects" do
|
31
11
|
it "returns that range" do
|
32
|
-
expect(
|
12
|
+
expect(described_class.to_range(range)).to eq range
|
33
13
|
end
|
34
14
|
end
|
35
15
|
|
36
16
|
context "when passed other range" do
|
37
17
|
it "raises an exception" do
|
38
|
-
expect {
|
18
|
+
expect { described_class.to_range(1..3) }.to raise_exception ArgumentError
|
39
19
|
end
|
40
20
|
end
|
41
21
|
end
|
@@ -43,43 +23,97 @@ describe Sleek::Timeframe do
|
|
43
23
|
context "when passed an array" do
|
44
24
|
context "when array has two Time elements" do
|
45
25
|
it "constructs the range" do
|
46
|
-
expect(
|
26
|
+
expect(described_class.to_range([start_time, end_time])).to eq range
|
47
27
|
end
|
48
28
|
end
|
49
29
|
|
50
30
|
context "when passed other array" do
|
51
31
|
it "raises an exception" do
|
52
|
-
expect {
|
53
|
-
expect {
|
32
|
+
expect { described_class.to_range([1, 2]) }.to raise_exception ArgumentError
|
33
|
+
expect { described_class.to_range([start_time, end_time, end_time]) }.to raise_exception ArgumentError
|
54
34
|
end
|
55
35
|
end
|
56
36
|
end
|
57
37
|
|
58
38
|
context "when passed a string or a symbol" do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
39
|
+
context "without timezone" do
|
40
|
+
it "tries to parse it" do
|
41
|
+
described_class.should_receive(:parse).with('this_day', nil)
|
42
|
+
described_class.to_range('this_day')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with timezone" do
|
47
|
+
it "tries to parse it with appropriate timezone" do
|
48
|
+
described_class.should_receive(:parse).with('this_day', 'US/Pacific')
|
49
|
+
described_class.to_range('this_day', 'US/Pacific')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when passed something else" do
|
55
|
+
it "raises an exception" do
|
56
|
+
expect { described_class.to_range(some_object: 1) }.to raise_exception ArgumentError
|
63
57
|
end
|
64
58
|
end
|
65
59
|
end
|
66
60
|
|
67
61
|
describe ".parse" do
|
68
62
|
context "when passed the proper string" do
|
63
|
+
it "creates range from interval and number, preserving timezone" do
|
64
|
+
described_class.should_receive(:range_from_interval).with('day', 2, 'US/Pacific')
|
65
|
+
described_class.parse('this_2_days', 'US/Pacific')
|
66
|
+
end
|
67
|
+
|
69
68
|
it "parses the string and returns time range" do
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
tz = ActiveSupport::TimeZone.new('UTC')
|
70
|
+
|
71
|
+
td = described_class.parse('this_day')
|
72
|
+
expect(td.begin).to eq tz.now.beginning_of_day
|
73
|
+
expect(td.end).to eq tz.now.end_of_day.round
|
73
74
|
|
74
|
-
p2w =
|
75
|
-
expect(p2w.begin).to eq
|
76
|
-
expect(p2w.end).to eq
|
75
|
+
p2w = described_class.parse('previous_2_weeks')
|
76
|
+
expect(p2w.begin).to eq tz.now.beginning_of_week - 2.weeks
|
77
|
+
expect(p2w.end).to eq tz.now.end_of_week.round - 1.weeks
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
80
81
|
context "when passed malformed string" do
|
81
82
|
it "raises an exception" do
|
82
|
-
expect {
|
83
|
+
expect { described_class.parse('lol_wut') }.to raise_exception ArgumentError, "special timeframe string is malformed"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".range_from_interval" do
|
89
|
+
before { now.stub(:end_of_day) { 2.days } }
|
90
|
+
|
91
|
+
context "without timezone" do
|
92
|
+
let(:now) { double('utc_now') }
|
93
|
+
before { ActiveSupport::TimeZone.stub_chain(:new, :now).and_return(now) }
|
94
|
+
|
95
|
+
it "creates a range" do
|
96
|
+
expect(described_class.range_from_interval("day", 1)).to eq 1.day..2.days
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "with timezone" do
|
101
|
+
let(:now) { double('local_now') }
|
102
|
+
let(:tz) { stub('timezone', now: now) }
|
103
|
+
|
104
|
+
before do
|
105
|
+
ActiveSupport::TimeZone.stub(:new).and_return(tz)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "gets current time in the timezone" do
|
109
|
+
ActiveSupport::TimeZone.should_receive(:new).with('US/Pacific')
|
110
|
+
tz.should_receive(:now)
|
111
|
+
|
112
|
+
described_class.range_from_interval('day', 1, 'US/Pacific')
|
113
|
+
end
|
114
|
+
|
115
|
+
it "creates a range" do
|
116
|
+
expect(described_class.range_from_interval('day', 1, 'US/Pacific')).to eq 1.day..2.days
|
83
117
|
end
|
84
118
|
end
|
85
119
|
end
|
data/spec/lib/sleek_spec.rb
CHANGED
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Sleek do
|
4
4
|
describe ".for_namespace" do
|
5
|
-
it "should return namespaced Sleek::
|
6
|
-
Sleek::
|
5
|
+
it "should return namespaced Sleek::Namespace instance" do
|
6
|
+
Sleek::Namespace.should_receive(:new).with(:test_ns)
|
7
7
|
Sleek.for_namespace(:test_ns)
|
8
8
|
end
|
9
9
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sleek
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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-
|
12
|
+
date: 2013-06-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongoid
|
@@ -122,12 +122,13 @@ files:
|
|
122
122
|
- README.md
|
123
123
|
- Rakefile
|
124
124
|
- lib/sleek.rb
|
125
|
-
- lib/sleek/base.rb
|
126
125
|
- lib/sleek/core_ext/range.rb
|
127
126
|
- lib/sleek/core_ext/time.rb
|
128
127
|
- lib/sleek/event.rb
|
129
128
|
- lib/sleek/filter.rb
|
129
|
+
- lib/sleek/group_by_criteria.rb
|
130
130
|
- lib/sleek/interval.rb
|
131
|
+
- lib/sleek/namespace.rb
|
131
132
|
- lib/sleek/queries.rb
|
132
133
|
- lib/sleek/queries/average.rb
|
133
134
|
- lib/sleek/queries/count.rb
|
@@ -136,16 +137,17 @@ files:
|
|
136
137
|
- lib/sleek/queries/minimum.rb
|
137
138
|
- lib/sleek/queries/query.rb
|
138
139
|
- lib/sleek/queries/sum.rb
|
139
|
-
- lib/sleek/queries/targetable.rb
|
140
140
|
- lib/sleek/query_collection.rb
|
141
|
+
- lib/sleek/query_command.rb
|
141
142
|
- lib/sleek/timeframe.rb
|
142
143
|
- lib/sleek/version.rb
|
143
144
|
- sleek.gemspec
|
144
145
|
- sleek.png
|
145
|
-
- spec/lib/sleek/base_spec.rb
|
146
146
|
- spec/lib/sleek/event_spec.rb
|
147
147
|
- spec/lib/sleek/filter_spec.rb
|
148
|
+
- spec/lib/sleek/group_by_criteria_spec.rb
|
148
149
|
- spec/lib/sleek/interval_spec.rb
|
150
|
+
- spec/lib/sleek/namespace_spec.rb
|
149
151
|
- spec/lib/sleek/queries/average_spec.rb
|
150
152
|
- spec/lib/sleek/queries/count_spec.rb
|
151
153
|
- spec/lib/sleek/queries/count_unique_spec.rb
|
@@ -153,8 +155,8 @@ files:
|
|
153
155
|
- spec/lib/sleek/queries/minimum_spec.rb
|
154
156
|
- spec/lib/sleek/queries/query_spec.rb
|
155
157
|
- spec/lib/sleek/queries/sum_spec.rb
|
156
|
-
- spec/lib/sleek/queries/targetable_spec.rb
|
157
158
|
- spec/lib/sleek/query_collection_spec.rb
|
159
|
+
- spec/lib/sleek/query_command_spec.rb
|
158
160
|
- spec/lib/sleek/timeframe_spec.rb
|
159
161
|
- spec/lib/sleek_spec.rb
|
160
162
|
- spec/spec_helper.rb
|
@@ -184,10 +186,11 @@ signing_key:
|
|
184
186
|
specification_version: 3
|
185
187
|
summary: Sleek is a library for doing analytics.
|
186
188
|
test_files:
|
187
|
-
- spec/lib/sleek/base_spec.rb
|
188
189
|
- spec/lib/sleek/event_spec.rb
|
189
190
|
- spec/lib/sleek/filter_spec.rb
|
191
|
+
- spec/lib/sleek/group_by_criteria_spec.rb
|
190
192
|
- spec/lib/sleek/interval_spec.rb
|
193
|
+
- spec/lib/sleek/namespace_spec.rb
|
191
194
|
- spec/lib/sleek/queries/average_spec.rb
|
192
195
|
- spec/lib/sleek/queries/count_spec.rb
|
193
196
|
- spec/lib/sleek/queries/count_unique_spec.rb
|
@@ -195,8 +198,8 @@ test_files:
|
|
195
198
|
- spec/lib/sleek/queries/minimum_spec.rb
|
196
199
|
- spec/lib/sleek/queries/query_spec.rb
|
197
200
|
- spec/lib/sleek/queries/sum_spec.rb
|
198
|
-
- spec/lib/sleek/queries/targetable_spec.rb
|
199
201
|
- spec/lib/sleek/query_collection_spec.rb
|
202
|
+
- spec/lib/sleek/query_command_spec.rb
|
200
203
|
- spec/lib/sleek/timeframe_spec.rb
|
201
204
|
- spec/lib/sleek_spec.rb
|
202
205
|
- spec/spec_helper.rb
|