boffin 0.1.0
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/.gitignore +4 -0
- data/.rspec +2 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +8 -0
- data/LICENSE +18 -0
- data/README.md +302 -0
- data/Rakefile +14 -0
- data/boffin.gemspec +29 -0
- data/lib/boffin.rb +87 -0
- data/lib/boffin/config.rb +91 -0
- data/lib/boffin/hit.rb +83 -0
- data/lib/boffin/keyspace.rb +147 -0
- data/lib/boffin/trackable.rb +66 -0
- data/lib/boffin/tracker.rb +229 -0
- data/lib/boffin/utils.rb +171 -0
- data/lib/boffin/version.rb +4 -0
- data/spec/boffin/config_spec.rb +65 -0
- data/spec/boffin/hit_spec.rb +42 -0
- data/spec/boffin/keyspace_spec.rb +85 -0
- data/spec/boffin/trackable_spec.rb +38 -0
- data/spec/boffin/tracker_spec.rb +162 -0
- data/spec/boffin/utils_spec.rb +158 -0
- data/spec/boffin_spec.rb +44 -0
- data/spec/spec_helper.rb +50 -0
- metadata +128 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Boffin::Utils do
|
4
|
+
describe '::underscore' do
|
5
|
+
it 'works with namespaces' do
|
6
|
+
subject.underscore('MyMod::MyClass').should == 'my_mod_my_class'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'works without namespaces' do
|
10
|
+
subject.underscore('MyMod').should == 'my_mod'
|
11
|
+
subject.underscore('Mod').should == 'mod'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'works with blank strings' do
|
15
|
+
subject.underscore('').should == ''
|
16
|
+
subject.underscore(' ').should == ' '
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '::blank?' do
|
21
|
+
it 'returns true for []' do
|
22
|
+
subject.blank?([]).should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns true for {}' do
|
26
|
+
subject.blank?({}).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns true for nil' do
|
30
|
+
subject.blank?(nil).should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns true for ""' do
|
34
|
+
subject.blank?('').should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns true for false' do
|
38
|
+
subject.blank?(false).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns false for non-blank things' do
|
42
|
+
subject.blank?(0).should be_false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '::extract_time_unit' do
|
47
|
+
specify { subject.extract_time_unit(hours: 6).should == [:hours, 6] }
|
48
|
+
specify { subject.extract_time_unit(days: 2).should == [:days, 2] }
|
49
|
+
specify { subject.extract_time_unit(months: 3).should == [:months, 3] }
|
50
|
+
|
51
|
+
it 'throws an error if no time unit pair exists in the hash' do
|
52
|
+
lambda { subject.extract_time_unit(fun: 'times') }.
|
53
|
+
should raise_error ArgumentError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '::time_ago' do
|
58
|
+
before { @time = Time.local(2011, 2, 15, 12) }
|
59
|
+
|
60
|
+
specify { subject.time_ago(@time, hours: 6).should == Time.local(2011, 2, 15, 6) }
|
61
|
+
specify { subject.time_ago(@time, days: 5).should == Time.local(2011, 2, 10, 12) }
|
62
|
+
specify { subject.time_ago(@time, months: 1).should == Time.local(2011, 1, 16, 12) } # A "month" is 30 days
|
63
|
+
|
64
|
+
it 'throws an error if no time unit pair exists in the hash' do
|
65
|
+
lambda { subject.time_ago(@time, fun: 'fail') }.
|
66
|
+
should raise_error ArgumentError
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '::time_ago_range' do
|
71
|
+
before { @time = Time.local(2011, 2, 15, 12) }
|
72
|
+
|
73
|
+
specify { subject.time_ago_range(@time, hours: 6).size.should == 6 }
|
74
|
+
specify { subject.time_ago_range(@time, months: 1).size.should == 1 }
|
75
|
+
|
76
|
+
specify do
|
77
|
+
subject.time_ago_range(@time, days: 2).
|
78
|
+
should == [Time.local(2011, 2, 14, 12), Time.local(2011, 2, 15, 12)]
|
79
|
+
end
|
80
|
+
|
81
|
+
specify do
|
82
|
+
subject.time_ago_range(@time, days: 3).
|
83
|
+
should == [
|
84
|
+
Time.local(2011, 2, 13, 12),
|
85
|
+
Time.local(2011, 2, 14, 12),
|
86
|
+
Time.local(2011, 2, 15, 12)
|
87
|
+
]
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'ranges from n days away upto @time' do
|
91
|
+
times = subject.time_ago_range(@time, days: 4)
|
92
|
+
times.first.should == Time.local(2011, 2, 12, 12)
|
93
|
+
times.last.should == @time
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'throws an error if no time unit pair exists in the hash' do
|
97
|
+
lambda { subject.time_ago_range(@time, fun: 'crash') }.
|
98
|
+
should raise_error ArgumentError
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '::uniquenesses_as_session_identifier' do
|
103
|
+
specify do
|
104
|
+
subject.uniquenesses_as_session_identifier([]).
|
105
|
+
should == Boffin::NIL_SESSION_MEMBER
|
106
|
+
end
|
107
|
+
|
108
|
+
specify do
|
109
|
+
subject.uniquenesses_as_session_identifier([nil, 'hi']).
|
110
|
+
should == 'hi'
|
111
|
+
end
|
112
|
+
|
113
|
+
specify do
|
114
|
+
subject.uniquenesses_as_session_identifier([MockDitty.new]).
|
115
|
+
should == 'mock_ditty:1'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '::object_as_session_identifier' do
|
120
|
+
specify { subject.object_as_session_identifier(nil).should == '' }
|
121
|
+
specify { subject.object_as_session_identifier(3.14).should == '3.14' }
|
122
|
+
|
123
|
+
specify do
|
124
|
+
subject.object_as_session_identifier(MockDitty.new).
|
125
|
+
should == 'mock_ditty:1'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '::object_as_member' do
|
130
|
+
it 'calls #as_member on the object if available' do
|
131
|
+
obj = MockMember.new(100)
|
132
|
+
subject.object_as_member(obj).should == '100'
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'calls #id.to_s on the object if available' do
|
136
|
+
obj = MockDitty.new(100)
|
137
|
+
subject.object_as_member(obj).should == '100'
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'calls #to_s on everything else' do
|
141
|
+
subject.object_as_member(3.14).should == '3.14'
|
142
|
+
subject.object_as_member(:symbol).should == 'symbol'
|
143
|
+
subject.object_as_member('string').should == 'string'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '::object_as_namespace' do
|
148
|
+
specify { subject.object_as_namespace(:ns).should == 'ns' }
|
149
|
+
specify { subject.object_as_namespace(MockDitty).should == 'mock_ditty' }
|
150
|
+
specify { subject.object_as_namespace('ns').should == 'ns' }
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '::object_as_key' do
|
154
|
+
specify { subject.object_as_key(MockDitty.new).should == '1' }
|
155
|
+
specify { subject.object_as_key(100).should == 'MTAw' }
|
156
|
+
specify { subject.object_as_key('/test?te=st').should == 'L3Rlc3Q/dGU9c3Q=' }
|
157
|
+
end
|
158
|
+
end
|
data/spec/boffin_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MockEmptyDitty < MockDitty; end
|
4
|
+
|
5
|
+
describe Boffin do
|
6
|
+
describe '::track' do
|
7
|
+
before do
|
8
|
+
@tracker = Boffin.track(MockEmptyDitty, [:views, :tests])
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'injects Trackable into a class' do
|
12
|
+
MockEmptyDitty.include?(Boffin::Trackable).should be_true
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'sets hit types' do
|
16
|
+
MockEmptyDitty.boffin.hit_types.should == [:views, :tests]
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns Trackable' do
|
20
|
+
Boffin.track(:thing).should be_a Boffin::Tracker
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '::config' do
|
25
|
+
before do
|
26
|
+
@config = Boffin.config.dup
|
27
|
+
Boffin.instance_variable_set(:@config, nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
after do
|
31
|
+
Boffin.instance_variable_set(:@config, @config)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'accepts a hash' do
|
35
|
+
Boffin.config(namespace: 'trendy')
|
36
|
+
Boffin.config.namespace.should == 'trendy'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'accepts a block' do
|
40
|
+
Boffin.config { |c| c.namespace = 'jazzy' }
|
41
|
+
Boffin.config.namespace.should == 'jazzy'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'redis'
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
$redis = if ENV['DEBUG']
|
8
|
+
require 'logger'
|
9
|
+
Redis.connect(logger: Logger.new(STDERR))
|
10
|
+
else
|
11
|
+
Redis.connect
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.expand_path('../../lib/boffin', __FILE__)
|
15
|
+
|
16
|
+
Boffin.config do |c|
|
17
|
+
c.redis = $redis
|
18
|
+
c.namespace = 'boffin_test'
|
19
|
+
end
|
20
|
+
|
21
|
+
class MockDitty
|
22
|
+
attr :id
|
23
|
+
def initialize(id = 1); @id = id; end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Just a different namespace to make the specs easier to follow.
|
27
|
+
class MockUser < MockDitty; end
|
28
|
+
|
29
|
+
class MockMember
|
30
|
+
attr :as_member
|
31
|
+
def initialize(id = 1); @as_member = id; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class MockTrackableIncluded < MockDitty
|
35
|
+
include Boffin::Trackable
|
36
|
+
boffin.hit_types = [:views, :likes]
|
37
|
+
end
|
38
|
+
|
39
|
+
class MockTrackableInjected < MockDitty
|
40
|
+
Boffin.track(self, [:views, :likes])
|
41
|
+
end
|
42
|
+
|
43
|
+
module SpecHelper
|
44
|
+
module_function
|
45
|
+
def flush_keyspace!
|
46
|
+
if (keys = $redis.keys("#{Boffin.config.namespace}*")).any?
|
47
|
+
$redis.del(*keys)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boffin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Carsten Nielsen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-26 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: &70146172825080 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70146172825080
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70146172824200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.6'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70146172824200
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: timecop
|
38
|
+
requirement: &70146172823600 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70146172823600
|
47
|
+
description: ! 'Boffin is a library for tracking hits to things in your Ruby application.
|
48
|
+
Things
|
49
|
+
|
50
|
+
can be IDs of records in a database, strings representing tags or topics, URLs
|
51
|
+
|
52
|
+
of webpages, names of places, whatever you desire. Boffin is able to provide
|
53
|
+
|
54
|
+
lists of those things based on most hits, least hits, it can even report on
|
55
|
+
|
56
|
+
weighted combinations of different types of hits.
|
57
|
+
|
58
|
+
'
|
59
|
+
email: heycarsten@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- .gitignore
|
65
|
+
- .rspec
|
66
|
+
- .yardopts
|
67
|
+
- CHANGELOG.md
|
68
|
+
- Gemfile
|
69
|
+
- LICENSE
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- boffin.gemspec
|
73
|
+
- lib/boffin.rb
|
74
|
+
- lib/boffin/config.rb
|
75
|
+
- lib/boffin/hit.rb
|
76
|
+
- lib/boffin/keyspace.rb
|
77
|
+
- lib/boffin/trackable.rb
|
78
|
+
- lib/boffin/tracker.rb
|
79
|
+
- lib/boffin/utils.rb
|
80
|
+
- lib/boffin/version.rb
|
81
|
+
- spec/boffin/config_spec.rb
|
82
|
+
- spec/boffin/hit_spec.rb
|
83
|
+
- spec/boffin/keyspace_spec.rb
|
84
|
+
- spec/boffin/trackable_spec.rb
|
85
|
+
- spec/boffin/tracker_spec.rb
|
86
|
+
- spec/boffin/utils_spec.rb
|
87
|
+
- spec/boffin_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
homepage: http://github.com/heycarsten/boffin
|
90
|
+
licenses: []
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
hash: -3925281016385501386
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
hash: -3925281016385501386
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project: boffin
|
115
|
+
rubygems_version: 1.8.6
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Hit tracking library for Ruby using Redis
|
119
|
+
test_files:
|
120
|
+
- spec/boffin/config_spec.rb
|
121
|
+
- spec/boffin/hit_spec.rb
|
122
|
+
- spec/boffin/keyspace_spec.rb
|
123
|
+
- spec/boffin/trackable_spec.rb
|
124
|
+
- spec/boffin/tracker_spec.rb
|
125
|
+
- spec/boffin/utils_spec.rb
|
126
|
+
- spec/boffin_spec.rb
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
has_rdoc: yard
|