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.
@@ -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 "A clicker was initialized to write to that database."
20
- puts "You can access it as `clicker`."
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
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'sinatra'
4
+ gem 'sequel'
5
+ gem 'sqlite3'
6
+ gem 'click', path: File.join(File.dirname(__FILE__), '..')
@@ -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`.
@@ -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
@@ -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
@@ -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
 
@@ -1,2 +1,3 @@
1
+ require 'click/database/models/session'
1
2
  require 'click/database/models/snapshot'
2
3
  require 'click/database/models/object_count'
@@ -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
@@ -0,0 +1,17 @@
1
+ require 'sequel'
2
+
3
+ module Click
4
+ module Database
5
+ module Models
6
+ class Session < Sequel::Model
7
+ one_to_many :snapshot
8
+
9
+ dataset_module do
10
+ def by_name(name)
11
+ from_self.where(name: name)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -14,6 +14,11 @@ module Click
14
14
  def before(time)
15
15
  filter { timestamp < time}
16
16
  end
17
+
18
+ def by_session_name(session_name)
19
+ session_dataset = Session.where(name: session_name)
20
+ from_self.qualify.join(session_dataset, id: :session_id)
21
+ end
17
22
  end
18
23
  end
19
24
  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
@@ -5,5 +5,8 @@ module Click
5
5
 
6
6
  def after_click(clicker)
7
7
  end
8
+
9
+ def on_add(clicker)
10
+ end
8
11
  end
9
12
  end
@@ -1,3 +1,3 @@
1
1
  module Click
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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 before_click and after_click' do
78
- observer = double(before_click: nil, after_click: nil)
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
- describe Click::Database::Models::ObjectCount do
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
- describe Click::Database::Models::Snapshot do
7
- describe 'scopes' do
8
- describe '.after' do
9
- it 'excludes records prior to the given time' do
10
- with_in_memory_db do
11
- described_class.create(timestamp: Date.new(2000))
12
- later = described_class.create(timestamp: Date.new(2006))
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
- expect(described_class.after(Date.new(2003)).all).to eq([later])
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
- describe '.before' do
20
- it 'excludes records after the given time' do
21
- with_in_memory_db do
22
- earlier = described_class.create(timestamp: Date.new(2000))
23
- described_class.create(timestamp: Date.new(2006))
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
- expect(described_class.before(Date.new(2003)).all).to eq([earlier])
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
- it 'can combine scopes' do
31
- with_in_memory_db do
32
- described_class.create(timestamp: Date.new(2000))
33
- middle = described_class.create(timestamp: Date.new(2003))
34
- described_class.create(timestamp: Date.new(2006))
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
- expect(described_class.after(Date.new(2001)).before(Date.new(2005)).all).to eq([middle])
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
- clicker.add_observer(writer)
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)
@@ -9,7 +9,7 @@ describe Click::Observer do
9
9
  end
10
10
 
11
11
  expect {
12
- clicker = Click::Clicker.new
12
+ clicker = Click::Clicker.new('test')
13
13
  clicker.add_observer(klass.new)
14
14
  clicker.click!
15
15
  }.not_to raise_error
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.3
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-02 00:00:00.000000000 Z
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