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.
Files changed (38) hide show
  1. data/README.md +95 -20
  2. data/lib/sleek.rb +4 -2
  3. data/lib/sleek/core_ext/range.rb +6 -7
  4. data/lib/sleek/event.rb +4 -1
  5. data/lib/sleek/filter.rb +11 -0
  6. data/lib/sleek/group_by_criteria.rb +144 -0
  7. data/lib/sleek/interval.rb +21 -20
  8. data/lib/sleek/{base.rb → namespace.rb} +13 -8
  9. data/lib/sleek/queries.rb +0 -1
  10. data/lib/sleek/queries/average.rb +1 -1
  11. data/lib/sleek/queries/count_unique.rb +1 -1
  12. data/lib/sleek/queries/maximum.rb +1 -1
  13. data/lib/sleek/queries/minimum.rb +1 -1
  14. data/lib/sleek/queries/query.rb +70 -37
  15. data/lib/sleek/queries/sum.rb +1 -1
  16. data/lib/sleek/query_collection.rb +3 -3
  17. data/lib/sleek/query_command.rb +71 -0
  18. data/lib/sleek/timeframe.rb +45 -52
  19. data/lib/sleek/version.rb +1 -1
  20. data/spec/lib/sleek/event_spec.rb +3 -3
  21. data/spec/lib/sleek/filter_spec.rb +3 -3
  22. data/spec/lib/sleek/group_by_criteria_spec.rb +139 -0
  23. data/spec/lib/sleek/interval_spec.rb +6 -5
  24. data/spec/lib/sleek/{base_spec.rb → namespace_spec.rb} +15 -8
  25. data/spec/lib/sleek/queries/average_spec.rb +1 -1
  26. data/spec/lib/sleek/queries/count_spec.rb +1 -1
  27. data/spec/lib/sleek/queries/count_unique_spec.rb +1 -1
  28. data/spec/lib/sleek/queries/maximum_spec.rb +1 -1
  29. data/spec/lib/sleek/queries/minimum_spec.rb +1 -1
  30. data/spec/lib/sleek/queries/query_spec.rb +58 -84
  31. data/spec/lib/sleek/queries/sum_spec.rb +1 -1
  32. data/spec/lib/sleek/query_collection_spec.rb +11 -9
  33. data/spec/lib/sleek/query_command_spec.rb +171 -0
  34. data/spec/lib/sleek/timeframe_spec.rb +70 -36
  35. data/spec/lib/sleek_spec.rb +2 -2
  36. metadata +11 -8
  37. data/lib/sleek/queries/targetable.rb +0 -13
  38. 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) { Sleek::Queries::Sum.new(:default, :purchases, target_property: "total") }
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
- subject(:collection) { Sleek::QueryCollection.new(:default) }
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
- collection = Sleek::QueryCollection.new(:my_namespace)
9
- expect(collection.namespace).to eq :my_namespace
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 class and passes options" do
15
- Sleek::Queries::Count.should_receive(:new).with(:default, :purchases, { some: :opts }).and_call_original
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
- count = stub('count_query')
21
- Sleek::Queries::Count.should_receive(:new).and_return(count)
22
- count.should_receive(:run)
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(Sleek::Timeframe.to_range(range)).to eq range
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 { Sleek::Timeframe.to_range(1..3) }.to raise_exception ArgumentError
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(Sleek::Timeframe.to_range([start_time, end_time])).to eq range
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 { Sleek::Timeframe.to_range([1, 2]) }.to raise_exception ArgumentError
53
- expect { Sleek::Timeframe.to_range([start_time, end_time, end_time]) }.to raise_exception ArgumentError
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
- it "tries to parse it" do
60
- range = stub('range')
61
- Sleek::Timeframe.should_receive(:to_range).with('this_day').and_return range
62
- expect(Sleek::Timeframe.to_range('this_day')).to eq range
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
- td = Sleek::Timeframe.parse('this_day')
71
- expect(td.begin).to eq Time.now.beginning_of_day
72
- expect(td.end).to eq Time.now.end_of_day.round
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 = Sleek::Timeframe.parse('previous_2_weeks')
75
- expect(p2w.begin).to eq Time.now.beginning_of_week - 2.weeks
76
- expect(p2w.end).to eq Time.now.end_of_week.round - 1.weeks
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 { Sleek::Timeframe.parse('lol_wut') }.to raise_exception ArgumentError, "special timeframe string is malformed"
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
@@ -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::Base instance" do
6
- Sleek::Base.should_receive(:new).with(:test_ns)
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.1
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-05-10 00:00:00.000000000 Z
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