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 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
@@ -0,0 +1,5 @@
1
+ shared_examples_for 'connections with sql_tagger' do
2
+ it 'assigns SqlTagger.default to @sql_tagger' do
3
+ @db.sql_tagger.should == SqlTagger.default
4
+ end
5
+ end
@@ -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
@@ -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