sql_tagger 0.0.1
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/MIT-LICENSE +20 -0
- data/README.rdoc +14 -0
- data/VERSION +1 -0
- data/lib/sql_tagger/mysql.rb +21 -0
- data/lib/sql_tagger.rb +68 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/sql_tagger/mysql_spec.rb +48 -0
- data/spec/sql_tagger_spec.rb +58 -0
- data/sql_tagger.gemspec +16 -0
- metadata +104 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 SlideShare Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
= sql_tagger
|
2
|
+
|
3
|
+
+sql_tagger+ is a gem that inserts comments into SQL queries. These comments
|
4
|
+
include a string from <tt>Kernel#caller</tt> that (hopefully) reveals what Ruby
|
5
|
+
code was responsible for performing the query.
|
6
|
+
|
7
|
+
To use this, just require the appropriate file. For example, to use this with
|
8
|
+
the +mysql+ gem, perform <tt>require 'sql_tagger/mysql'</tt> instead of
|
9
|
+
<tt>require 'mysql'</tt>.
|
10
|
+
|
11
|
+
Before:
|
12
|
+
SELECT 1
|
13
|
+
After:
|
14
|
+
/* program.rb:25:in `some_method' */ SELECT 1
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sql_tagger'
|
2
|
+
require 'mysql'
|
3
|
+
|
4
|
+
class Mysql
|
5
|
+
include SqlTagger::Initializer
|
6
|
+
|
7
|
+
# @see Mysql#query
|
8
|
+
def query_with_sql_tagger(sql, &block)
|
9
|
+
query_without_sql_tagger(@sql_tagger.tag(sql), &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @see Mysql#prepare
|
13
|
+
def prepare_with_sql_tagger(query)
|
14
|
+
prepare_without_sql_tagger(@sql_tagger.tag(query))
|
15
|
+
end
|
16
|
+
|
17
|
+
['query', 'prepare'].each do |method|
|
18
|
+
alias_method "#{method}_without_sql_tagger", method
|
19
|
+
alias_method method, "#{method}_with_sql_tagger"
|
20
|
+
end
|
21
|
+
end
|
data/lib/sql_tagger.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
# Instances of this class insert stack trace comments into SQL queries.
|
4
|
+
class SqlTagger
|
5
|
+
VERSION = IO.read(
|
6
|
+
File.join(File.dirname(__FILE__), '..', 'VERSION')
|
7
|
+
).chomp.freeze
|
8
|
+
|
9
|
+
# @return [Regexp]
|
10
|
+
# regular expression used to match stack strings we should skip (usually
|
11
|
+
# because such stack strings aren't specific enough, like stack strings
|
12
|
+
# where the file belongs to a gem)
|
13
|
+
attr_accessor :exclusion_pattern
|
14
|
+
|
15
|
+
# @return [Set] set that holds stack strings we skipped before
|
16
|
+
attr_reader :exclusion_cache
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@exclusion_pattern = /^#{RbConfig::CONFIG['prefix']}|\/vendor\//
|
20
|
+
@exclusion_cache = Set.new
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the given query string with a string from +Kernel#caller+ prepended
|
24
|
+
# as a comment that reveals what code triggered the query.
|
25
|
+
#
|
26
|
+
# For example, given "SELECT 1", this will return something like
|
27
|
+
# "/* program.rb:25:in `some_method' */ SELECT 1".
|
28
|
+
#
|
29
|
+
# @param [String] sql SQL query string
|
30
|
+
# @return [String] query string with a comment at the beginning
|
31
|
+
def tag(sql)
|
32
|
+
caller(2).each do |string|
|
33
|
+
next if @exclusion_cache.member?(string)
|
34
|
+
if string !~ @exclusion_pattern
|
35
|
+
return "/* #{string} */ #{sql}"
|
36
|
+
else
|
37
|
+
@exclusion_cache.add(string)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Just in case we skip the whole stack somehow ...
|
42
|
+
"/* SqlTagger#tag skipped the whole stack */ #{sql}"
|
43
|
+
end
|
44
|
+
|
45
|
+
@default = self.new
|
46
|
+
|
47
|
+
class << self
|
48
|
+
# @return [SqlTagger] default SqlTagger to use
|
49
|
+
attr_accessor :default
|
50
|
+
end
|
51
|
+
|
52
|
+
# Mixin that monkey patches the receiver's +initialize+ method to set
|
53
|
+
# +@sql_tagger+.
|
54
|
+
module Initializer
|
55
|
+
def self.included(base)
|
56
|
+
base.send(:alias_method, :initialize_without_sql_tagger, :initialize)
|
57
|
+
base.send(:alias_method, :initialize, :initialize_with_sql_tagger)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [SqlTagger] the SqlTagger used to tag queries for this instance
|
61
|
+
attr_accessor :sql_tagger
|
62
|
+
|
63
|
+
def initialize_with_sql_tagger(*args, &block)
|
64
|
+
@sql_tagger = SqlTagger.default
|
65
|
+
initialize_without_sql_tagger(*args, &block)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sql_tagger/mysql'
|
3
|
+
|
4
|
+
describe Mysql do
|
5
|
+
before :all do
|
6
|
+
@db = Mysql.new
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
@db.close
|
11
|
+
end
|
12
|
+
|
13
|
+
it_should_behave_like 'connections with sql_tagger'
|
14
|
+
|
15
|
+
describe '#query' do
|
16
|
+
it 'works' do
|
17
|
+
result = @db.query('SELECT 2')
|
18
|
+
result.fetch_row.should == ['2']
|
19
|
+
result.free
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'works when given a block' do
|
23
|
+
@db.query('SELECT 5') do |result|
|
24
|
+
result.fetch_row.should == ['5']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'calls SqlTagger#tag' do
|
29
|
+
@db.sql_tagger.should_receive(:tag).and_return('/* something.rb */ SELECT 1')
|
30
|
+
@db.query('SELECT 1').free
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#prepare' do
|
35
|
+
it 'works' do
|
36
|
+
stmt = @db.prepare('SELECT ?')
|
37
|
+
stmt.execute(9)
|
38
|
+
stmt.fetch.should == ['9']
|
39
|
+
stmt.free_result
|
40
|
+
stmt.close
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'calls SqlTagger#tag' do
|
44
|
+
@db.sql_tagger.should_receive(:tag).and_return('/* something.rb */ SELECT 1')
|
45
|
+
@db.prepare('SELECT 1').close
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'sql_tagger'
|
2
|
+
|
3
|
+
describe SqlTagger do
|
4
|
+
describe '#tag' do
|
5
|
+
before :each do
|
6
|
+
@sql_tagger = SqlTagger.new
|
7
|
+
prefix = '/usr'
|
8
|
+
@sql_tagger.exclusion_pattern = /^#{prefix}/
|
9
|
+
|
10
|
+
@stack_strings_to_skip = [
|
11
|
+
"#{prefix}/lib//gems/activerecord-2.3.5/lib/active_record/base.rb:500",
|
12
|
+
"#{prefix}//gems/actionpack-2.3.5/lib/something.rb:20",
|
13
|
+
]
|
14
|
+
@valid_stack_string = '/home/app/myapp/lib/user.rb:150'
|
15
|
+
@caller_result = @stack_strings_to_skip + [@valid_stack_string]
|
16
|
+
@sql_tagger.stub!(:caller => @caller_result)
|
17
|
+
|
18
|
+
@sql = 'SELECT 1'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'skips stack strings that match @exclusion_pattern' do
|
22
|
+
@sql_tagger.tag(@sql).should == "/* #{@valid_stack_string} */ #{@sql}"
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns the 1st stack string that does not match @exclusion_pattern' do
|
26
|
+
@caller_result.push(
|
27
|
+
'/home/app/myapp/lib/document.rb:788',
|
28
|
+
'/home/app/myapp/runner.rb:29'
|
29
|
+
)
|
30
|
+
@sql_tagger.tag(@sql).should == "/* #{@valid_stack_string} */ #{@sql}"
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'adds skipped stack strings into @exclusion_cache' do
|
34
|
+
@sql_tagger.exclusion_cache.should be_empty
|
35
|
+
@sql_tagger.tag(@sql)
|
36
|
+
@stack_strings_to_skip.each do |string|
|
37
|
+
@sql_tagger.exclusion_cache.should include(string)
|
38
|
+
end
|
39
|
+
@sql_tagger.exclusion_cache.size.should == @stack_strings_to_skip.length
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'skips strings in @exclusion_cache' do
|
43
|
+
correct_string = '/home/myapp/i.rb:2890'
|
44
|
+
@caller_result.push(correct_string)
|
45
|
+
@sql_tagger.exclusion_cache.add(@valid_stack_string)
|
46
|
+
@sql_tagger.tag(@sql).should == "/* #{correct_string} */ #{@sql}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.default' do
|
51
|
+
it 'returns a functional SqlTagger' do
|
52
|
+
SqlTagger.default.should be_a(SqlTagger)
|
53
|
+
# The following is to ensure that SqlTagger.default is set after
|
54
|
+
# #initialize is defined.
|
55
|
+
SqlTagger.default.exclusion_pattern.should be_a(Regexp)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/sql_tagger.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'sql_tagger'
|
3
|
+
s.version = IO.read('VERSION').chomp
|
4
|
+
s.authors = ['Toby Hsieh']
|
5
|
+
s.homepage = 'https://github.com/SlideShareInc/sql_tagger'
|
6
|
+
s.summary = 'Stack trace comments for SQL queries'
|
7
|
+
s.description = 'sql_tagger inserts stack trace comments into SQL queries.'
|
8
|
+
|
9
|
+
s.add_development_dependency('rspec')
|
10
|
+
s.add_development_dependency('mysql')
|
11
|
+
|
12
|
+
s.files = ['MIT-LICENSE', 'README.rdoc', 'VERSION', 'sql_tagger.gemspec'] +
|
13
|
+
Dir.glob('lib/**/*')
|
14
|
+
|
15
|
+
s.test_files = Dir.glob('spec/**/*')
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sql_tagger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Toby Hsieh
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-05-11 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: mysql
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
description: sql_tagger inserts stack trace comments into SQL queries.
|
50
|
+
email:
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- MIT-LICENSE
|
59
|
+
- README.rdoc
|
60
|
+
- VERSION
|
61
|
+
- sql_tagger.gemspec
|
62
|
+
- lib/sql_tagger/mysql.rb
|
63
|
+
- lib/sql_tagger.rb
|
64
|
+
- spec/spec_helper.rb
|
65
|
+
- spec/sql_tagger/mysql_spec.rb
|
66
|
+
- spec/sql_tagger_spec.rb
|
67
|
+
has_rdoc: true
|
68
|
+
homepage: https://github.com/SlideShareInc/sql_tagger
|
69
|
+
licenses: []
|
70
|
+
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
requirements: []
|
95
|
+
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.3.7
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: Stack trace comments for SQL queries
|
101
|
+
test_files:
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
- spec/sql_tagger/mysql_spec.rb
|
104
|
+
- spec/sql_tagger_spec.rb
|