critique 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/.gemset ADDED
@@ -0,0 +1 @@
1
+ RVM_GEMSET="ruby-1.9.3@critique"
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1,11 @@
1
+ source .gemset
2
+ export USE_BUNDLER=force
3
+
4
+ rvm use --create --install $RVM_GEMSET
5
+
6
+ if [[ -s "./bootstrap.gems" ]]; then
7
+ if ! rvm gemset import bootstrap.gems > /dev/null 2>&1; then
8
+ echo "ERROR: Unable to bootstrap the gems" >&2
9
+ fi
10
+ fi
11
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in critique.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Corey Innis
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,55 @@
1
+ # Critique
2
+
3
+ **WIP**
4
+
5
+ critiques your code... simple memory profiling with easy setup (e.g., no need to patch ruby).
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'critique'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install critique
20
+
21
+ ## Usage
22
+
23
+ given your code:
24
+
25
+ class ExampleClass
26
+ include Critique
27
+
28
+ def method
29
+ critique do
30
+ # code
31
+ end
32
+ end
33
+ end
34
+
35
+ enable Critique:
36
+
37
+ Critique.enable! # e.g., in a Rails initializer
38
+ Critique.logger = $stdout
39
+ # or...
40
+ # Critique.logger = 'path/to/log'
41
+ # Critique.logger = Rails.logger
42
+
43
+ run & view logs:
44
+
45
+ X ExampleClass#method --> ... used: 6.60 GB free: 1.59 GB
46
+ X ExampleClass#method <-- ... used: 6.62 GB free: 1.57 GB delta: +0.32%
47
+
48
+
49
+ ## Contributing
50
+
51
+ 1. Fork it
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+ begin
5
+ Bundler.setup
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts 'run `bundle install` to install missing gems'
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'rake'
13
+ require 'rspec/core/rake_task'
14
+
15
+ RSpec::Core::RakeTask.new(:spec) do |spec|
16
+ spec.rspec_opts = '-Ispec'
17
+ end
18
+
19
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
20
+ spec.rspec_opts = '-Ispec'
21
+ spec.rcov = true
22
+ end
23
+
24
+ task :default => :spec
data/bootstrap.gems ADDED
@@ -0,0 +1,2 @@
1
+ bundler -v 1.1.3
2
+
data/critique.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/critique/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Corey Innis"]
6
+ gem.email = ["corey@coolerator.net"]
7
+ gem.description = %q{critiques your code}
8
+ gem.summary = %q{critiques your code}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "critique"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Critique::VERSION
17
+
18
+ gem.required_ruby_version = ">= 1.9"
19
+ gem.add_development_dependency "bundler"
20
+ gem.add_development_dependency "rake"
21
+ gem.add_development_dependency "rspec"
22
+ gem.add_development_dependency "rr"
23
+ gem.add_development_dependency "simplecov"
24
+ end
@@ -0,0 +1,114 @@
1
+ module Critique
2
+ module Profiling
3
+ def self.profile(base, caller_offset = 0)
4
+ method_name = caller[caller_offset] =~ /`([^']*)'/ && $1
5
+ method_text = label_for(base, method_name)
6
+
7
+ Profiler.enter(method_text)
8
+ result = yield # (Profiler)
9
+ Profiler.leave(method_text)
10
+
11
+ result
12
+ end
13
+
14
+ class Profiler
15
+ class << self
16
+ def info(message)
17
+ Critique.logger.info(['X', padding, message].join)
18
+ end
19
+
20
+ def enter(label)
21
+ padding(:+)
22
+ before = stack.push(system_usage.push(label)).last
23
+
24
+ info(([label, '-->', filler(label)] + pretty(before)).join(' '))
25
+ end
26
+
27
+ def leave(label)
28
+ before = stack.pop
29
+ after = system_usage
30
+
31
+ info(([label, '<--', filler(label)] + pretty(after, before)).join(' '))
32
+
33
+ padding(:-)
34
+ end
35
+
36
+ private
37
+
38
+ def pretty(pair, diff_with = nil)
39
+ used = pair[0]
40
+ free = pair[1]
41
+ result = [
42
+ sprintf("used: %.2f GB", used / conversion_gb),
43
+ sprintf("free: %.2f GB", free / conversion_gb)
44
+ ]
45
+
46
+ if diff_with
47
+ current = used
48
+ previous = diff_with[0]
49
+ bytes = (current - previous).to_f
50
+ percent = (bytes / previous) * 100
51
+
52
+ result.push(sprintf("delta: %+.2f%", percent))
53
+ end
54
+
55
+ result
56
+ end
57
+
58
+ def padding(direction = nil)
59
+ @_padding ||= 0
60
+ @_padding = @_padding.send(direction, 2) if direction
61
+ @_padding = 0 if @_padding < 0
62
+ (' ' * @_padding)
63
+ end
64
+
65
+ def filler(text)
66
+ '.' * (73 - text.length - @_padding) # data starting at column 80
67
+ end
68
+
69
+ def system_usage
70
+ # installed = `sysctl -n hw.memsize`.to_i / conversion_gb
71
+
72
+ stats = `vm_stat`.split("\n")
73
+ used = add_stats(stats, 'wired down', 'active', 'inactive')
74
+ free = add_stats(stats, 'free', 'speculative')
75
+
76
+ [used, free]
77
+ end
78
+
79
+ def add_stats(*args)
80
+ stats = args.shift
81
+ keys = args
82
+ matches = stats.select { |s| keys.any? { |k| s =~ /Pages #{k}:/ } }
83
+ values = matches.map { |m| m.split(/\s+/).last.to_i * conversion_paging }.inject(0, :+)
84
+ end
85
+
86
+ def conversion_paging
87
+ 4096
88
+ end
89
+
90
+ def conversion_gb
91
+ (1024 * 1024 * 1000.0)
92
+ end
93
+
94
+ def stack
95
+ @_stack ||= []
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def self.label_for(base, method_name)
103
+ [label_class(base), label_sep(base), method_name].join
104
+ end
105
+
106
+ def self.label_class(base)
107
+ base.is_a?(Class) ? base.name : base.class.name
108
+ end
109
+
110
+ def self.label_sep(base)
111
+ base.is_a?(Class) ? '.' : '#'
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ module Critique
2
+ VERSION = "0.1"
3
+ end
data/lib/critique.rb ADDED
@@ -0,0 +1,51 @@
1
+ require "critique/version"
2
+ require "logger"
3
+
4
+ module Critique
5
+ autoload :Profiling, 'critique/profiling'
6
+
7
+ class << self
8
+ def included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ def profile(base)
13
+ yield
14
+ end
15
+
16
+ def disable!
17
+ module_eval("def self.profile(base) ; yield ; end")
18
+ end
19
+
20
+ def enable!
21
+ module_eval("def self.profile(base, &block) ; Profiling.profile(base, 2, &block) ; end")
22
+ @_enabled = true
23
+ end
24
+
25
+ def enabled?
26
+ @_enabled || false
27
+ end
28
+
29
+ def logger=(logger)
30
+ if logger.is_a?(IO) || logger.is_a?(String)
31
+ @_logger = Logger.new(logger)
32
+ else
33
+ @_logger = logger
34
+ end
35
+ end
36
+
37
+ def logger
38
+ @_logger ||= Logger.new($stdout)
39
+ end
40
+ end
41
+
42
+ module ClassMethods
43
+ def critique(&block)
44
+ Critique.profile(self, &block)
45
+ end
46
+ end
47
+
48
+ def critique(&block)
49
+ Critique.profile(self, &block)
50
+ end
51
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Critique do
4
+ class ExampleClass
5
+ include Critique
6
+ end
7
+
8
+ before do
9
+ Critique.disable!
10
+ # Critique.logger = '/dev/null'
11
+ end
12
+
13
+ it "is defined" do
14
+ Critique.should be_a(Module)
15
+ end
16
+
17
+ context "when included" do
18
+ it "defines .critique on the base class" do
19
+ ExampleClass.should respond_to(:critique)
20
+ end
21
+
22
+ it "defines #critique on the base class" do
23
+ ExampleClass.new.should respond_to(:critique)
24
+ end
25
+ end
26
+
27
+ describe ".enabled?" do
28
+ context "in the default state" do
29
+ it "returns false" do
30
+ Critique.should_not be_enabled
31
+ end
32
+ end
33
+
34
+ context "when enabled" do
35
+ before do
36
+ Critique.enable!
37
+ end
38
+
39
+ it "returns true" do
40
+ Critique.should be_enabled
41
+ end
42
+ end
43
+ end
44
+
45
+ describe ".critique" do
46
+ let(:code) { 1 + 2 }
47
+
48
+ context "when disabled" do
49
+ it "does not execute profiling" do
50
+ dont_allow(Critique::Profiling).profile
51
+ ExampleClass.critique { code }
52
+ end
53
+
54
+ it "executes the code block" do
55
+ result = ExampleClass.critique { code }
56
+ result.should == 3
57
+ end
58
+ end
59
+
60
+ context "when enabled" do
61
+ before do
62
+ Critique.enable!
63
+ end
64
+
65
+ it "executes profiling" do
66
+ mock(Critique::Profiling).profile(ExampleClass, 2)
67
+ ExampleClass.critique { code }
68
+ end
69
+
70
+ it "executes the code block" do
71
+ ExampleClass.critique { code }.should == 3
72
+ end
73
+ end
74
+
75
+ context "in the default (disabled) state" do
76
+ it "does not run profiling" do
77
+ dont_allow(Critique::Profiling).profile
78
+ ExampleClass.critique { code }
79
+ end
80
+ end
81
+ end
82
+ end
data/spec/process.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'profiling'
2
+
3
+ unless ARGV.size == 2
4
+ puts "usage: ruby process.rb <filename.ext> <config>"
5
+ puts " e.g.,"
6
+ puts " ruby process.rb video.mov all"
7
+ puts " ruby process.rb video.mov 8k"
8
+ puts " ruby process.rb video.mov 10m"
9
+ end
10
+
11
+ filename = ARGV[0]
12
+ config = ARGV[1]
13
+
14
+ unless filename && File.exists?(filename)
15
+ puts "\n\nfile does not exist."
16
+ exit 1
17
+ end
18
+
19
+ class Processor
20
+ extend Profiling
21
+ include Profiling
22
+
23
+ attr_reader :path, :size
24
+
25
+ def initialize(path)
26
+ @path = path
27
+ @size = File.size(path)
28
+ end
29
+
30
+ def read_all
31
+ heading(:all)
32
+
33
+ profile do |p|
34
+ File.read(path) # NOTE: doing nothing with it
35
+ end
36
+ end
37
+
38
+ def read_bytes(num)
39
+ bytes = num.to_i
40
+ bytes = (bytes * 1024) if num =~ /.*k$/i
41
+ bytes = (bytes * 1024 * 1024) if num =~ /.*m$/i
42
+
43
+ heading(:part, bytes)
44
+
45
+ profile do |p|
46
+ offset = 0
47
+ length = bytes
48
+
49
+ while offset < size
50
+ remain = size - offset
51
+ amount = (remain < length) ? remain : length
52
+
53
+ $stdout.print '.' # TODO: move to Profiling
54
+ $stdout.flush
55
+
56
+ File.read(path, amount, offset) # NOTE: doing nothing with it
57
+ offset += amount
58
+ end
59
+
60
+ $stdout.puts
61
+ end
62
+ end
63
+
64
+ def heading(mode, length = nil)
65
+ puts [' ', ('-' * 76)].join
66
+ puts " process.rb... reading #{size} bytes (#{[mode, length].compact.join(' ')})"
67
+ puts [' ', ('-' * 76)].join
68
+ end
69
+
70
+ # def self.cls_method
71
+ # profile do |p|
72
+ # # p.info("method body")
73
+ # "return value"
74
+ # end
75
+ # end
76
+ end
77
+
78
+ if config == 'all'
79
+ Processor.new(filename).read_all
80
+ else
81
+ Processor.new(filename).read_bytes(config)
82
+ end
83
+ # Processor.cls_method
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+
3
+ begin
4
+ Bundler.setup
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ require 'critique'
12
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each do
13
+ |f| require f
14
+ end
15
+
16
+ RSpec.configure do |config|
17
+ config.mock_with :rr
18
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: critique
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Corey Innis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70336553333680 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70336553333680
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70336553333200 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70336553333200
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70336553332760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70336553332760
47
+ - !ruby/object:Gem::Dependency
48
+ name: rr
49
+ requirement: &70336553332340 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70336553332340
58
+ - !ruby/object:Gem::Dependency
59
+ name: simplecov
60
+ requirement: &70336553317820 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70336553317820
69
+ description: critiques your code
70
+ email:
71
+ - corey@coolerator.net
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gemset
77
+ - .gitignore
78
+ - .rspec
79
+ - .rvmrc
80
+ - Gemfile
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bootstrap.gems
85
+ - critique.gemspec
86
+ - lib/critique.rb
87
+ - lib/critique/profiling.rb
88
+ - lib/critique/version.rb
89
+ - spec/critique_spec.rb
90
+ - spec/process.rb
91
+ - spec/spec_helper.rb
92
+ homepage: ''
93
+ licenses: []
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '1.9'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: -4008275762118213474
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.11
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: critiques your code
119
+ test_files:
120
+ - spec/critique_spec.rb
121
+ - spec/process.rb
122
+ - spec/spec_helper.rb