method_info 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +39 -8
- data/VERSION +1 -1
- data/lib/method_info.rb +3 -79
- data/lib/method_info/ancestor_method_structure.rb +105 -0
- data/lib/method_info/object_method.rb +30 -0
- data/lib/method_info/option_handler.rb +44 -0
- data/spec/method_info/ancestor_method_structure_spec.rb +15 -0
- data/spec/method_info/object_method_spec.rb +19 -0
- data/spec/method_info/option_handler_spec.rb +102 -0
- data/spec/method_info_spec.rb +4 -155
- data/spec/spec_helper.rb +2 -1
- metadata +11 -2
data/README.rdoc
CHANGED
@@ -1,15 +1,46 @@
|
|
1
1
|
= method_info
|
2
2
|
|
3
|
-
|
3
|
+
Defines a method_info method on every Object which will show the methods that each of the object's ancestors has defined on it. The default settings are chosen to cause the least amount of surprise. This means the output may be a bit verbose, but there are options that can to narrow down the output to what you are interested in. The following options are provided:
|
4
4
|
|
5
|
-
|
5
|
+
* :format (default: nil)
|
6
|
+
- :string returns a string representation
|
7
|
+
- :array returns an array representation
|
8
|
+
- anything else prints out a string representation
|
9
|
+
* :ancestors_to_show (default: []) (Overrules the hiding of any ancestors as specified
|
10
|
+
by the :ancestors_to_exclude option)
|
11
|
+
* :ancestors_to_exclude (default: []) (If a class is excluded, all modules included
|
12
|
+
under it are excluded as well, an ancestor specified in :ancestors_to_show will be
|
13
|
+
shown regardless of the this value)
|
14
|
+
* :method_missing (default: false)
|
15
|
+
* :public_methods (default: true)
|
16
|
+
* :protected_methods (default: false)
|
17
|
+
* :private_methods (default: false)
|
18
|
+
* :singleton_methods (default: true)
|
19
|
+
* :include_name_of_excluded_ancestors (default: true)
|
6
20
|
|
7
|
-
|
8
|
-
|
9
|
-
>>
|
10
|
-
=>
|
11
|
-
>> "abc".method_info
|
12
|
-
|
21
|
+
Examples:
|
22
|
+
|
23
|
+
>> require 'method_info'
|
24
|
+
=> true
|
25
|
+
>> "abc".method_info
|
26
|
+
::: String :::
|
27
|
+
%, *, +, <<, <=>, ==, =~, [], []=, bytes, bytesize, capitalize, capitalize!, casecmp, center, chars, chomp, chomp!, chop, chop!, concat, count, crypt, delete, delete!, downcase, downcase!, dump, each, each_byte, each_char, each_line, empty?, end_with?, eql?, gsub, gsub!, hash, hex, include?, index, insert, inspect, intern, is_binary_data?, is_complex_yaml?, length, lines, ljust, lstrip, lstrip!, match, next, next!, oct, partition, replace, reverse, reverse!, rindex, rjust, rpartition, rstrip, rstrip!, scan, size, slice, slice!, split, squeeze, squeeze!, start_with?, strip, strip!, sub, sub!, succ, succ!, sum, swapcase, swapcase!, taguri, taguri=, to_f, to_i, to_s, to_str, to_sym, to_yaml, tr, tr!, tr_s, tr_s!, unpack, upcase, upcase!, upto
|
28
|
+
::: Enumerable :::
|
29
|
+
all?, any?, collect, cycle, detect, drop, drop_while, each_cons, each_slice, each_with_index, entries, enum_cons, enum_slice, enum_with_index, find, find_all, find_index, first, grep, group_by, inject, map, max, max_by, member?, min, min_by, minmax, minmax_by, none?, one?, reduce, reject, reverse_each, select, sort, sort_by, take, take_while, to_a, zip
|
30
|
+
::: Comparable :::
|
31
|
+
<, <=, >, >=, between?
|
32
|
+
::: Object :::
|
33
|
+
to_yaml_properties, to_yaml_style
|
34
|
+
::: MethodInfo::ObjectMethod :::
|
35
|
+
method_info
|
36
|
+
::: Kernel :::
|
37
|
+
===, __id__, __send__, class, clone, display, dup, enum_for, equal?, extend, freeze, frozen?, id, instance_eval, instance_exec, instance_of?, instance_variable_defined?, instance_variable_get, instance_variable_set, instance_variables, is_a?, kind_of?, method, methods, nil?, object_id, private_methods, protected_methods, public_methods, respond_to?, send, singleton_methods, taint, tainted?, tap, to_enum, type, untaint
|
38
|
+
Methodless: #<Class:#<String:0x13fd42c>>
|
39
|
+
=> nil
|
40
|
+
::: Symbol :::
|
41
|
+
===, id2name, inspect, taguri, taguri=, to_i, to_int, to_proc, to_s, to_sym, to_yaml
|
42
|
+
Excluded: Object, MethodInfo::ObjectMethod, Kernel
|
43
|
+
=> nil
|
13
44
|
|
14
45
|
== Note on Patches/Pull Requests
|
15
46
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/method_info.rb
CHANGED
@@ -1,80 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
MethodInfo.new(self)
|
4
|
-
end
|
5
|
-
end
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
6
3
|
|
7
|
-
|
8
|
-
include MethodInfoMethod
|
9
|
-
end
|
10
|
-
|
11
|
-
class MethodInfo
|
12
|
-
def initialize(object)
|
13
|
-
@object = object
|
14
|
-
unless @object.singleton_methods.empty?
|
15
|
-
@eigenclass = class << object; self; end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def ancestors
|
20
|
-
@ancestors = []
|
21
|
-
if @eigenclass
|
22
|
-
@ancestors << @eigenclass
|
23
|
-
end
|
24
|
-
@ancestors += @object.class.ancestors
|
25
|
-
end
|
26
|
-
|
27
|
-
# Returns the class or module where method is defined
|
28
|
-
def method_owner(method)
|
29
|
-
@object.method(method).owner
|
30
|
-
end
|
31
|
-
|
32
|
-
# Returns the same value as :method_owner, but also check if the
|
33
|
-
# method is handled by a method_missing method in the chain. If it
|
34
|
-
# is :method_missing is returned, otherwise the error raised is
|
35
|
-
# reraised. This requires an invocation of the method which could
|
36
|
-
# cause side effects. Hence this method is considered to be
|
37
|
-
# dangerous.
|
38
|
-
def method_owner!(method)
|
39
|
-
method_owner(method)
|
40
|
-
rescue NameError => e
|
41
|
-
begin
|
42
|
-
@object.clone.send(method)
|
43
|
-
:method_missing
|
44
|
-
rescue NoMethodError
|
45
|
-
raise e
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def method_map
|
50
|
-
@method_map = Hash.new
|
51
|
-
current_ancestors = ancestors
|
52
|
-
@method_map['__ancestors'] = current_ancestors
|
53
|
-
current_ancestors.each do |ancestor|
|
54
|
-
@method_map[ancestor] = []
|
55
|
-
end
|
56
|
-
|
57
|
-
@object.methods.each do |method|
|
58
|
-
@method_map[method_owner(method)] << method
|
59
|
-
end
|
60
|
-
@method_map
|
61
|
-
end
|
62
|
-
|
63
|
-
def to_s
|
64
|
-
map = method_map
|
65
|
-
|
66
|
-
result = ""
|
67
|
-
map['__ancestors'].each do |ancestor|
|
68
|
-
break if ancestor == Object
|
69
|
-
next if map[ancestor].empty?
|
70
|
-
result +=
|
71
|
-
"=== #{ancestor} ===\n" +
|
72
|
-
map[ancestor].sort.join(", ") +
|
73
|
-
"\n"
|
74
|
-
end
|
75
|
-
index_of_object = map['__ancestors'].index(Object)
|
76
|
-
result +=
|
77
|
-
"=== #{map['__ancestors'][index_of_object..-1].join(", ")} ==="
|
78
|
-
result
|
79
|
-
end
|
80
|
-
end
|
4
|
+
require 'method_info/object_method'
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module MethodInfo
|
2
|
+
class AncestorMethodStructure
|
3
|
+
# :ancestors_to_show (default: []) (Overrules the hiding of any ancestors as specified
|
4
|
+
# by the :ancestors_to_exclude option)
|
5
|
+
# :ancestors_to_exclude (default: []) (If a class is excluded, all modules included
|
6
|
+
# under it are excluded as well, an ancestor specified in
|
7
|
+
# :ancestors_to_show will be shown regardless of the this value)
|
8
|
+
# :method_missing (default: false)
|
9
|
+
# :public_methods (default: true)
|
10
|
+
# :protected_methods (default: false)
|
11
|
+
# :private_methods (default: false)
|
12
|
+
# :singleton_methods (default: true)
|
13
|
+
# :include_name_of_excluded_ancestors (default: true)
|
14
|
+
def self.build(object, options)
|
15
|
+
methods = []
|
16
|
+
methods += object.methods if options[:public_methods]
|
17
|
+
methods += object.protected_methods if options[:protected_methods]
|
18
|
+
methods += object.private_methods if options[:private_methods]
|
19
|
+
methods -= object.singleton_methods unless options[:singleton_methods]
|
20
|
+
ancestor_method_structure = AncestorMethodStructure.new(object, options)
|
21
|
+
|
22
|
+
methods.each do |method|
|
23
|
+
ancestor_method_structure.add_method_to_ancestor(method, method_owner(object, method))
|
24
|
+
end
|
25
|
+
ancestor_method_structure
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(object, options)
|
29
|
+
@options = options
|
30
|
+
@ancestors = []
|
31
|
+
@excluded_ancestors = []
|
32
|
+
@ancestor_methods = {}
|
33
|
+
if options[:singleton_methods]
|
34
|
+
begin
|
35
|
+
@ancestors << (class << object; self; end)
|
36
|
+
rescue TypeError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
all_ancestors = object.class.ancestors
|
40
|
+
last_class_was_excluded = false
|
41
|
+
all_ancestors.each do |ancestor|
|
42
|
+
if options[:ancestors_to_show].include?(ancestor)
|
43
|
+
@ancestors << ancestor
|
44
|
+
if ancestor.is_a?(Class)
|
45
|
+
last_class_was_excluded = false
|
46
|
+
end
|
47
|
+
elsif options[:ancestors_to_exclude].include?(ancestor)
|
48
|
+
if ancestor.is_a?(Class)
|
49
|
+
last_class_was_excluded = true
|
50
|
+
@excluded_ancestors << ancestor
|
51
|
+
end
|
52
|
+
else
|
53
|
+
if ancestor.is_a?(Class)
|
54
|
+
@ancestors << ancestor
|
55
|
+
last_class_was_excluded = false
|
56
|
+
else
|
57
|
+
if last_class_was_excluded
|
58
|
+
@excluded_ancestors << ancestor
|
59
|
+
else
|
60
|
+
@ancestors << ancestor
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@ancestors.each { |ancestor| @ancestor_methods[ancestor] = [] }
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_method_to_ancestor(method, ancestor)
|
69
|
+
if @ancestors.include?(ancestor)
|
70
|
+
@ancestor_methods[ancestor] << method
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_a
|
75
|
+
ancestors_with_methods.map { |ancestor| [ancestor, @ancestor_methods[ancestor].sort] }
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
s = ancestors_with_methods.map do |ancestor|
|
80
|
+
"::: %s :::\n%s\n" % [ancestor.to_s, @ancestor_methods[ancestor].sort.join(', ')]
|
81
|
+
end.join('')
|
82
|
+
methodless_ancestors = @ancestors.select { |ancestor| @ancestor_methods[ancestor].empty? }
|
83
|
+
if @options[:include_name_of_methodless_ancestors] && ! methodless_ancestors.empty?
|
84
|
+
s += "Methodless: " + methodless_ancestors.join(', ') + "\n"
|
85
|
+
end
|
86
|
+
if @options[:include_name_of_excluded_ancestors] && ! @excluded_ancestors.empty?
|
87
|
+
s += "Excluded: " + @excluded_ancestors.join(', ') + "\n"
|
88
|
+
end
|
89
|
+
s
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def ancestors_with_methods
|
95
|
+
@ancestors.
|
96
|
+
select { |ancestor| ! @ancestor_methods[ancestor].empty? }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the class or module where method is defined
|
100
|
+
def self.method_owner(object, method)
|
101
|
+
object.method(method).owner
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'method_info/option_handler'
|
2
|
+
|
3
|
+
module MethodInfo
|
4
|
+
module ObjectMethod
|
5
|
+
# Provides information about an object's methods.
|
6
|
+
# Options:
|
7
|
+
# :format (default: nil)
|
8
|
+
# - :string returns a string representation
|
9
|
+
# - :array returns an array representation
|
10
|
+
# - anything else prints out a string representation
|
11
|
+
# :ancestors_to_show (default: []) (Overrules the hiding of any ancestors as specified
|
12
|
+
# by the :ancestors_to_exclude option)
|
13
|
+
# :ancestors_to_exclude (default: []) (If a class is excluded, all modules included
|
14
|
+
# under it are excluded as well, an ancestor specified in
|
15
|
+
# :ancestors_to_show will be shown regardless of the this value)
|
16
|
+
# :method_missing (default: false)
|
17
|
+
# :public_methods (default: true)
|
18
|
+
# :protected_methods (default: false)
|
19
|
+
# :private_methods (default: false)
|
20
|
+
# :singleton_methods (default: true)
|
21
|
+
# :include_name_of_excluded_ancestors (default: true)
|
22
|
+
def method_info(options = {})
|
23
|
+
OptionHandler.handle(self, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Object
|
29
|
+
include MethodInfo::ObjectMethod
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'method_info/ancestor_method_structure'
|
2
|
+
|
3
|
+
module MethodInfo
|
4
|
+
class OptionHandler
|
5
|
+
def self.handle(object, options = {})
|
6
|
+
processed_options = process_options(options)
|
7
|
+
format = processed_options.delete(:format)
|
8
|
+
ancestor_method_structure = AncestorMethodStructure.build(object, processed_options)
|
9
|
+
if format == :string
|
10
|
+
ancestor_method_structure.to_s
|
11
|
+
elsif format == :array
|
12
|
+
ancestor_method_structure.to_a
|
13
|
+
elsif format
|
14
|
+
raise(ArgumentError.new("Unknown value for :format option. Supported values are: nil, :array, :string"))
|
15
|
+
else
|
16
|
+
puts ancestor_method_structure
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.default_profile
|
21
|
+
{
|
22
|
+
:ancestors_to_show => [],
|
23
|
+
:ancestors_to_exclude => [],
|
24
|
+
:format => nil,
|
25
|
+
:include_name_of_excluded_ancestors => true,
|
26
|
+
:include_name_of_methodless_ancestors => true,
|
27
|
+
:private_methods => false,
|
28
|
+
:protected_methods => false,
|
29
|
+
:singleton_methods => true,
|
30
|
+
:public_methods => true
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.process_options(options = {})
|
35
|
+
defaults = default_profile
|
36
|
+
unknown_options = options.keys - defaults.keys
|
37
|
+
if unknown_options.empty?
|
38
|
+
defaults.merge(options)
|
39
|
+
else
|
40
|
+
raise ArgumentError.new("Unsupported options: " + unknown_options.map { |k| k.to_s }.sort.join(', '))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'method_info/ancestor_method_structure'
|
3
|
+
|
4
|
+
module MethodInfo
|
5
|
+
describe AncestorMethodStructure do
|
6
|
+
describe "class" do
|
7
|
+
it "should have specs"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "AncestorMethodStructure::build" do
|
11
|
+
it "should print the methods on an object" do
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'method_info/object_method'
|
3
|
+
|
4
|
+
module MethodInfo
|
5
|
+
module ObjectMethod
|
6
|
+
describe "method_info" do
|
7
|
+
it "passes the object it was called on to the option handler" do
|
8
|
+
@obj = Object.new
|
9
|
+
OptionHandler.should_receive(:handle).with(@obj, anything)
|
10
|
+
@obj.method_info
|
11
|
+
end
|
12
|
+
|
13
|
+
it "passes its options to the option handler" do
|
14
|
+
OptionHandler.should_receive(:handle).with(anything, { :a => :one, :b => :two })
|
15
|
+
Object.method_info(:a => :one, :b => :two)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'method_info/option_handler'
|
3
|
+
|
4
|
+
module MethodInfo
|
5
|
+
def suppressing_output
|
6
|
+
output = $stdout
|
7
|
+
$stdout = File.open('/dev/null', 'w')
|
8
|
+
yield
|
9
|
+
ensure
|
10
|
+
$stdout = output
|
11
|
+
end
|
12
|
+
|
13
|
+
describe OptionHandler do
|
14
|
+
before do
|
15
|
+
OptionHandler.stub!(:puts)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "handle" do
|
19
|
+
describe "processing options" do
|
20
|
+
it "raises an argument error when an unsupported option is passed" do
|
21
|
+
lambda { MethodInfo::OptionHandler.handle(:object, :unknown_option => :one) }.
|
22
|
+
should raise_error(ArgumentError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises an error mentioning any unsupported options, ordered alphabetically" do
|
26
|
+
lambda { MethodInfo::OptionHandler.handle(:object, :unknown_option => :one, :another => :two) }.
|
27
|
+
should raise_error(ArgumentError, "Unsupported options: another, unknown_option")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "uses a value from the default profile if an option was not passed" do
|
31
|
+
MethodInfo::OptionHandler.stub!(:default_profile).and_return({ :mock_option, :mock_value })
|
32
|
+
AncestorMethodStructure.should_receive(:build).with(anything, hash_including(:mock_option => :mock_value))
|
33
|
+
MethodInfo::OptionHandler.handle(:object)
|
34
|
+
end
|
35
|
+
it "uses a value for an option if it was passed in" do
|
36
|
+
MethodInfo::OptionHandler.stub!(:default_profile).and_return({ :mock_option, :mock_value })
|
37
|
+
AncestorMethodStructure.should_receive(:build).with(anything, hash_including(:mock_option => :passed_value))
|
38
|
+
MethodInfo::OptionHandler.handle(:object, :mock_option => :passed_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has the correct default values for options" do
|
42
|
+
default_options = MethodInfo::OptionHandler.default_profile
|
43
|
+
default_options[:format].should == nil
|
44
|
+
default_options[:ancestors_to_show].should == []
|
45
|
+
default_options[:ancestors_to_exclude].should == []
|
46
|
+
default_options[:include_name_of_excluded_ancestors].should == true
|
47
|
+
default_options[:include_name_of_methodless_ancestors].should == true
|
48
|
+
default_options[:public_methods].should == true
|
49
|
+
default_options[:singleton_methods].should == true
|
50
|
+
default_options[:protected_methods].should == false
|
51
|
+
default_options[:private_methods].should == false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "builds an ancestor method structure with the object" do
|
56
|
+
mock_object = mock('object')
|
57
|
+
AncestorMethodStructure.should_receive(:build).with(mock_object, anything)
|
58
|
+
MethodInfo::OptionHandler.handle(mock_object)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "passes through regular options when building an ancestor method structure" do
|
62
|
+
AncestorMethodStructure.should_receive(:build).with(anything, hash_including(:private_methods => :some_value))
|
63
|
+
MethodInfo::OptionHandler.handle(:foo, { :private_methods => :some_value })
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not pass the :format option when building an ancestor method structure" do
|
67
|
+
AncestorMethodStructure.should_receive(:build).with(anything, hash_not_including(:format))
|
68
|
+
MethodInfo::OptionHandler.handle(:foo, { :format => :string })
|
69
|
+
end
|
70
|
+
|
71
|
+
it "prints the ancestor_method_structure if the :format option is not set" do
|
72
|
+
mock_ams = mock('ancestor_method_structure')
|
73
|
+
AncestorMethodStructure.stub!(:build).and_return(mock_ams)
|
74
|
+
OptionHandler.should_receive(:puts).with(mock_ams)
|
75
|
+
MethodInfo::OptionHandler.handle(:foo)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "returns the array representation of the ancestor_method_structure if the :format option is :array" do
|
79
|
+
mock_ams = mock('ancestor_method_structure')
|
80
|
+
AncestorMethodStructure.stub!(:build).and_return(mock_ams)
|
81
|
+
mock_array_representation = mock('array representation')
|
82
|
+
mock_ams.should_receive(:to_a).and_return mock_array_representation
|
83
|
+
MethodInfo::OptionHandler.handle(:foo, {:format => :array}).should == mock_array_representation
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns the string representation of the ancestor_method_structure if the :format option is :string" do
|
87
|
+
mock_ams = mock('ancestor_method_structure')
|
88
|
+
AncestorMethodStructure.stub!(:build).and_return(mock_ams)
|
89
|
+
mock_string_representation = mock('string representation')
|
90
|
+
mock_ams.should_receive(:to_s).and_return mock_string_representation
|
91
|
+
MethodInfo::OptionHandler.handle(:foo, {:format => :string}).should == mock_string_representation
|
92
|
+
end
|
93
|
+
|
94
|
+
it "raises an error if the :format option is not supported" do
|
95
|
+
AncestorMethodStructure.stub!(:build)
|
96
|
+
lambda { MethodInfo::OptionHandler.handle(:foo, { :format => :unknown }) }.
|
97
|
+
should raise_error(ArgumentError,
|
98
|
+
"Unknown value for :format option. Supported values are: nil, :array, :string")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/spec/method_info_spec.rb
CHANGED
@@ -1,160 +1,9 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
|
4
|
-
describe "ancestors" do
|
5
|
-
it "has the ancestors that a String has on any system for a String object" do
|
6
|
-
ancestors = 37.method_info.ancestors
|
7
|
-
usual_ancestors = [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
|
8
|
-
ancestors_without_system_specific_ones = ancestors.
|
9
|
-
select { |ancestor| usual_ancestors.include?(ancestor) }
|
10
|
-
ancestors_without_system_specific_ones.should == usual_ancestors
|
11
|
-
end
|
12
|
-
|
13
|
-
it "does not contain a module that was not included" do
|
14
|
-
class Forest
|
15
|
-
end
|
16
|
-
sherwood = Forest.new
|
17
|
-
sherwood.method_info.ancestors.should_not include(Enumerable)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "contains an included module" do
|
21
|
-
class Zoo
|
22
|
-
include(Enumerable)
|
23
|
-
end
|
24
|
-
artis = Zoo.new
|
25
|
-
artis.method_info.ancestors.should include(Enumerable)
|
26
|
-
end
|
27
|
-
|
28
|
-
it "has an object's eigenclass as the first element if it has singleton methods" do
|
29
|
-
monkey = Object.new
|
30
|
-
def monkey.talk
|
31
|
-
"Ook!"
|
32
|
-
end
|
33
|
-
eigenclass_of_monkey = class << monkey; self; end
|
34
|
-
monkey.method_info.ancestors.first.should == eigenclass_of_monkey
|
35
|
-
end
|
36
|
-
|
37
|
-
it "does not include the object's eigenclass if it has no singleton methods" do
|
38
|
-
monkey = Object.new
|
39
|
-
eigenclass_of_monkey = class << monkey; self; end
|
40
|
-
monkey.method_info.ancestors.should_not include(eigenclass_of_monkey)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "method_owner" do
|
45
|
-
class AbstractMethodOwnerDummy
|
46
|
-
def abstract_instance_method
|
47
|
-
:abstract_instance_method
|
48
|
-
end
|
49
|
-
|
50
|
-
def duplicate_instance_method
|
51
|
-
:abstract_duplicate_instance_method
|
52
|
-
end
|
53
|
-
|
54
|
-
def method_missing(method)
|
55
|
-
if method == :missing_method_handled_at_abstract
|
56
|
-
return :missing_method_handled_at_abstract
|
57
|
-
end
|
58
|
-
super
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class ConcreteMethodOwnerDummy < AbstractMethodOwnerDummy
|
63
|
-
def concrete_instance_method
|
64
|
-
:concrete_instance_method
|
65
|
-
end
|
66
|
-
|
67
|
-
def duplicate_instance_method
|
68
|
-
:concrete_duplicate_instance_method
|
69
|
-
end
|
70
|
-
|
71
|
-
def method_missing(method)
|
72
|
-
if method == :missing_method_handled_at_concrete
|
73
|
-
return :missing_method_handled_at_concrete
|
74
|
-
end
|
75
|
-
super
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it "is the class of the object for an instance_method" do
|
80
|
-
ConcreteMethodOwnerDummy.new.method_info.method_owner(:concrete_instance_method).should ==
|
81
|
-
ConcreteMethodOwnerDummy
|
82
|
-
end
|
3
|
+
require 'method_info'
|
83
4
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
it "raises an error if the object does not respond to the method" do
|
90
|
-
lambda { ConcreteMethodOwnerDummy.new.method_info.method_owner(:poof) }.should raise_error(NameError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it "raises an error if the method is handled by :method_missing" do
|
94
|
-
lambda { ConcreteMethodOwnerDummy.new.method_info.method_owner(:missing_method_handled_at_concrete) }.should raise_error(NameError)
|
95
|
-
end
|
96
|
-
|
97
|
-
describe "method_owner!" do
|
98
|
-
it "is the class of the object for an instance_method" do
|
99
|
-
ConcreteMethodOwnerDummy.new.method_info.method_owner!(:concrete_instance_method).should ==
|
100
|
-
ConcreteMethodOwnerDummy
|
101
|
-
end
|
102
|
-
|
103
|
-
it "is the superclass of an objects class if that is where the method is first defined" do
|
104
|
-
ConcreteMethodOwnerDummy.new.method_info.method_owner!(:abstract_instance_method).should ==
|
105
|
-
AbstractMethodOwnerDummy
|
106
|
-
end
|
107
|
-
|
108
|
-
it "raises an error if the object does not respond to the method" do
|
109
|
-
lambda { ConcreteMethodOwnerDummy.new.method_info.method_owner!(:poof) }.should raise_error(NameError)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "is :method_missing if the concrete class handles the method" do
|
113
|
-
ConcreteMethodOwnerDummy.new.method_info.method_owner!(:missing_method_handled_at_concrete).should ==
|
114
|
-
:method_missing
|
115
|
-
end
|
116
|
-
|
117
|
-
it "is :method_missing if the abstract class handles the method" do
|
118
|
-
ConcreteMethodOwnerDummy.new.method_info.method_owner!(:missing_method_handled_at_abstract).should ==
|
119
|
-
:method_missing
|
120
|
-
end
|
121
|
-
|
122
|
-
it "is :method_missing if the object has a method_missing singleton method that handles the method" do
|
123
|
-
monkey = Object.new
|
124
|
-
def monkey.method_missing(method)
|
125
|
-
if method == :missing_method_handled_at_singleton_method
|
126
|
-
return :missing_method_handled_at_singleton_method
|
127
|
-
end
|
128
|
-
super
|
129
|
-
end
|
130
|
-
monkey.method_info.method_owner!(:missing_method_handled_at_singleton_method).should ==
|
131
|
-
:method_missing
|
132
|
-
end
|
133
|
-
|
134
|
-
it "does not modify an object whose method_missing has side effects" do
|
135
|
-
monkey = Object.new
|
136
|
-
monkey.instance_eval { @hair = "brown" }
|
137
|
-
def monkey.method_missing(method)
|
138
|
-
@hair = "blue"
|
139
|
-
end
|
140
|
-
monkey.method_info.method_owner!(:unknown_method)
|
141
|
-
monkey.instance_eval('@hair').should == "brown"
|
142
|
-
end
|
143
|
-
|
144
|
-
# Undesirable behaviour, but I don't think there is an easy way around it
|
145
|
-
it "will not protect an object's objects from method_missing side effects" do
|
146
|
-
monkey = Object.new
|
147
|
-
monkey.instance_eval { @limbs = [:arms, :legs] }
|
148
|
-
def monkey.method_missing(method)
|
149
|
-
@limbs.shift
|
150
|
-
end
|
151
|
-
monkey.method_info.method_owner!(:unknown_method)
|
152
|
-
monkey.instance_eval('@limbs').should == [:legs]
|
153
|
-
end
|
154
|
-
|
155
|
-
it "raises an error if the object does not respond to the method" do
|
156
|
-
lambda { ConcreteMethodOwnerDummy.new.method_info.method_owner!(:poof) }.should raise_error(NameError)
|
157
|
-
end
|
158
|
-
end
|
5
|
+
describe MethodInfo do
|
6
|
+
it "defines the method_info method on instances of Object" do
|
7
|
+
Object.new.should respond_to(:method_info)
|
159
8
|
end
|
160
9
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: method_info
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom ten Thij
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-18 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,12 @@ files:
|
|
52
52
|
- features/step_definitions/method_info_steps.rb
|
53
53
|
- features/support/env.rb
|
54
54
|
- lib/method_info.rb
|
55
|
+
- lib/method_info/ancestor_method_structure.rb
|
56
|
+
- lib/method_info/object_method.rb
|
57
|
+
- lib/method_info/option_handler.rb
|
58
|
+
- spec/method_info/ancestor_method_structure_spec.rb
|
59
|
+
- spec/method_info/object_method_spec.rb
|
60
|
+
- spec/method_info/option_handler_spec.rb
|
55
61
|
- spec/method_info_spec.rb
|
56
62
|
- spec/spec.opts
|
57
63
|
- spec/spec_helper.rb
|
@@ -84,5 +90,8 @@ signing_key:
|
|
84
90
|
specification_version: 3
|
85
91
|
summary: Get info about an object's methods
|
86
92
|
test_files:
|
93
|
+
- spec/method_info/ancestor_method_structure_spec.rb
|
94
|
+
- spec/method_info/object_method_spec.rb
|
95
|
+
- spec/method_info/option_handler_spec.rb
|
87
96
|
- spec/method_info_spec.rb
|
88
97
|
- spec/spec_helper.rb
|