sleek 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +22 -0
  6. data/README.md +256 -0
  7. data/Rakefile +6 -0
  8. data/lib/sleek/base.rb +52 -0
  9. data/lib/sleek/core_ext/range.rb +44 -0
  10. data/lib/sleek/core_ext/time.rb +2 -0
  11. data/lib/sleek/event.rb +37 -0
  12. data/lib/sleek/filter.rb +24 -0
  13. data/lib/sleek/interval.rb +41 -0
  14. data/lib/sleek/queries/average.rb +21 -0
  15. data/lib/sleek/queries/count.rb +17 -0
  16. data/lib/sleek/queries/count_unique.rb +21 -0
  17. data/lib/sleek/queries/maximum.rb +21 -0
  18. data/lib/sleek/queries/minimum.rb +21 -0
  19. data/lib/sleek/queries/query.rb +105 -0
  20. data/lib/sleek/queries/sum.rb +21 -0
  21. data/lib/sleek/queries/targetable.rb +13 -0
  22. data/lib/sleek/queries.rb +8 -0
  23. data/lib/sleek/query_collection.rb +25 -0
  24. data/lib/sleek/timeframe.rb +85 -0
  25. data/lib/sleek/version.rb +3 -0
  26. data/lib/sleek.rb +23 -0
  27. data/sleek.gemspec +28 -0
  28. data/sleek.png +0 -0
  29. data/spec/lib/sleek/base_spec.rb +48 -0
  30. data/spec/lib/sleek/event_spec.rb +21 -0
  31. data/spec/lib/sleek/filter_spec.rb +26 -0
  32. data/spec/lib/sleek/interval_spec.rb +24 -0
  33. data/spec/lib/sleek/queries/average_spec.rb +13 -0
  34. data/spec/lib/sleek/queries/count_spec.rb +13 -0
  35. data/spec/lib/sleek/queries/count_unique_spec.rb +15 -0
  36. data/spec/lib/sleek/queries/maximum_spec.rb +13 -0
  37. data/spec/lib/sleek/queries/minimum_spec.rb +13 -0
  38. data/spec/lib/sleek/queries/query_spec.rb +226 -0
  39. data/spec/lib/sleek/queries/sum_spec.rb +13 -0
  40. data/spec/lib/sleek/queries/targetable_spec.rb +29 -0
  41. data/spec/lib/sleek/query_collection_spec.rb +27 -0
  42. data/spec/lib/sleek/timeframe_spec.rb +86 -0
  43. data/spec/lib/sleek_spec.rb +10 -0
  44. data/spec/spec_helper.rb +17 -0
  45. metadata +203 -0
@@ -0,0 +1,226 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek::Queries::Query do
4
+ let(:query_class) { Sleek::Queries::Query }
5
+ subject(:query) { query_class.new(:default, :purchases) }
6
+
7
+ describe "#initialize" do
8
+ it "sets the namespace and bucket" do
9
+ query = Sleek::Queries::Query.new(:my_namespace, :purchases)
10
+ expect(query.namespace).to eq :my_namespace
11
+ expect(query.bucket).to eq :purchases
12
+ end
13
+
14
+ context "when options are valid" do
15
+ before { query_class.any_instance.stub(valid_options?: true) }
16
+
17
+ it "does not raise ArgumerError" do
18
+ expect { query_class.new(:d, :p) }.to_not raise_exception ArgumentError
19
+ end
20
+ end
21
+
22
+ context "when options are invalid" do
23
+ before { query_class.any_instance.stub(valid_options?: false) }
24
+
25
+ it "raises ArgumentError" do
26
+ expect { query_class.new(:d, :p) }.to raise_exception ArgumentError, "options are invalid"
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "#events" do
32
+ context "when no timeframe is specifies" do
33
+ context "when no filter is specified" do
34
+ it "returns events in current namespace and bucket" do
35
+ Sleek::Event.should_receive(:where).with(namespace: :default, bucket: :purchases)
36
+ query.events
37
+ end
38
+ end
39
+
40
+ context "when filter is specified" do
41
+ before { query.stub(filter?: true) }
42
+
43
+ it "applies filters" do
44
+ final = stub('final_criteria')
45
+ query.should_receive(:apply_filters).and_return(final)
46
+ expect(query.events).to eq final
47
+ end
48
+ end
49
+ end
50
+
51
+ context "when timeframe is specified" do
52
+ let(:start) { 1.day.ago }
53
+ let(:finish) { Time.now }
54
+ before { query.stub(:time_range).and_return(start..finish) }
55
+
56
+ context "when no filter is specified" do
57
+ it "gets only events between timeframe ends" do
58
+ pre_evts = stub('pre_events')
59
+ Sleek::Event.should_receive(:where).with(namespace: :default, bucket: :purchases).and_return(pre_evts)
60
+ pre_evts.should_receive(:between).with("s.t" => start..finish)
61
+ query.events
62
+ end
63
+ end
64
+
65
+ context "when filter is specified" do
66
+ before { query.stub(filter?: true) }
67
+
68
+ it "applies filters" do
69
+ pre_evts = stub('pre_events')
70
+ criteria = stub('criteria')
71
+ final = stub('final_criteria')
72
+ Sleek::Event.should_receive(:where).with(namespace: :default, bucket: :purchases).and_return(pre_evts)
73
+ pre_evts.should_receive(:between).and_return(criteria)
74
+ query.should_receive(:apply_filters).with(criteria).and_return(final)
75
+ expect(query.events).to eq final
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#apply_filters" do
82
+ it "applies every filter to criteria" do
83
+ filters = [Sleek::Filter.new(:test, :gt, 1), Sleek::Filter.new(:test, :lt, 100)]
84
+ query.stub(filter?: true, filters: filters)
85
+ criteria = stub('criteria')
86
+ criteria2 = stub('criteria2')
87
+ final = stub('final_criteria')
88
+ criteria.should_receive(:gt).with("d.test" => 1).and_return(criteria2)
89
+ criteria2.should_receive(:lt).with("d.test" => 100).and_return(final)
90
+
91
+ expect(query.apply_filters(criteria)).to eq final
92
+ end
93
+ end
94
+
95
+ describe "#filters" do
96
+ context "when filters are specified" do
97
+ context "when proper single filter" do
98
+ before { query.stub(options: { filter: [:test, :gt, 1] }) }
99
+
100
+ it "returns an one-element array with Filter" do
101
+ expect(query.filters).to eq [Sleek::Filter.new(:test, :gt, 1)]
102
+ end
103
+ end
104
+
105
+ context "when proper multiple filters" do
106
+ before { query.stub(options: { filter: [[:test, :gt, 1], [:test, :lt, 100]] }) }
107
+
108
+ it "returns multiple-element array with Filters" do
109
+ expect(query.filters).to eq [Sleek::Filter.new(:test, :gt, 1), Sleek::Filter.new(:test, :lt, 100)]
110
+ end
111
+ end
112
+
113
+ context "when malformed filter" do
114
+ before { query.stub(options: { filter: :mwahaha }) }
115
+
116
+ it "raises an exception" do
117
+ expect { query.filters }.to raise_exception ArgumentError, "wrong filter - mwahaha"
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "#timeframe" do
124
+ context "when timeframe is specified" do
125
+ let(:tf) { stub('timeframe') }
126
+ before { query.stub(options: { timeframe: tf }) }
127
+
128
+ it "creates new timeframe instance" do
129
+ Sleek::Timeframe.should_receive(:new).with(tf)
130
+ query.timeframe
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#series" do
136
+ context "when timeframe and interval are specified" do
137
+ let(:tf) { stub('timeframe') }
138
+ before { query.stub(options: { timeframe: 'this_day', interval: :hourly }, timeframe: tf) }
139
+
140
+ it "splits timeframe into intervals of sub-timeframes" do
141
+ interval = stub('interval')
142
+ Sleek::Interval.should_receive(:new).with(:hourly, tf).and_return(interval)
143
+ interval.should_receive(:timeframes)
144
+ query.series
145
+ end
146
+ end
147
+ end
148
+
149
+ describe "#valid_options?" do
150
+ context "when options is a hash" do
151
+ context "when no interval is passed" do
152
+ before { query.stub(options: {}) }
153
+
154
+ it "is true" do
155
+ expect(query.valid_options?).to be_true
156
+ end
157
+ end
158
+
159
+ context "when interval is passed" do
160
+ context "when timeframe is passed" do
161
+ before { query.stub(options: { interval: :hourly, timeframe: Time.now.all_day }) }
162
+
163
+ it "is true" do
164
+ expect(query.valid_options?).to be_true
165
+ end
166
+ end
167
+
168
+ context "when timeframe is not passed" do
169
+ before { query.stub(options: { interval: :hourly }) }
170
+ it "is false" do
171
+ expect(query.valid_options?).to be_false
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ context "when options isn't a hash" do
178
+ before { query.stub(options: 1) }
179
+
180
+ it "is false" do
181
+ expect(query.valid_options?).to be_false
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "#run" do
187
+ context "when no series were requested" do
188
+ it "performs query on events" do
189
+ events = stub
190
+ result = stub
191
+ query.should_receive(:perform).with(events).and_return(result)
192
+ query.stub(events: events)
193
+ query.run
194
+ end
195
+ end
196
+
197
+ context "when series were requested" do
198
+ let(:series) { (0..23).to_a.map { |i| stub(to_time_range: (i..(i+1))) } }
199
+ before { query.stub(options: { timeframe: 'this_day', interval: :hourly }, series: series) }
200
+
201
+ it "performs query on each of sub-timeframes" do
202
+ 24.times do |i|
203
+ evts = stub('events')
204
+ query.should_receive(:events).with(i..(i+1)).and_return(evts)
205
+ query.should_receive(:perform).with(evts)
206
+ end
207
+
208
+ query.run
209
+ end
210
+
211
+ it "returns the array of results" do
212
+ results = []
213
+
214
+ 24.times do |i|
215
+ evts = stub('events')
216
+ value = stub('value')
217
+ results << { timeframe: series[i], value: value }
218
+ query.should_receive(:events).with(i..(i+1)).and_return(evts)
219
+ query.should_receive(:perform).with(evts).and_return(value)
220
+ end
221
+
222
+ expect(query.run).to eq results
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek::Queries::Sum do
4
+ subject(:query) { Sleek::Queries::Sum.new(:default, :purchases, target_property: "total") }
5
+
6
+ describe "#perform" do
7
+ it "counts the events" do
8
+ events = stub('events')
9
+ events.should_receive(:sum).with("d.total").and_return(2_072_70)
10
+ expect(query.perform(events)).to eq 2_072_70
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek::Queries::Targetable do
4
+ let(:query_superclass) do
5
+ Class.new(Struct.new(:options)) do
6
+ def valid_options?; true; end
7
+ end
8
+ end
9
+
10
+ let(:query_class) do
11
+ Class.new(query_superclass) do
12
+ include Sleek::Queries::Targetable
13
+ end
14
+ end
15
+
16
+ describe "validation" do
17
+ context "when target_property is passed" do
18
+ it "should pass" do
19
+ expect(query_class.new(target_property: :a).valid_options?).to be true
20
+ end
21
+ end
22
+
23
+ context "when target_property is not passed" do
24
+ it "should not pass" do
25
+ expect(query_class.new({}).valid_options?).to be false
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek::QueryCollection do
4
+ subject(:collection) { Sleek::QueryCollection.new(:default) }
5
+
6
+ describe "#initialize" do
7
+ it "sets the namespace" do
8
+ collection = Sleek::QueryCollection.new(:my_namespace)
9
+ expect(collection.namespace).to eq :my_namespace
10
+ end
11
+ end
12
+
13
+ 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
+ collection.count(:purchases, { some: :opts })
17
+ end
18
+
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)
23
+
24
+ collection.count(:purchases)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek::Timeframe do
4
+ let(:start_time) { 1.day.ago }
5
+ let(:end_time) { Time.now }
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
+
28
+ describe ".to_range" do
29
+ context "when passed a range" do
30
+ context "when the range is of Time objects" do
31
+ it "returns that range" do
32
+ expect(Sleek::Timeframe.to_range(range)).to eq range
33
+ end
34
+ end
35
+
36
+ context "when passed other range" do
37
+ it "raises an exception" do
38
+ expect { Sleek::Timeframe.to_range(1..3) }.to raise_exception ArgumentError
39
+ end
40
+ end
41
+ end
42
+
43
+ context "when passed an array" do
44
+ context "when array has two Time elements" do
45
+ it "constructs the range" do
46
+ expect(Sleek::Timeframe.to_range([start_time, end_time])).to eq range
47
+ end
48
+ end
49
+
50
+ context "when passed other array" do
51
+ 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
54
+ end
55
+ end
56
+ end
57
+
58
+ 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
63
+ end
64
+ end
65
+ end
66
+
67
+ describe ".parse" do
68
+ context "when passed the proper string" do
69
+ 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
73
+
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
77
+ end
78
+ end
79
+
80
+ context "when passed malformed string" do
81
+ it "raises an exception" do
82
+ expect { Sleek::Timeframe.parse('lol_wut') }.to raise_exception ArgumentError, "special timeframe string is malformed"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sleek do
4
+ describe ".for_namespace" do
5
+ it "should return namespaced Sleek::Base instance" do
6
+ Sleek::Base.should_receive(:new).with(:test_ns)
7
+ Sleek.for_namespace(:test_ns)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'sleek'
2
+ require 'database_cleaner'
3
+
4
+ Mongoid.configure do |config|
5
+ config.connect_to('sleek_test', consistency: :strong)
6
+ end
7
+
8
+ RSpec.configure do |config|
9
+ config.before(:suite) do
10
+ DatabaseCleaner.strategy = :truncation
11
+ DatabaseCleaner.orm = 'mongoid'
12
+ end
13
+
14
+ config.before(:each) do
15
+ DatabaseCleaner.clean
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sleek
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gosha Arinich
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.2'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.2'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '2.13'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '2.13'
94
+ - !ruby/object:Gem::Dependency
95
+ name: database_cleaner
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '0.9'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '0.9'
110
+ description: Sleek is a library for doing analytics.
111
+ email:
112
+ - me@goshakkk.name
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - .rspec
119
+ - .travis.yml
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - lib/sleek.rb
125
+ - lib/sleek/base.rb
126
+ - lib/sleek/core_ext/range.rb
127
+ - lib/sleek/core_ext/time.rb
128
+ - lib/sleek/event.rb
129
+ - lib/sleek/filter.rb
130
+ - lib/sleek/interval.rb
131
+ - lib/sleek/queries.rb
132
+ - lib/sleek/queries/average.rb
133
+ - lib/sleek/queries/count.rb
134
+ - lib/sleek/queries/count_unique.rb
135
+ - lib/sleek/queries/maximum.rb
136
+ - lib/sleek/queries/minimum.rb
137
+ - lib/sleek/queries/query.rb
138
+ - lib/sleek/queries/sum.rb
139
+ - lib/sleek/queries/targetable.rb
140
+ - lib/sleek/query_collection.rb
141
+ - lib/sleek/timeframe.rb
142
+ - lib/sleek/version.rb
143
+ - sleek.gemspec
144
+ - sleek.png
145
+ - spec/lib/sleek/base_spec.rb
146
+ - spec/lib/sleek/event_spec.rb
147
+ - spec/lib/sleek/filter_spec.rb
148
+ - spec/lib/sleek/interval_spec.rb
149
+ - spec/lib/sleek/queries/average_spec.rb
150
+ - spec/lib/sleek/queries/count_spec.rb
151
+ - spec/lib/sleek/queries/count_unique_spec.rb
152
+ - spec/lib/sleek/queries/maximum_spec.rb
153
+ - spec/lib/sleek/queries/minimum_spec.rb
154
+ - spec/lib/sleek/queries/query_spec.rb
155
+ - spec/lib/sleek/queries/sum_spec.rb
156
+ - spec/lib/sleek/queries/targetable_spec.rb
157
+ - spec/lib/sleek/query_collection_spec.rb
158
+ - spec/lib/sleek/timeframe_spec.rb
159
+ - spec/lib/sleek_spec.rb
160
+ - spec/spec_helper.rb
161
+ homepage: http://github.com/goshakkk/sleek
162
+ licenses:
163
+ - MIT
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ! '>='
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 1.8.23
183
+ signing_key:
184
+ specification_version: 3
185
+ summary: Sleek is a library for doing analytics.
186
+ test_files:
187
+ - spec/lib/sleek/base_spec.rb
188
+ - spec/lib/sleek/event_spec.rb
189
+ - spec/lib/sleek/filter_spec.rb
190
+ - spec/lib/sleek/interval_spec.rb
191
+ - spec/lib/sleek/queries/average_spec.rb
192
+ - spec/lib/sleek/queries/count_spec.rb
193
+ - spec/lib/sleek/queries/count_unique_spec.rb
194
+ - spec/lib/sleek/queries/maximum_spec.rb
195
+ - spec/lib/sleek/queries/minimum_spec.rb
196
+ - spec/lib/sleek/queries/query_spec.rb
197
+ - spec/lib/sleek/queries/sum_spec.rb
198
+ - spec/lib/sleek/queries/targetable_spec.rb
199
+ - spec/lib/sleek/query_collection_spec.rb
200
+ - spec/lib/sleek/timeframe_spec.rb
201
+ - spec/lib/sleek_spec.rb
202
+ - spec/spec_helper.rb
203
+ has_rdoc: