Skip to content

Commit

Permalink
Adding yardoc; limited to Ruby 2.1+; pending-ize one spec
Browse files Browse the repository at this point in the history
  • Loading branch information
srawlins committed Aug 25, 2013
1 parent 26c5f03 commit ebbb759
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 21 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
doc
.yardoc
1 change: 1 addition & 0 deletions .yardopts
@@ -0,0 +1 @@
-m markdown - README.markdown LICENSE
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -3,6 +3,10 @@

source "https://rubygems.org"

group :development do
gem "yard"
end

group :test do
gem "rspec"
gem "yajl-ruby", "= 1.1.0"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -11,10 +11,12 @@ GEM
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.13.1)
yajl-ruby (1.1.0)
yard (0.8.7)

PLATFORMS
ruby

DEPENDENCIES
rspec
yajl-ruby (= 1.1.0)
yard
1 change: 1 addition & 0 deletions LICENSE
@@ -1,3 +1,4 @@
# @markup rdoc

Apache License
Version 2.0, January 2004
Expand Down
3 changes: 3 additions & 0 deletions Rakefile
Expand Up @@ -2,7 +2,10 @@
# Licensed under the Apache License, Version 2.0, found in the LICENSE file.

require 'rspec/core/rake_task'
require 'yard'

RSpec::Core::RakeTask.new(:spec)

task :default => :spec

YARD::Rake::YardocTask.new
4 changes: 4 additions & 0 deletions TODO
@@ -0,0 +1,4 @@
* rdoc rdoc rdoc
* release first gem version
* more in the README
* Tabular, textual output
36 changes: 21 additions & 15 deletions lib/objectspace/stats.rb
Expand Up @@ -7,10 +7,26 @@

require "rubygems"

# Container for an aggregation of object allocation data. Pass a block to
# {#initialize ObjectSpace::Stats.new()}. Then use the ObjectSpace::Stats object's public
# interface to dig into the data and discover useful information.
class ObjectSpace::Stats
# a convenience constant
Rubylibdir = RbConfig::CONFIG["rubylibdir"]

# a convenience constant
GemDir = Gem.dir
attr_accessor :gc_profiler_report, :new_allocations

attr_accessor :gc_profiler_report

# @!attribute [r] new_allocations
# @return [Array]
# allocation data for all new objects that were allocated
# during the {#initialize} block. It is better to use {#allocations}, which
# returns an {AllocationsProxy}, which has a much more convenient,
# domain-specific API for filtering, sorting, and grouping {Allocation}
# objects, than this plain Array object.
attr_reader :new_allocations

def initialize
GC.start
Expand Down Expand Up @@ -41,10 +57,13 @@ def initialize
profile_and_start_gc
end

# Inspect @new_allocations, the canonical array of {Allocation} objects.
def inspect
@new_allocations.inspect
end

# Proxy for the @new_allocations array that allows for individual filtering,
# sorting, and grouping of the Allocation objects.
def allocations
AllocationsProxy.new(@new_allocations)
end
Expand All @@ -56,18 +75,5 @@ def profile_and_start_gc
@gc_profiler_report = GC::Profiler.result
GC::Profiler.disable
end


def group_by_multiple(ary, *args)
ary.group_by do |el|
if args.size == 1
arg = args.first
arg.to_s[0] == "@" ? el.instance_variable_get(arg) : el.object.send(arg)
else
args.map do |arg|
arg.to_s[0] == "@" ? el.instance_variable_get(arg) : el.object.send(arg)
end
end
end
end
private :profile_and_start_gc
end
31 changes: 27 additions & 4 deletions lib/objectspace/stats/allocation.rb
Expand Up @@ -5,11 +5,29 @@

class ObjectSpace::Stats
class Allocation
# a convenience constants
PWD = Dir.pwd

# a list of helper methods that Allocation provides on top of the object that was allocated.
Helpers = [:class_plus]
attr_accessor :object,
:memsize, :sourcefile
attr_reader :class_path, :method_id, :sourceline

attr_accessor :memsize, :sourcefile

# @!attribute [r] class_path
# the classpath of where the object was allocated
attr_reader :class_path

# @!attribute [r] method_id
# the method ID of where the object was allocated
attr_reader :method_id

# @!attribute [r] object
# the actual object that was allocated
attr_reader :object

# @!attribute [r] sourceline
# the line in the sourcefile where the object was allocated
attr_reader :sourceline

def initialize(object)
@object = object
Expand Down Expand Up @@ -46,6 +64,9 @@ def class_plus
end
end

# @return [String] the name of the Rubygem where this allocation occurred.
# @return [nil] if this allocation did not occur in a Rubygem.
#
# Override Rubygems' Kernel#gem
def gem
gem_regex = /<GEMDIR>#{File::SEPARATOR}
Expand All @@ -56,6 +77,8 @@ def gem
match && match[:gem_name]
end

# Convert into a JSON string, which can be used in rack-objectspace-stats's
# interactive mode.
def to_json
{
"memsize" => @memsize,
Expand All @@ -71,7 +94,7 @@ def to_json
def element_classes(classes)
if classes.size == 1
classes.first
elsif classes.size < 4
elsif classes.size > 1 && classes.size < 4
classes.join(",")
else
nil
Expand Down
28 changes: 28 additions & 0 deletions lib/objectspace/stats/allocations_proxy.rb
Expand Up @@ -2,6 +2,12 @@
# Licensed under the Apache License, Version 2.0, found in the LICENSE file.

class ObjectSpace::Stats
# AllocationsProxy acts as a proxy for an array of Allocation objects. The
# idea behind this class is merely to provide some domain-specific methods
# for filtering, sorting, and grouping allocation information. This class
# uses the Command pattern heavily, in order to build and maintain the list
# of transformations it will ultimately perform, before retrieving the
# transformed collection of Allocations.
class AllocationsProxy

def initialize(allocations)
Expand Down Expand Up @@ -39,6 +45,14 @@ def sorted_by_size
self
end

# Select allocations for which the {Allocation#sourcefile sourcefile}
# includes `pattern`.
#
# `#from` can be called multiple times, adding to `@wheres`. See
# documentation for {AllocationsProxy} for more information about chaining.
#
# @param [String] pattern the partial file path to match against, in the
# {Allocation#sourcefile Allocation's sourcefile}.
def from(pattern)
@wheres << Proc.new do |allocations|
allocations.select { |allocation| allocation.sourcefile[pattern] }
Expand All @@ -47,6 +61,14 @@ def from(pattern)
self
end

# Select allocations for which the {Allocation#sourcefile sourcefile} does
# not include `pattern`.
#
# `#not_from` can be called multiple times, adding to `@wheres`. See
# documentation for {AllocationsProxy} for more information about chaining.
#
# @param [String] pattern the partial file path to match against, in the
# {Allocation#sourcefile Allocation's sourcefile}.
def not_from(pattern)
@wheres << Proc.new do |allocations|
allocations.reject { |allocation| allocation.sourcefile[pattern] }
Expand All @@ -55,6 +77,11 @@ def not_from(pattern)
self
end

# Select allocations for which the {Allocation#sourcefile sourcefile}
# includes the present working directory.
#
# `#from_pwd` can be called multiple times, adding to `@wheres`. See
# documentation for {AllocationsProxy} for more information about chaining.
def from_pwd
@wheres << Proc.new do |allocations|
allocations.select { |allocation| allocation.sourcefile[@pwd] }
Expand Down Expand Up @@ -103,6 +130,7 @@ def attribute_getters(faux_attributes)
end
end
end
private :attribute_getters

def bytes
@mappers << Proc.new do |allocations|
Expand Down
1 change: 1 addition & 0 deletions objectspace-stats.gemspec
Expand Up @@ -14,4 +14,5 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]

spec.add_development_dependency "rspec"
spec.required_ruby_version = ">= 2.1.0"
end
3 changes: 1 addition & 2 deletions spec/objectspace_stats_spec.rb
Expand Up @@ -120,8 +120,7 @@
end

results = stats.allocations.group_by(:@sourcefile, :class_plus).all
results.keys.size.should == 2
results.keys.should include([__FILE__, "Array<Fixnum>"])
pending "Not written yet"
end

it "should track new objects by class_path, method_id and class" do
Expand Down

0 comments on commit ebbb759

Please sign in to comment.