cat_tree 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a4a536bc23956e61a60529f845b14fcef498f05a
4
+ data.tar.gz: fb7863349ba46fd6bc5c716821f2dede4a944cfd
5
+ SHA512:
6
+ metadata.gz: dffce9f4cc59207c5250e6665264c8a43012ebefa8fdbd0ca77658e169f2c98e2d55478e5f1d2578c31e23a2a0aed5e20777b4e21badd5b1e55ca09bad8e45a6
7
+ data.tar.gz: 67e5e948910397d2b1eee3b088cffd0749b2b6b1a269b77c1a8e17bd2b73bf8ab756c47d19e08612526a056f8f37f983eb8b8a69a7cd99dcebcd23630fddf191
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ bundle
16
+ gemfiles/*.lock
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "rails3" do
2
+ gem "activerecord", "~> 3.2.0"
3
+ end
4
+
5
+ appraise "rails40" do
6
+ gem "activerecord", "~> 4.0.0"
7
+ end
8
+
9
+ appraise "rails41" do
10
+ gem "activerecord", "~> 4.1.0"
11
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cat_tree.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Tsukasa OISHI
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # CatTree
2
+
3
+ CatTree monitors ActiveRecord objects in development environment the number of objects and the number of same objects.
4
+ It helps you decrease waste of memory and increase application performance.
5
+
6
+ ![CatTree](http://s3-ap-northeast-1.amazonaws.com/kaeruspoon/images/110/large.JPG?1328342672)
7
+
8
+
9
+ ## Usage
10
+
11
+ You can be used by simply installing.
12
+ CatTree notifies the result analyzing ActiveRecord objects. Look at the Rails log when Rails action finished.
13
+
14
+ ```
15
+ Started GET "/top" for xxx.xxx.xxx.xxx at yyyy
16
+ Processing by TopController#index as HTML
17
+ Parameters: {}
18
+ ....
19
+
20
+ [CatTree]
21
+ ActiveRecord::Base: 102
22
+ Same objects:
23
+ User(id:12): 2
24
+ /Users/tsukasa/dev/kaeruspoon/app/controllers/top_controller.rb:5:in `index'
25
+
26
+ /Users/tsukasa/dev/kaeruspoon/app/controllers/top_controller.rb:6:in `index'
27
+
28
+ Completed 200 OK in 1121.8ms (Views: 899.0ms | ActiveRecord: 222.8ms)
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ Add this line to your application's Gemfile:
34
+
35
+ ```ruby
36
+ gem 'cat_tree'
37
+ ```
38
+
39
+ And then execute:
40
+
41
+ $ bundle
42
+
43
+ Or install it yourself as:
44
+
45
+ $ gem install cat_tree
46
+
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it ( https://github.com/[my-github-username]/cat_tree/fork )
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create a new Pull Request
55
+
56
+
57
+ ## Test
58
+
59
+ I'm glad that you would do test!
60
+ To run the test suite, you need mysql installed.
61
+ How to setup your test environment.
62
+
63
+
64
+ ```bash
65
+ bundle install --path bundle
66
+ GEM_HOME=bundle/ruby/(your ruby version) gem install bundler --pre
67
+ bundle exec appraisal install
68
+ ```
69
+
70
+ This command run the spec suite for all rails versions supported.
71
+
72
+ ```base
73
+ bundle exec appraisal rake spec
74
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/cat_tree.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cat_tree/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cat_tree"
8
+ spec.version = CatTree::VERSION
9
+ spec.authors = ["Tsukasa OISHI"]
10
+ spec.email = ["tsukasa.oishi@gmail.com"]
11
+ spec.summary = %q{CatTree monitors ActiveRecord objects in development environment}
12
+ spec.description = %q{CatTree monitors ActiveRecord objects in development environment}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activerecord', '>= 3.2.0', '< 4.2'
22
+ spec.add_dependency 'activesupport', '>= 3.2.0', '< 4.2'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", '~> 2.14'
27
+ spec.add_development_dependency 'appraisal', '~> 1.0'
28
+ spec.add_development_dependency 'mysql2'
29
+ end
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.0"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.0"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.0"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,38 @@
1
+ module CatTree
2
+ module Initializer
3
+ module ClassMethods
4
+ @@cat_tree_observer = {}
5
+
6
+ def add_cat_tree_observer(observer)
7
+ @@cat_tree_observer[Thread.current.object_id] = observer
8
+ end
9
+
10
+ def remove_cat_tree_observer
11
+ @@cat_tree_observer[Thread.current.object_id] = nil
12
+ end
13
+
14
+ def cat_tree_notice(object)
15
+ if cat_tree_observer = @@cat_tree_observer[Thread.current.object_id]
16
+ cat_tree_observer.notice(object)
17
+ end
18
+ end
19
+ end
20
+
21
+ module ArBase
22
+ def self.included(base)
23
+ base.after_initialize :cat_tree_notice
24
+ base.extend CatTree::Initializer::ClassMethods
25
+ end
26
+
27
+ private
28
+
29
+ def cat_tree_notice
30
+ self.class.cat_tree_notice(self)
31
+ end
32
+ end
33
+
34
+ def self.extend_active_record
35
+ ActiveRecord::Base.__send__(:include, Initializer::ArBase)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ module CatTree
2
+ class Logger
3
+ class << self
4
+ attr_writer :logger
5
+
6
+ def warn(message)
7
+ return unless @logger
8
+ @logger.warn message
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,68 @@
1
+ require 'active_record'
2
+ require 'cat_tree/logger'
3
+
4
+ module CatTree
5
+ class Observer
6
+ def self.check(&block)
7
+ self.new.check(&block)
8
+ end
9
+
10
+ def initialize
11
+ @ar_base = {}
12
+ end
13
+
14
+ def notice(object)
15
+ return if object.new_record?
16
+ key = "#{object.class.name}(id:#{object.id})"
17
+ @ar_base[key] ||= {:count => 0, :callers => []}
18
+ @ar_base[key][:count] += 1
19
+ if defined?(Rails)
20
+ root_path = Rails.root.to_s
21
+ root_path += "/" unless root_path.last == "/"
22
+ cal = caller.select{|c| c =~ %r!#{root_path}(app|lib)/!}
23
+ @ar_base[key][:callers] << cal unless cal.empty?
24
+ else
25
+ @ar_base[key][:callers] << caller
26
+ end
27
+ end
28
+
29
+ def ar_base_count
30
+ @ar_base.values.inject(0){|t,v| t + v[:count]}
31
+ end
32
+
33
+ def same_ar_base_objects
34
+ Hash[*(@ar_base.select{|k,v| v[:count] > 1}.flatten)]
35
+ end
36
+
37
+ def check
38
+ ActiveRecord::Base.add_cat_tree_observer(self)
39
+ yield
40
+ ensure
41
+ ActiveRecord::Base.remove_cat_tree_observer
42
+ output_message
43
+ end
44
+
45
+ private
46
+
47
+ def output_message
48
+ return if @ar_base.empty?
49
+
50
+ msg = ["", "[CatTree]"]
51
+ msg << " ActiveRecord::Base:\t#{ar_base_count}"
52
+
53
+ unless (same_objects = same_ar_base_objects).empty?
54
+ msg << " Same objects:"
55
+ same_objects.keys.sort_by{|k| same_objects[k][:count]}.reverse.each do |key|
56
+ msg << " #{key}:\t#{same_objects[key][:count]}"
57
+ same_objects[key][:callers].each do |cal|
58
+ cal.each{|c| msg << " #{c}"}
59
+ msg << ""
60
+ end
61
+ end
62
+ end
63
+ msg << ""
64
+
65
+ Logger.warn msg.join("\n")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,15 @@
1
+ require 'cat_tree/observer'
2
+
3
+ module CatTree
4
+ class Rack
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ Observer.check do
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require "cat_tree/rack"
2
+ require "cat_tree/initializer"
3
+ require "cat_tree/logger"
4
+ require 'rails'
5
+
6
+ module CatTree
7
+ class Railtie < Rails::Railtie
8
+ initializer "cat_tree.configure_rails_initialization" do |app|
9
+ app.config.app_middleware.use CatTree::Rack
10
+ CatTree::Logger.logger = Rails.logger
11
+
12
+ ActiveSupport.on_load(:active_record) do
13
+ Initializer.extend_active_record
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module CatTree
2
+ VERSION = "0.0.1"
3
+ end
data/lib/cat_tree.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "cat_tree/version"
2
+ require "cat_tree/initializer"
3
+ require "cat_tree/observer"
4
+ require "cat_tree/rack"
5
+ require "cat_tree/railtie" if defined?(Rails)
Binary file
@@ -0,0 +1,32 @@
1
+ ENV["RAILS_ENV"]="test"
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'logger'
4
+ require 'cat_tree'
5
+
6
+ ActiveRecord::Base.establish_connection(
7
+ :adapter => 'mysql2',
8
+ :encoding => 'utf8',
9
+ :reconnect => false,
10
+ :database => 'cat_tree_test',
11
+ :username => 'root',
12
+ :pool => 5,
13
+ :timeout => 5000
14
+ )
15
+
16
+ module TruncateTable
17
+ def truncate
18
+ connection.execute("TRUNCATE TABLE #{table_name}")
19
+ end
20
+ end
21
+
22
+ class User < ActiveRecord::Base
23
+ extend TruncateTable
24
+ has_many :articles
25
+ end
26
+
27
+ class Article < ActiveRecord::Base
28
+ extend TruncateTable
29
+ belongs_to :user
30
+ end
31
+
32
+ CatTree::Initializer.extend_active_record
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe CatTree::Observer do
4
+ before do
5
+ User.truncate
6
+ Article.truncate
7
+
8
+ u = User.create(:name => "cat_tree")
9
+ u.articles.create(:title => "title1")
10
+ u.articles.create(:title => "title2")
11
+ u2 = User.create(:name => "cat_tree2")
12
+ u2.articles.create(:title => "title3")
13
+ @number_of_object = rand(10) + 1
14
+ end
15
+
16
+ context "#check" do
17
+ it "count to find AR::Base object" do
18
+ observer = CatTree::Observer.new
19
+ observer.check do
20
+ @number_of_object.times { User.where(:name => "cat_tree").first }
21
+ end
22
+
23
+ expect(observer.ar_base_count).to eq(@number_of_object)
24
+ end
25
+
26
+ it "count to find AR::Base object with association" do
27
+ observer = CatTree::Observer.new
28
+ observer.check do
29
+ @number_of_object.times { User.includes(:articles).where(:name => "cat_tree").first }
30
+ end
31
+
32
+ expect(observer.ar_base_count).to eq(@number_of_object * 3)
33
+ end
34
+
35
+ it "count same AR:Base object" do
36
+ @number_of_object += 1
37
+ observer = CatTree::Observer.new
38
+ observer.check do
39
+ User.new
40
+ User.create(:name => "dummy")
41
+ @number_of_object.times do
42
+ User.includes(:articles).where(:name => "cat_tree").first
43
+ end
44
+ end
45
+
46
+ result = observer.same_ar_base_objects
47
+ expect(result.size).to eq(3)
48
+ result.each do |key, value|
49
+ expect(["User(id:1)", "Article(id:1)", "Article(id:2)"]).to include(key)
50
+ expect(value[:count]).to eq(@number_of_object)
51
+ end
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cat_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tsukasa OISHI
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 3.2.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '4.2'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.2.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '4.2'
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.7'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.7'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '10.0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '10.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '2.14'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '2.14'
95
+ - !ruby/object:Gem::Dependency
96
+ name: appraisal
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: mysql2
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ description: CatTree monitors ActiveRecord objects in development environment
124
+ email:
125
+ - tsukasa.oishi@gmail.com
126
+ executables: []
127
+ extensions: []
128
+ extra_rdoc_files: []
129
+ files:
130
+ - ".gitignore"
131
+ - Appraisals
132
+ - Gemfile
133
+ - LICENSE.txt
134
+ - README.md
135
+ - Rakefile
136
+ - cat_tree.gemspec
137
+ - gemfiles/rails3.gemfile
138
+ - gemfiles/rails40.gemfile
139
+ - gemfiles/rails41.gemfile
140
+ - lib/cat_tree.rb
141
+ - lib/cat_tree/initializer.rb
142
+ - lib/cat_tree/logger.rb
143
+ - lib/cat_tree/observer.rb
144
+ - lib/cat_tree/rack.rb
145
+ - lib/cat_tree/railtie.rb
146
+ - lib/cat_tree/version.rb
147
+ - spec/cat_tree_test.sqlite3
148
+ - spec/spec_helper.rb
149
+ - spec/unit/observer_spec.rb
150
+ homepage: ''
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.2.2
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: CatTree monitors ActiveRecord objects in development environment
174
+ test_files:
175
+ - spec/cat_tree_test.sqlite3
176
+ - spec/spec_helper.rb
177
+ - spec/unit/observer_spec.rb