click 0.0.3 → 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/bin/click-console +4 -4
- data/demo/Gemfile +6 -0
- data/demo/README.md +8 -0
- data/demo/app.rb +61 -0
- data/lib/click/clicker.rb +7 -0
- data/lib/click/database.rb +8 -0
- data/lib/click/database/models.rb +1 -0
- data/lib/click/database/models/object_count.rb +7 -0
- data/lib/click/database/models/session.rb +17 -0
- data/lib/click/database/models/snapshot.rb +5 -0
- data/lib/click/database/writer.rb +7 -2
- data/lib/click/observer.rb +3 -0
- data/lib/click/version.rb +1 -1
- data/spec/clicker_spec.rb +16 -3
- data/spec/database/models/object_count_spec.rb +22 -1
- data/spec/database/models/session_spec.rb +23 -0
- data/spec/database/models/snapshot_spec.rb +42 -22
- data/spec/database/writer_spec.rb +8 -2
- data/spec/observer_spec.rb +1 -1
- metadata +8 -2
data/bin/click-console
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'click/database'
|
4
|
-
require 'click/database/writer'
|
5
4
|
require 'click/clicker'
|
6
5
|
require 'pry'
|
7
6
|
|
@@ -12,12 +11,13 @@ module Click::Database
|
|
12
11
|
puts "Using connection string: #{connection_string}"
|
13
12
|
|
14
13
|
Click::Database.with_database(connection_string) do |db|
|
15
|
-
clicker = Click::Clicker.new
|
14
|
+
clicker = Click::Clicker.new('click-console')
|
15
|
+
require 'click/database/writer'
|
16
16
|
clicker.add_observer(Click::Database::Writer.new(db))
|
17
17
|
|
18
18
|
puts
|
19
|
-
puts
|
20
|
-
puts
|
19
|
+
puts 'A clicker was initialized to write to that database.'
|
20
|
+
puts 'You can access it as `clicker`.'
|
21
21
|
|
22
22
|
binding.pry(quiet: true)
|
23
23
|
end
|
data/demo/Gemfile
ADDED
data/demo/README.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Click demo app
|
2
|
+
|
3
|
+
This demo app serves two purposes.
|
4
|
+
|
5
|
+
1. A demonstration of integrating Click into an application that already uses a separate Sequel database.
|
6
|
+
2. A demonstration of Click in an app with a known memory leak. To leak objects, connect to the `/make_objects/:count` endpoint.
|
7
|
+
|
8
|
+
To inspect Click on the live application, run `click-console sqlite:///tmp/click_demo_memory.sqlite`.
|
data/demo/app.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'rack/logger'
|
3
|
+
require 'sequel'
|
4
|
+
require 'sqlite3'
|
5
|
+
|
6
|
+
require 'click'
|
7
|
+
require 'click/database'
|
8
|
+
|
9
|
+
db = Sequel.sqlite('/tmp/click_demo.sqlite')
|
10
|
+
|
11
|
+
Sequel::Model.db = db
|
12
|
+
|
13
|
+
db.create_table?(:visits) do
|
14
|
+
primary_key :id
|
15
|
+
String :ip_address
|
16
|
+
Time :timestamp
|
17
|
+
end
|
18
|
+
|
19
|
+
class Visit < Sequel::Model
|
20
|
+
end
|
21
|
+
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
24
|
+
Thread.new do
|
25
|
+
begin
|
26
|
+
clicker = nil
|
27
|
+
Click::Database.with_database('sqlite:///tmp/click_demo_memory.sqlite') do |click_db|
|
28
|
+
require 'click/database/writer'
|
29
|
+
writer = Click::Database::Writer.new(click_db)
|
30
|
+
clicker = Click::Clicker.new("Click demo app")
|
31
|
+
clicker.add_observer(writer)
|
32
|
+
end
|
33
|
+
|
34
|
+
loop do
|
35
|
+
clicker.click!
|
36
|
+
puts 'Click!'
|
37
|
+
sleep 10
|
38
|
+
end
|
39
|
+
rescue => e
|
40
|
+
puts "Exception in Click thread: #{e}"
|
41
|
+
raise
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
get '/' do
|
46
|
+
Visit.create(ip_address: request.ip, timestamp: Time.now)
|
47
|
+
|
48
|
+
<<HTML
|
49
|
+
<html><body>
|
50
|
+
<h1>Click demo app</h1>
|
51
|
+
<br/>
|
52
|
+
Visited #{Visit.count} time(s) by #{Visit.group_by(:ip_address).count} IP address(es).
|
53
|
+
</body></html>
|
54
|
+
HTML
|
55
|
+
end
|
56
|
+
|
57
|
+
$garbage = []
|
58
|
+
get '/make_objects/:count' do |count|
|
59
|
+
$garbage.concat(Array.new(count.to_i) { Object.new })
|
60
|
+
"I made #{count} object(s) just for you :)"
|
61
|
+
end
|
data/lib/click/clicker.rb
CHANGED
@@ -2,6 +2,12 @@ require 'click/indeterminable'
|
|
2
2
|
|
3
3
|
module Click
|
4
4
|
class Clicker
|
5
|
+
attr_reader :session_name
|
6
|
+
|
7
|
+
def initialize(session_name)
|
8
|
+
@session_name = session_name
|
9
|
+
end
|
10
|
+
|
5
11
|
def click!
|
6
12
|
observers.each { |o| o.before_click(self) }
|
7
13
|
|
@@ -34,6 +40,7 @@ module Click
|
|
34
40
|
|
35
41
|
def add_observer(observer)
|
36
42
|
observers << observer
|
43
|
+
observer.on_add(self)
|
37
44
|
end
|
38
45
|
|
39
46
|
private
|
data/lib/click/database.rb
CHANGED
@@ -25,13 +25,21 @@ module Click
|
|
25
25
|
|
26
26
|
def assign_db_to_models(db)
|
27
27
|
require 'click/database/models'
|
28
|
+
Click::Database::Models::Session.db = db
|
28
29
|
Click::Database::Models::Snapshot.db = db
|
29
30
|
Click::Database::Models::ObjectCount.db = db
|
30
31
|
end
|
31
32
|
|
32
33
|
def ensure_tables!(db)
|
34
|
+
db.create_table?(:sessions) do
|
35
|
+
primary_key :id
|
36
|
+
String :name, null: false
|
37
|
+
Time :started_at, null: false
|
38
|
+
end
|
39
|
+
|
33
40
|
db.create_table?(:snapshots) do
|
34
41
|
primary_key :id
|
42
|
+
foreign_key :session_id, :sessions, null: false
|
35
43
|
Time :timestamp, null: false
|
36
44
|
end
|
37
45
|
|
@@ -5,6 +5,13 @@ module Click
|
|
5
5
|
module Models
|
6
6
|
class ObjectCount < Sequel::Model
|
7
7
|
many_to_one :snapshot
|
8
|
+
|
9
|
+
dataset_module do
|
10
|
+
def by_session_name(session_name)
|
11
|
+
snapshot_dataset = Snapshot.by_session_name(session_name)
|
12
|
+
from_self.qualify.join(snapshot_dataset, id: :snapshot_id)
|
13
|
+
end
|
14
|
+
end
|
8
15
|
end
|
9
16
|
end
|
10
17
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'click/observer'
|
2
|
+
require 'click/database/models'
|
2
3
|
|
3
4
|
module Click
|
4
5
|
module Database
|
@@ -9,8 +10,12 @@ module Click
|
|
9
10
|
@db = db
|
10
11
|
end
|
11
12
|
|
13
|
+
def on_add(clicker)
|
14
|
+
@session = Models::Session.create(name: clicker.session_name, started_at: Time.now)
|
15
|
+
end
|
16
|
+
|
12
17
|
def after_click(clicker)
|
13
|
-
snapshot = Models::Snapshot.create(timestamp: Time.now)
|
18
|
+
snapshot = Models::Snapshot.create(timestamp: Time.now, session_id: session.id)
|
14
19
|
object_count_hashes = clicker.object_counts.map do |klass, count|
|
15
20
|
{snapshot_id: snapshot.id, class_name: klass.to_s, count: count}
|
16
21
|
end
|
@@ -19,7 +24,7 @@ module Click
|
|
19
24
|
end
|
20
25
|
|
21
26
|
private
|
22
|
-
attr_reader :db
|
27
|
+
attr_reader :db, :session
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
data/lib/click/observer.rb
CHANGED
data/lib/click/version.rb
CHANGED
data/spec/clicker_spec.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Click::Clicker do
|
4
|
-
subject(:clicker) { described_class.new }
|
4
|
+
subject(:clicker) { described_class.new('test') }
|
5
|
+
|
6
|
+
describe '#session_name' do
|
7
|
+
it 'is the string given to the constructor' do
|
8
|
+
expect(clicker.session_name).to eq('test')
|
9
|
+
end
|
10
|
+
end
|
5
11
|
|
6
12
|
describe '#instance_count' do
|
7
13
|
it 'counts instances of a single class' do
|
@@ -74,8 +80,15 @@ describe Click::Clicker do
|
|
74
80
|
end
|
75
81
|
|
76
82
|
describe 'observers' do
|
77
|
-
it 'calls
|
78
|
-
observer = double(
|
83
|
+
it 'calls #on_add' do
|
84
|
+
observer = double(on_add: nil)
|
85
|
+
observer.should_receive(:on_add).with(clicker)
|
86
|
+
|
87
|
+
clicker.add_observer(observer)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'calls #before_click and #after_click' do
|
91
|
+
observer = double(on_add: nil, before_click: nil, after_click: nil)
|
79
92
|
observer.should_receive(:before_click).with(clicker).ordered
|
80
93
|
observer.should_receive(:after_click).with(clicker).ordered
|
81
94
|
|
@@ -3,5 +3,26 @@ require 'click/database'
|
|
3
3
|
|
4
4
|
initialize_models
|
5
5
|
|
6
|
-
|
6
|
+
module Click::Database::Models
|
7
|
+
describe ObjectCount do
|
8
|
+
describe '.scopes' do
|
9
|
+
describe '.by_session_name' do
|
10
|
+
it 'returns only object counts belonging to the session with that name' do
|
11
|
+
with_in_memory_db do
|
12
|
+
ignored_session = Session.create(name: 'ignored', started_at: Time.now)
|
13
|
+
ignored_snapshot = Snapshot.create(timestamp: Time.now, session_id: ignored_session.id)
|
14
|
+
50.times { ObjectCount.create(class_name: "Foo", count: 1, snapshot_id: ignored_snapshot.id) }
|
15
|
+
|
16
|
+
important_session = Session.create(name: 'important', started_at: Time.now)
|
17
|
+
important_snapshot = Snapshot.create(timestamp: Time.now, session_id: important_session.id)
|
18
|
+
important_object_count = ObjectCount.create(class_name: "Bar", count: 2, snapshot_id: important_snapshot.id)
|
19
|
+
|
20
|
+
dataset = ObjectCount.by_session_name('important')
|
21
|
+
expect(dataset.count).to eq(1)
|
22
|
+
expect(dataset.map([:id, :class_name, :count])).to eq([[important_object_count.id, "Bar", 2]])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
7
28
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'click/database'
|
3
|
+
|
4
|
+
initialize_models
|
5
|
+
|
6
|
+
module Click::Database::Models
|
7
|
+
describe Session do
|
8
|
+
describe '.scopes' do
|
9
|
+
describe '.by_name' do
|
10
|
+
it 'returns only object counts belonging to the session with that name' do
|
11
|
+
with_in_memory_db do
|
12
|
+
Session.create(name: 'ignored', started_at: Time.now)
|
13
|
+
|
14
|
+
important_session = Session.create(name: 'important', started_at: Time.now)
|
15
|
+
|
16
|
+
dataset = Session.by_name('important')
|
17
|
+
expect(dataset.all).to eq([important_session])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,37 +3,57 @@ require 'click/database'
|
|
3
3
|
|
4
4
|
initialize_models
|
5
5
|
|
6
|
-
|
7
|
-
describe
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
module Click::Database::Models
|
7
|
+
describe Snapshot do
|
8
|
+
let(:session_id) { Click::Database::Models::Session.create(name: "test", started_at: Time.now).id }
|
9
|
+
|
10
|
+
describe 'scopes' do
|
11
|
+
describe '.after' do
|
12
|
+
it 'excludes records prior to the given time' do
|
13
|
+
with_in_memory_db do
|
14
|
+
described_class.create(timestamp: Date.new(2000), session_id: session_id)
|
15
|
+
later = described_class.create(timestamp: Date.new(2006), session_id: session_id)
|
13
16
|
|
14
|
-
|
17
|
+
expect(described_class.after(Date.new(2003)).all).to eq([later])
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
|
-
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
describe '.before' do
|
23
|
+
it 'excludes records after the given time' do
|
24
|
+
with_in_memory_db do
|
25
|
+
earlier = described_class.create(timestamp: Date.new(2000), session_id: session_id)
|
26
|
+
described_class.create(timestamp: Date.new(2006), session_id: session_id)
|
24
27
|
|
25
|
-
|
28
|
+
expect(described_class.before(Date.new(2003)).all).to eq([earlier])
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
|
-
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
describe '.by_session_name' do
|
34
|
+
it 'returns only snapshots belonging to the session with that name' do
|
35
|
+
with_in_memory_db do
|
36
|
+
ignored_session = Session.create(name: 'ignored', started_at: Time.now)
|
37
|
+
50.times { Snapshot.create(timestamp: Time.now, session_id: ignored_session.id) }
|
38
|
+
|
39
|
+
important_session = Session.create(name: 'important', started_at: Time.now)
|
40
|
+
important_snapshot = Snapshot.create(timestamp: Time.now, session_id: important_session.id)
|
35
41
|
|
36
|
-
|
42
|
+
dataset = Snapshot.by_session_name('important')
|
43
|
+
expect(dataset.count).to eq(1)
|
44
|
+
expect(dataset.map([:id, :timestamp, :session_id])).to eq([[important_snapshot.id, important_snapshot.timestamp, important_session.id]])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'can combine scopes' do
|
50
|
+
with_in_memory_db do
|
51
|
+
described_class.create(timestamp: Date.new(2000), session_id: session_id)
|
52
|
+
middle = described_class.create(timestamp: Date.new(2003), session_id: session_id)
|
53
|
+
described_class.create(timestamp: Date.new(2006), session_id: session_id)
|
54
|
+
|
55
|
+
expect(described_class.after(Date.new(2001)).before(Date.new(2005)).all).to eq([middle])
|
56
|
+
end
|
37
57
|
end
|
38
58
|
end
|
39
59
|
end
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'click/database'
|
3
|
+
|
4
|
+
initialize_models
|
5
|
+
|
3
6
|
require 'click/database/writer'
|
4
7
|
|
5
8
|
describe Click::Database::Writer do
|
6
9
|
it 'writes records to the database' do
|
7
10
|
with_in_memory_db do |db|
|
8
11
|
writer = Click::Database::Writer.new(db)
|
9
|
-
clicker = Click::Clicker.new
|
10
|
-
|
12
|
+
clicker = Click::Clicker.new("test")
|
13
|
+
|
14
|
+
expect {
|
15
|
+
clicker.add_observer(writer)
|
16
|
+
}.to change { Click::Database::Models::Session.count }.from(0).to(1)
|
11
17
|
|
12
18
|
expect(Click::Database::Models::Snapshot.count).to eq(0)
|
13
19
|
expect(Click::Database::Models::ObjectCount.count).to eq(0)
|
data/spec/observer_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: click
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
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-
|
12
|
+
date: 2013-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -124,11 +124,15 @@ files:
|
|
124
124
|
- Rakefile
|
125
125
|
- bin/click-console
|
126
126
|
- click.gemspec
|
127
|
+
- demo/Gemfile
|
128
|
+
- demo/README.md
|
129
|
+
- demo/app.rb
|
127
130
|
- lib/click.rb
|
128
131
|
- lib/click/clicker.rb
|
129
132
|
- lib/click/database.rb
|
130
133
|
- lib/click/database/models.rb
|
131
134
|
- lib/click/database/models/object_count.rb
|
135
|
+
- lib/click/database/models/session.rb
|
132
136
|
- lib/click/database/models/snapshot.rb
|
133
137
|
- lib/click/database/writer.rb
|
134
138
|
- lib/click/indeterminable.rb
|
@@ -137,6 +141,7 @@ files:
|
|
137
141
|
- spec/click_spec.rb
|
138
142
|
- spec/clicker_spec.rb
|
139
143
|
- spec/database/models/object_count_spec.rb
|
144
|
+
- spec/database/models/session_spec.rb
|
140
145
|
- spec/database/models/snapshot_spec.rb
|
141
146
|
- spec/database/writer_spec.rb
|
142
147
|
- spec/observer_spec.rb
|
@@ -170,6 +175,7 @@ test_files:
|
|
170
175
|
- spec/click_spec.rb
|
171
176
|
- spec/clicker_spec.rb
|
172
177
|
- spec/database/models/object_count_spec.rb
|
178
|
+
- spec/database/models/session_spec.rb
|
173
179
|
- spec/database/models/snapshot_spec.rb
|
174
180
|
- spec/database/writer_spec.rb
|
175
181
|
- spec/observer_spec.rb
|