introspection-0.0.4/0000755000004100000410000000000013321134523014440 5ustar www-datawww-dataintrospection-0.0.4/.travis.yml0000644000004100000410000000031013321134523016543 0ustar www-datawww-datalanguage: ruby before_install: - gem install bundler - rvm list known rvm: - 1.8 - 1.9 - 2.0 - 2.1 - 2.2 - 2.3 - jruby-9.1.5.0 - rbx-3.9 matrix: allow_failures: - rvm: rbx-3.9 introspection-0.0.4/test/0000755000004100000410000000000013321134523015417 5ustar www-datawww-dataintrospection-0.0.4/test/module_snapshot_test.rb0000644000004100000410000000227113321134523022211 0ustar www-datawww-datarequire "test_helper" class ModuleSnapshotTest < Minitest::Test 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 end introspection-0.0.4/test/snapshot_test.rb0000644000004100000410000000325313321134523020645 0ustar www-datawww-datarequire "test_helper" require "blankslate" class SnapshotTest < Minitest::Test 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 # Should not raise anything Snapshot.new(BlankSlate.new) end end introspection-0.0.4/test/class_snapshot_test.rb0000644000004100000410000000526613321134523022040 0ustar www-datawww-datarequire "test_helper" class ClassSnapshotTest < Minitest::Test 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 end introspection-0.0.4/test/instance_snapshot_test.rb0000644000004100000410000000740713321134523022536 0ustar www-datawww-datarequire "test_helper" class InstanceSnapshotTest < Minitest::Test 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 end introspection-0.0.4/test/test_helper.rb0000644000004100000410000000146713321134523020272 0ustar www-datawww-datarequire "rubygems" require "bundler/setup" require "introspection" require "minitest/autorun" 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 Minitest::Test include Introspection::TestHelper include Introspection::LocalAssertions include Introspection::Assertions end introspection-0.0.4/README.md0000644000004100000410000000104413321134523015716 0ustar www-datawww-data## Introspection [![Build Status](https://travis-ci.org/floehopper/introspection.svg?branch=master)](https://travis-ci.org/floehopper/introspection) [![Gem Version](https://badge.fury.io/rb/introspection.png)](http://badge.fury.io/rb/introspection) Dynamic 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.4/.gitignore0000644000004100000410000000002013321134523016420 0ustar www-datawww-dataGemfile.lock pkgintrospection-0.0.4/COPYING.txt0000644000004100000410000000205713321134523016315 0ustar www-datawww-data== Licence (MIT) Copyright (c) 2011 James Mead Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.introspection-0.0.4/Rakefile0000644000004100000410000000032713321134523016107 0ustar www-datawww-datarequire "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.4/lib/0000755000004100000410000000000013321134523015206 5ustar www-datawww-dataintrospection-0.0.4/lib/introspection.rb0000644000004100000410000000024513321134523020434 0ustar www-datawww-datarequire "introspection/core_ext" require "introspection/receivers" require "introspection/method" require "introspection/snapshot" require "introspection/assertions"introspection-0.0.4/lib/introspection/0000755000004100000410000000000013321134523020106 5ustar www-datawww-dataintrospection-0.0.4/lib/introspection/core_ext/0000755000004100000410000000000013321134523021716 5ustar www-datawww-dataintrospection-0.0.4/lib/introspection/core_ext/symbol.rb0000644000004100000410000000035713321134523023555 0ustar www-datawww-dataclass 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.4/lib/introspection/version.rb0000644000004100000410000000005513321134523022120 0ustar www-datawww-datamodule Introspection VERSION = "0.0.4" end introspection-0.0.4/lib/introspection/snapshot.rb0000644000004100000410000000151713321134523022276 0ustar www-datawww-datarequire "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.4/lib/introspection/method.rb0000644000004100000410000000116713321134523021720 0ustar www-datawww-datarequire "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.4/lib/introspection/core_ext.rb0000644000004100000410000000004713321134523022244 0ustar www-datawww-datarequire "introspection/core_ext/symbol"introspection-0.0.4/lib/introspection/receivers.rb0000644000004100000410000000140413321134523022421 0ustar www-datawww-datarequire "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 receivers = [] receivers << __metaclass__ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.1.0') receivers += __metaclass__.ancestors receivers -= superklass.__metaclass__.ancestors receivers end def receivers local_receivers + superklass.receivers end end end class Object include Introspection::Receivers endintrospection-0.0.4/lib/introspection/assertions.rb0000644000004100000410000000073013321134523022625 0ustar www-datawww-datamodule 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.4/Gemfile0000644000004100000410000000004713321134523015734 0ustar www-datawww-datasource 'https://rubygems.org' gemspec introspection-0.0.4/samples/0000755000004100000410000000000013321134523016104 5ustar www-datawww-dataintrospection-0.0.4/samples/class.rb0000644000004100000410000000272313321134523017542 0ustar www-datawww-datamodule 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.4/samples/instance.rb0000644000004100000410000000246613321134523020245 0ustar www-datawww-datamodule 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.4/samples/module.rb0000644000004100000410000000050113321134523017712 0ustar www-datawww-datamodule 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.4/introspection.gemspec0000644000004100000410000000220213321134523020701 0ustar www-datawww-data# -*- 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.license = "MIT" 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_development_dependency "minitest", "~> 5.0" if RUBY_VERSION < '1.9.3' s.add_development_dependency "rake", "~> 10.0" else s.add_development_dependency "rake" end s.add_development_dependency "blankslate" end