introspection-0.0.2/0000755000175000017500000000000011677350620013776 5ustar boutilboutilintrospection-0.0.2/metadata.yml0000644000175000017500000000552611677350620016311 0ustar boutilboutil--- !ruby/object:Gem::Specification name: introspection version: !ruby/object:Gem::Version hash: 27 prerelease: segments: - 0 - 0 - 2 version: 0.0.2 platform: ruby authors: - James Mead autorequire: bindir: bin cert_chain: [] date: 2011-08-12 00:00:00 +01:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: metaclass prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version hash: 29 segments: - 0 - 0 - 1 version: 0.0.1 type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: instantiator prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version hash: 25 segments: - 0 - 0 - 3 version: 0.0.3 type: :runtime version_requirements: *id002 - !ruby/object:Gem::Dependency name: rake prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id003 description: "" email: - james@floehopper.org executables: [] extensions: [] extra_rdoc_files: [] files: - .gitignore - .travis.yml - Gemfile - README.md - Rakefile - introspection.gemspec - lib/introspection.rb - lib/introspection/assertions.rb - lib/introspection/change_detector.rb - lib/introspection/core_ext.rb - lib/introspection/core_ext/symbol.rb - lib/introspection/method.rb - lib/introspection/receivers.rb - lib/introspection/snapshot.rb - lib/introspection/version.rb - samples/class.rb - samples/instance.rb - samples/module.rb - test/class_snapshot_test.rb - test/instance_snapshot_test.rb - test/module_snapshot_test.rb - test/snapshot_test.rb - test/test_helper.rb has_rdoc: true homepage: http://jamesmead.org licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 23 segments: - 1 - 3 - 6 version: 1.3.6 requirements: [] rubyforge_project: introspection rubygems_version: 1.6.2 signing_key: specification_version: 3 summary: Dynamic inspection of the hierarchy of method definitions on a Ruby object. test_files: - test/class_snapshot_test.rb - test/instance_snapshot_test.rb - test/module_snapshot_test.rb - test/snapshot_test.rb - test/test_helper.rb introspection-0.0.2/test/0000755000175000017500000000000011677350620014755 5ustar boutilboutilintrospection-0.0.2/test/test_helper.rb0000644000175000017500000000146511677350620017626 0ustar boutilboutilrequire "rubygems" require "bundler/setup" require "introspection" require "test/unit" module Introspection module TestHelper def for_all_method_visibilities(&block) [:public, :protected, :private].each do |visibility| block.call(visibility) end end end module LocalAssertions def assert_method_exists(object, owner, method_name, visibility) snapshot = Snapshot.new(object) method = owner.instance_method(method_name) expected_method = Method.new(method, visibility) methods_for_name = snapshot.methods.select { |m| m.name == method_name } assert_equal [expected_method], methods_for_name end end end class Test::Unit::TestCase include Introspection::TestHelper include Introspection::LocalAssertions include Introspection::Assertions endintrospection-0.0.2/test/snapshot_test.rb0000644000175000017500000000325211677350620020202 0ustar boutilboutilrequire "test_helper" require "blankslate" class SnapshotTest < Test::Unit::TestCase include Introspection def test_should_report_methods_added instance = Class.new.new before = Snapshot.new(instance) instance.__metaclass__.send(:define_method, :foo) {} after = Snapshot.new(instance) diff = before.diff(after) assert_equal 1, diff[:added].length assert_equal instance.__metaclass__, diff[:added][0].owner assert_equal :foo, diff[:added][0].name end def test_should_report_methods_removed instance = Class.new.new instance.__metaclass__.send(:define_method, :foo) {} before = Snapshot.new(instance) instance.__metaclass__.send(:remove_method, :foo) after = Snapshot.new(instance) diff = before.diff(after) assert_equal 1, diff[:removed].length assert_equal instance.__metaclass__, diff[:removed][0].owner assert_equal :foo, diff[:removed][0].name end def test_should_indicate_snapshot_has_changed_when_method_is_added instance = Class.new.new assert_snapshot_changed(instance) do instance.__metaclass__.send(:define_method, :foo) {} end end def test_should_indicate_snapshot_has_changed_when_method_is_removed instance = Class.new.new instance.__metaclass__.send(:define_method, :foo) {} assert_snapshot_changed(instance) do instance.__metaclass__.send(:remove_method, :foo) end end def test_should_indicate_snapshot_has_not_changed_when_method_no_methods_are_added_or_removed instance = Class.new.new assert_snapshot_unchanged(instance) {} end def test_should_cope_with_blankslate_object assert_nothing_raised { Snapshot.new(BlankSlate.new) } end endintrospection-0.0.2/test/module_snapshot_test.rb0000644000175000017500000000227611677350620021554 0ustar boutilboutilrequire "test_helper" class ModuleSnapshotTest < Test::Unit::TestCase def test_detect_module_method_on_module for_all_method_visibilities do |visibility| mod = Module.new mod.__metaclass__.send(:define_method, :foo) {} mod.__metaclass__.send(visibility, :foo) assert_method_exists(mod, mod.__metaclass__, :foo, visibility) end end def test_detect_method_on_module_included_as_module_method_on_module for_all_method_visibilities do |visibility| supermod = Module.new supermod.send(:define_method, :foo) {} supermod.send(visibility, :foo) mod = Module.new do extend supermod end assert_method_exists(mod, supermod, :foo, visibility) end end def test_detect_method_on_module_included_into_module_included_as_module_method_on_module for_all_method_visibilities do |visibility| superdupermod = Module.new superdupermod.send(:define_method, :foo) {} superdupermod.send(visibility, :foo) supermod = Module.new do include superdupermod end mod = Module.new do extend supermod end assert_method_exists(mod, superdupermod, :foo, visibility) end end endintrospection-0.0.2/test/instance_snapshot_test.rb0000644000175000017500000000741411677350620022072 0ustar boutilboutilrequire "test_helper" class InstanceSnapshotTest < Test::Unit::TestCase def test_detect_instance_method_on_singleton_class for_all_method_visibilities do |visibility| instance = Class.new.new instance.__metaclass__.send(:define_method, :foo) {} instance.__metaclass__.send(visibility, :foo) assert_method_exists(instance, instance.__metaclass__, :foo, visibility) end end def test_detect_instance_method_on_module_included_into_singleton_class for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) instance = Class.new.new instance.extend(mod) assert_method_exists(instance, mod, :foo, visibility) end end def test_detect_instance_method_on_module_included_module_included_into_singleton_class for_all_method_visibilities do |visibility| supermod = Module.new supermod.send(:define_method, :foo) {} supermod.send(visibility, :foo) mod = Module.new mod.send(:include, supermod) instance = Class.new.new instance.extend(mod) assert_method_exists(instance, supermod, :foo, visibility) end end def test_detect_instance_method_on_class for_all_method_visibilities do |visibility| klass = Class.new klass.send(:define_method, :foo) {} klass.send(visibility, :foo) instance = klass.new assert_method_exists(instance, klass, :foo, visibility) end end def test_detect_instance_method_on_superclass for_all_method_visibilities do |visibility| superklass = Class.new superklass.send(:define_method, :foo) {} superklass.send(visibility, :foo) instance = Class.new(superklass).new assert_method_exists(instance, superklass, :foo, visibility) end end def test_detect_instance_method_on_superclass_of_superclass for_all_method_visibilities do |visibility| superduperklass = Class.new superduperklass.send(:define_method, :foo) {} superduperklass.send(visibility, :foo) instance = Class.new(Class.new(superduperklass)).new assert_method_exists(instance, superduperklass, :foo, visibility) end end def test_detect_instance_method_on_module_included_into_class for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) instance = Class.new do include mod end.new assert_method_exists(instance, mod, :foo, visibility) end end def test_detect_instance_method_on_module_included_into_superclass for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) superklass = Class.new do include mod end instance = Class.new(superklass).new assert_method_exists(instance, mod, :foo, visibility) end end def test_detect_instance_method_on_module_included_into_superclass_of_superclass for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) superduperklass = Class.new do include mod end instance = Class.new(Class.new(superduperklass)).new assert_method_exists(instance, mod, :foo, visibility) end end def test_detect_instance_method_on_module_included_into_module_included_into_class for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) supermod = Module.new do include mod end klass = Class.new do include supermod end instance = klass.new assert_method_exists(instance, mod, :foo, visibility) end end endintrospection-0.0.2/test/class_snapshot_test.rb0000644000175000017500000000527311677350620021374 0ustar boutilboutilrequire "test_helper" class ClassSnapshotTest < Test::Unit::TestCase def test_detect_class_method_on_class for_all_method_visibilities do |visibility| klass = Class.new klass.__metaclass__.send(:define_method, :foo) {} klass.__metaclass__.send(visibility, :foo) assert_method_exists(klass, klass.__metaclass__, :foo, visibility) end end def test_detect_class_method_on_superclass for_all_method_visibilities do |visibility| superklass = Class.new superklass.__metaclass__.send(:define_method, :foo) {} superklass.__metaclass__.send(visibility, :foo) klass = Class.new(superklass) assert_method_exists(klass, superklass.__metaclass__, :foo, visibility) end end def test_detect_class_method_on_superclass_of_superclass for_all_method_visibilities do |visibility| superduperklass = Class.new superduperklass.__metaclass__.send(:define_method, :foo) {} superduperklass.__metaclass__.send(visibility, :foo) klass = Class.new(Class.new(superduperklass)) assert_method_exists(klass, superduperklass.__metaclass__, :foo, visibility) end end def test_detect_method_on_module_included_as_class_method_into_class for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) klass = Class.new do extend mod end assert_method_exists(klass, mod, :foo, visibility) end end def test_detect_method_on_module_included_as_class_method_into_superclass for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) superklass = Class.new do extend mod end klass = Class.new(superklass) assert_method_exists(klass, mod, :foo, visibility) end end def test_detect_method_on_module_included_as_class_method_into_superclass_of_superclass for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) superduperklass = Class.new do extend mod end klass = Class.new(Class.new(superduperklass)) assert_method_exists(klass, mod, :foo, visibility) end end def test_detect_method_on_module_included_into_module_included_as_class_method_into_class for_all_method_visibilities do |visibility| mod = Module.new mod.send(:define_method, :foo) {} mod.send(visibility, :foo) supermod = Module.new do include mod end klass = Class.new do extend supermod end assert_method_exists(klass, mod, :foo, visibility) end end endintrospection-0.0.2/samples/0000755000175000017500000000000011677350620015442 5ustar boutilboutilintrospection-0.0.2/samples/module.rb0000644000175000017500000000050111677350620017250 0ustar boutilboutilmodule Grandaddy def foo puts "Grandaddy#foo" super rescue NoMethodError end end module Daddy def foo puts "Daddy#foo" super rescue NoMethodError end include Grandaddy end module Sonny def self.foo puts "Sonny.foo" super rescue NoMethodError end extend Daddy end Sonny.foointrospection-0.0.2/samples/instance.rb0000644000175000017500000000246611677350620017603 0ustar boutilboutilmodule Kernel def foo puts "Kernel#foo" super rescue NoMethodError end end class Object def foo puts "Object#foo" super rescue NoMethodError end end module GreatUncle def foo puts "GreatUncle#foo" super rescue NoMethodError end end module GreatAunt def foo puts "GreatAunt#foo" super rescue NoMethodError end end class Grandaddy def foo puts "Grandaddy#foo" super rescue NoMethodError end include GreatUncle, GreatAunt end module Uncle def foo puts "Uncle#foo" super rescue NoMethodError end end module Aunt def foo puts "Aunt#foo" super rescue NoMethodError end end class Daddy < Grandaddy def foo puts "Daddy#foo" super rescue NoMethodError end include Uncle, Aunt end module Brother def foo puts "Brother#foo" super rescue NoMethodError end end module HalfSister def foo puts "HalfSister#foo" super rescue NoMethodError end end module Sister def foo puts "Sister#foo" super rescue NoMethodError end include HalfSister end class Sonny < Daddy def foo puts "Sonny#foo" super rescue NoMethodError end include Brother, Sister end sonny = Sonny.new class << sonny def foo puts "sonny#foo" super rescue NoMethodError end end sonny.foointrospection-0.0.2/samples/class.rb0000644000175000017500000000272311677350620017100 0ustar boutilboutilmodule Kernel def foo puts "Kernel#foo" super rescue NoMethodError end end class Object def foo puts "Object#foo" super rescue NoMethodError end def self.foo puts "Object.foo" super rescue NoMethodError end end class Module def foo puts "Module#foo" super rescue NoMethodError end end class Class def foo puts "Class#foo" super rescue NoMethodError end end module GreatUncle def foo puts "GreatUncle#foo" super rescue NoMethodError end end module GreatAunt def foo puts "GreatAunt#foo" super rescue NoMethodError end end class Grandaddy def self.foo puts "Grandaddy.foo" super rescue NoMethodError end extend GreatUncle, GreatAunt end module Uncle def foo puts "Uncle#foo" super rescue NoMethodError end end module Aunt def foo puts "Aunt#foo" super rescue NoMethodError end end class Daddy < Grandaddy def self.foo puts "Daddy.foo" super rescue NoMethodError end extend Uncle, Aunt end module Brother def foo puts "Brother#foo" super rescue NoMethodError end end module HalfSister def foo puts "HalfSister#foo" super rescue NoMethodError end end module Sister def foo puts "Sister#foo" super rescue NoMethodError end include HalfSister end class Sonny < Daddy def self.foo puts "Sonny.foo" super rescue NoMethodError end extend Brother, Sister end Sonny.foo introspection-0.0.2/lib/0000755000175000017500000000000011677350620014544 5ustar boutilboutilintrospection-0.0.2/lib/introspection/0000755000175000017500000000000011677350620017444 5ustar boutilboutilintrospection-0.0.2/lib/introspection/version.rb0000644000175000017500000000005511677350620021456 0ustar boutilboutilmodule Introspection VERSION = "0.0.2" end introspection-0.0.2/lib/introspection/snapshot.rb0000644000175000017500000000151711677350620021634 0ustar boutilboutilrequire "introspection/receivers" require "metaclass" module Introspection class Snapshot attr_reader :methods def initialize(object) @methods = (object.receivers rescue []).map do |receiver| [:public, :protected, :private].map do |visibility| query_method = "#{visibility}_instance_methods" receiver.send(query_method, false).map do |method| unbound_method = receiver.instance_method(method) if unbound_method.owner.equal?(receiver) Method.new(unbound_method, visibility) end end.compact end end.flatten end def diff(other) { :added => other.methods - methods, :removed => methods - other.methods } end def changed?(other) diff(other).values.flatten.any? end end endintrospection-0.0.2/lib/introspection/receivers.rb0000644000175000017500000000116411677350620021762 0ustar boutilboutilrequire "metaclass" module Introspection module Receivers class NullMetaclass def ancestors Array.new end end class NullReceiver def __metaclass__ NullMetaclass.new end def receivers Array.new end end def superklass respond_to?(:superclass) ? superclass : NullReceiver.new end def local_receivers [__metaclass__] + __metaclass__.ancestors - superklass.__metaclass__.ancestors end def receivers local_receivers + superklass.receivers end end end class Object include Introspection::Receivers endintrospection-0.0.2/lib/introspection/method.rb0000644000175000017500000000116711677350620021256 0ustar boutilboutilrequire "forwardable" module Introspection class Method extend Forwardable def_delegators :@method, :owner attr_reader :visibility def initialize(method, visibility = :public) @method, @visibility = method, visibility end def ==(other) (owner == other.owner) && (name == other.name) && (visibility == other.visibility) end def eql?(other) (self.class === other) && (self == other) end def hash [owner, name, visibility].hash end def name @method.name.to_sym end def inspect "#{owner}##{name} (#{visibility})" end end endintrospection-0.0.2/lib/introspection/core_ext/0000755000175000017500000000000011677350620021254 5ustar boutilboutilintrospection-0.0.2/lib/introspection/core_ext/symbol.rb0000644000175000017500000000035711677350620023113 0ustar boutilboutilclass Symbol # Standard in ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Symbol.html] def to_proc Proc.new { |*args| args.shift.__send__(self, *args) } end unless :to_proc.respond_to?(:to_proc) end introspection-0.0.2/lib/introspection/core_ext.rb0000644000175000017500000000004711677350620021602 0ustar boutilboutilrequire "introspection/core_ext/symbol"introspection-0.0.2/lib/introspection/change_detector.rb0000644000175000017500000000312311677350620023106 0ustar boutilboutilrequire "introspection" require "instantiator" before_class_snapshots = {} before_instance_snapshots = {} ObjectSpace.each_object do |object| if Class === object next if Instantiator.unsupported_class?(object) object.instantiate end end ObjectSpace.each_object do |object| if Class === object next if Instantiator.unsupported_class?(object) before_class_snapshots[object] = Introspection::Snapshot.new(object) before_instance_snapshots[object] = Introspection::Snapshot.new(object.instantiate) end end class String def foo end def self.bar end end after_class_snapshots = {} after_instance_snapshots = {} ObjectSpace.each_object do |object| if Class === object next if Instantiator.unsupported_class?(object) after_class_snapshots[object] = Introspection::Snapshot.new(object) after_instance_snapshots[object] = Introspection::Snapshot.new(object.instantiate) end end before_instance_snapshots.each_key do |key| if after_instance_snapshots[key] if before_instance_snapshots[key].changed?(after_instance_snapshots[key]) p [key, :instance_method, before_instance_snapshots[key].diff(after_instance_snapshots[key])] end end end before_class_snapshots.each_key do |key| if after_class_snapshots[key] if before_class_snapshots[key].changed?(after_class_snapshots[key]) p [key, :class_method, before_class_snapshots[key].diff(after_class_snapshots[key])] end end end # => [String, :instance_method, {:removed=>[], :added=>[String#foo (public)]}] # => [String, :class_method, {:removed=>[], :added=>[##bar (public)]}] introspection-0.0.2/lib/introspection/assertions.rb0000644000175000017500000000073011677350620022163 0ustar boutilboutilmodule Introspection module Assertions def assert_snapshot_changed(object) before = Snapshot.new(object) yield after = Snapshot.new(object) assert before.changed?(after), "Snapshot has not changed." end def assert_snapshot_unchanged(object) before = Snapshot.new(object) yield after = Snapshot.new(object) assert !before.changed?(after), "Snapshot has changed: #{before.diff(after).inspect}" end end endintrospection-0.0.2/lib/introspection.rb0000644000175000017500000000024511677350620017772 0ustar boutilboutilrequire "introspection/core_ext" require "introspection/receivers" require "introspection/method" require "introspection/snapshot" require "introspection/assertions"introspection-0.0.2/introspection.gemspec0000644000175000017500000000173611677350620020252 0ustar boutilboutil# -*- encoding: utf-8 -*- lib = File.expand_path('../lib/', __FILE__) $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) require "introspection/version" Gem::Specification.new do |s| s.name = "introspection" s.version = Introspection::VERSION s.platform = Gem::Platform::RUBY s.authors = ["James Mead"] s.email = ["james@floehopper.org"] s.homepage = "http://jamesmead.org" s.summary = %q{Dynamic inspection of the hierarchy of method definitions on a Ruby object.} s.description = %q{} s.required_rubygems_version = ">= 1.3.6" s.rubyforge_project = "introspection" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.add_dependency "metaclass", "~> 0.0.1" s.add_dependency "instantiator", "~> 0.0.3" s.add_development_dependency "rake" end introspection-0.0.2/Rakefile0000644000175000017500000000032711677350620015445 0ustar boutilboutilrequire "bundler" Bundler::GemHelper.install_tasks require "rake/testtask" Rake::TestTask.new do |t| t.libs << "test" t.test_files = FileList["test/**/*_test.rb"] t.verbose = true end task :default => :test introspection-0.0.2/README.md0000644000175000017500000000045111677350620015255 0ustar boutilboutilDynamic inspection of the hierarchy of method definitions on a Ruby object. Motivations :- * Extract code that may be generally useful from Mocha. * Learn more about the Ruby's Object, Class & Module and the method receiver chain. * Detect undesirable changes to classes made by other libraries.introspection-0.0.2/Gemfile0000644000175000017500000000003211677350620015264 0ustar boutilboutilsource :rubygems gemspec introspection-0.0.2/.travis.yml0000644000175000017500000000003011677350620016100 0ustar boutilboutilrvm: - 1.8.7 - 1.9.2introspection-0.0.2/.gitignore0000644000175000017500000000002011677350620015756 0ustar boutilboutilGemfile.lock pkg