method_info 0.1.0 → 0.1.2
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/README.rdoc +10 -0
- data/VERSION +1 -1
- data/lib/method_info/ancestor_filter.rb +61 -0
- data/lib/method_info/ancestor_method_structure.rb +41 -37
- data/lib/method_info/option_handler.rb +9 -2
- data/spec/method_info/ancestor_filter_spec.rb +71 -0
- data/spec/method_info/option_handler_spec.rb +12 -0
- metadata +5 -2
data/README.rdoc
CHANGED
@@ -17,6 +17,16 @@ Defines a method_info method on every Object which will show the methods that ea
|
|
17
17
|
* :private_methods (default: false)
|
18
18
|
* :singleton_methods (default: true)
|
19
19
|
* :include_name_of_excluded_ancestors (default: true)
|
20
|
+
* :enable_colors (default: false)
|
21
|
+
|
22
|
+
You can set default options which will override the inbuild defaults. Here is an example which
|
23
|
+
will hide the methods defined on all instances of Object and show colour in the output (this
|
24
|
+
requires the ansi-termcolor gem):
|
25
|
+
MethodInfo::OptionHandler.default_options = {
|
26
|
+
:ancestors_to_exclude => [Object],
|
27
|
+
:enable_colors => true
|
28
|
+
}
|
29
|
+
It is suggested that you set these to your liking in your ~/irbrc.
|
20
30
|
|
21
31
|
Examples:
|
22
32
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module MethodInfo
|
2
|
+
|
3
|
+
# Utility class to filter a list of ancestors, taking the class/module hierarchy into account
|
4
|
+
class AncestorFilter
|
5
|
+
# A list of the ancestors that were picked by the filter
|
6
|
+
attr_reader :picked
|
7
|
+
|
8
|
+
# Creates an AncestorFilter and performs a filtering based on the options passed.
|
9
|
+
# ==== Parameters
|
10
|
+
#
|
11
|
+
# * <tt>:include</tt> - An ancestor that is in this list and the original ancestor list will always be included, regardless of the value of :exclude.
|
12
|
+
# * <tt>:exclude</tt> - A list of ancestors that are to be excluded from the original list. If a class is excluded, all modules included under it are excluded as well.
|
13
|
+
def initialize(ancestors, options = {})
|
14
|
+
@ancestors = ancestors
|
15
|
+
filter(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Perform another filter operation on the same list of ancestors. See initialize for supported
|
19
|
+
# options.
|
20
|
+
def filter(options = {})
|
21
|
+
@options = options
|
22
|
+
@exclude = @options[:exclude] || []
|
23
|
+
@include = @options[:include] || []
|
24
|
+
@picked =
|
25
|
+
@ancestors -
|
26
|
+
(@exclude - included_ancestors) -
|
27
|
+
(modules_under_excluded_classes - included_ancestors)
|
28
|
+
end
|
29
|
+
|
30
|
+
# A list of the ancestors that were excluded by the filter
|
31
|
+
def excluded
|
32
|
+
@ancestors - @picked
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def included_ancestors
|
38
|
+
@ancestors & @include
|
39
|
+
end
|
40
|
+
|
41
|
+
def modules_under_excluded_classes
|
42
|
+
group_ancestors_by_class
|
43
|
+
@ancestors.select { |ancestor| ancestor.is_a?(Class) && @exclude.include?(ancestor) }.
|
44
|
+
map { |klass| @class_module_map[klass] }.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
def group_ancestors_by_class
|
48
|
+
@class_module_map = Hash.new
|
49
|
+
@last_class = nil
|
50
|
+
@class_module_map[nil] = []
|
51
|
+
@ancestors.each do |ancestor|
|
52
|
+
if ancestor.is_a?(Class)
|
53
|
+
@class_module_map[ancestor] = []
|
54
|
+
@last_class = ancestor
|
55
|
+
else
|
56
|
+
@class_module_map[@last_class] << ancestor
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'method_info/ancestor_filter'
|
2
|
+
|
1
3
|
module MethodInfo
|
2
4
|
class AncestorMethodStructure
|
3
5
|
# :ancestors_to_show (default: []) (Overrules the hiding of any ancestors as specified
|
@@ -11,61 +13,44 @@ module MethodInfo
|
|
11
13
|
# :private_methods (default: false)
|
12
14
|
# :singleton_methods (default: true)
|
13
15
|
# :include_name_of_excluded_ancestors (default: true)
|
16
|
+
# :colors (default: false) TODO: configure colours
|
14
17
|
def self.build(object, options)
|
15
18
|
methods = []
|
16
19
|
methods += object.methods if options[:public_methods]
|
17
20
|
methods += object.protected_methods if options[:protected_methods]
|
18
21
|
methods += object.private_methods if options[:private_methods]
|
19
22
|
methods -= object.singleton_methods unless options[:singleton_methods]
|
23
|
+
|
20
24
|
ancestor_method_structure = AncestorMethodStructure.new(object, options)
|
21
25
|
|
22
26
|
methods.each do |method|
|
23
|
-
ancestor_method_structure.add_method_to_ancestor(method
|
27
|
+
ancestor_method_structure.add_method_to_ancestor(method)
|
24
28
|
end
|
25
29
|
ancestor_method_structure
|
26
30
|
end
|
27
31
|
|
28
32
|
def initialize(object, options)
|
33
|
+
@object = object
|
29
34
|
@options = options
|
35
|
+
|
30
36
|
@ancestors = []
|
31
|
-
@excluded_ancestors = []
|
32
|
-
@ancestor_methods = {}
|
33
37
|
if options[:singleton_methods]
|
34
38
|
begin
|
35
39
|
@ancestors << (class << object; self; end)
|
36
40
|
rescue TypeError
|
37
41
|
end
|
38
42
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
43
|
+
@ancestors += object.class.ancestors
|
44
|
+
@ancestor_filter = AncestorFilter.new(@ancestors,
|
45
|
+
:include => options[:ancestors_to_show],
|
46
|
+
:exclude => options[:ancestors_to_exclude])
|
47
|
+
|
48
|
+
@ancestor_methods = Hash.new
|
65
49
|
@ancestors.each { |ancestor| @ancestor_methods[ancestor] = [] }
|
66
50
|
end
|
67
51
|
|
68
|
-
def add_method_to_ancestor(method
|
52
|
+
def add_method_to_ancestor(method)
|
53
|
+
ancestor = AncestorMethodStructure.method_owner(@object, method)
|
69
54
|
if @ancestors.include?(ancestor)
|
70
55
|
@ancestor_methods[ancestor] << method
|
71
56
|
end
|
@@ -76,24 +61,43 @@ module MethodInfo
|
|
76
61
|
end
|
77
62
|
|
78
63
|
def to_s
|
64
|
+
if @options[:enable_colors]
|
65
|
+
require 'term/ansicolor'
|
66
|
+
|
67
|
+
class_color = Term::ANSIColor.yellow
|
68
|
+
module_color = Term::ANSIColor.red
|
69
|
+
message_color = Term::ANSIColor.green
|
70
|
+
reset_color = Term::ANSIColor.white
|
71
|
+
else
|
72
|
+
class_color = ""
|
73
|
+
module_color = ""
|
74
|
+
message_color = ""
|
75
|
+
reset_color = ""
|
76
|
+
end
|
77
|
+
|
79
78
|
s = ancestors_with_methods.map do |ancestor|
|
80
|
-
"::: %s :::\n%s\n" % [ancestor.
|
79
|
+
"%s::: %s :::\n%s%s\n" % [ancestor.is_a?(Class) ? class_color : module_color,
|
80
|
+
ancestor.to_s,
|
81
|
+
reset_color,
|
82
|
+
@ancestor_methods[ancestor].sort.join(', ')]
|
81
83
|
end.join('')
|
82
|
-
methodless_ancestors = @ancestors.select { |ancestor| @ancestor_methods[ancestor].empty? }
|
83
84
|
if @options[:include_name_of_methodless_ancestors] && ! methodless_ancestors.empty?
|
84
|
-
s += "Methodless
|
85
|
+
s += "#{message_color}Methodless:#{reset_color} " + methodless_ancestors.join(', ') + "\n"
|
85
86
|
end
|
86
|
-
if @options[:include_name_of_excluded_ancestors] && ! @
|
87
|
-
s += "Excluded
|
87
|
+
if @options[:include_name_of_excluded_ancestors] && ! @ancestor_filter.excluded.empty?
|
88
|
+
s += "#{message_color}Excluded:#{reset_color} " + @ancestor_filter.excluded.join(', ') + "\n"
|
88
89
|
end
|
89
90
|
s
|
90
91
|
end
|
91
92
|
|
92
93
|
private
|
93
94
|
|
95
|
+
def methodless_ancestors
|
96
|
+
@ancestor_filter.picked.select { |ancestor| @ancestor_methods[ancestor].empty? }
|
97
|
+
end
|
98
|
+
|
94
99
|
def ancestors_with_methods
|
95
|
-
@
|
96
|
-
select { |ancestor| ! @ancestor_methods[ancestor].empty? }
|
100
|
+
@ancestor_filter.picked.select { |ancestor| ! @ancestor_methods[ancestor].empty? }
|
97
101
|
end
|
98
102
|
|
99
103
|
# Returns the class or module where method is defined
|
@@ -2,6 +2,8 @@ require 'method_info/ancestor_method_structure'
|
|
2
2
|
|
3
3
|
module MethodInfo
|
4
4
|
class OptionHandler
|
5
|
+
@@custom_default_options = {}
|
6
|
+
|
5
7
|
def self.handle(object, options = {})
|
6
8
|
processed_options = process_options(options)
|
7
9
|
format = processed_options.delete(:format)
|
@@ -27,12 +29,17 @@ module MethodInfo
|
|
27
29
|
:private_methods => false,
|
28
30
|
:protected_methods => false,
|
29
31
|
:singleton_methods => true,
|
30
|
-
:public_methods => true
|
32
|
+
:public_methods => true,
|
33
|
+
:enable_colors => false
|
31
34
|
}
|
32
35
|
end
|
33
36
|
|
37
|
+
def self.default_options=(options = {})
|
38
|
+
@@custom_default_options = options
|
39
|
+
end
|
40
|
+
|
34
41
|
def self.process_options(options = {})
|
35
|
-
defaults = default_profile
|
42
|
+
defaults = default_profile.merge(@@custom_default_options)
|
36
43
|
unknown_options = options.keys - defaults.keys
|
37
44
|
if unknown_options.empty?
|
38
45
|
defaults.merge(options)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'method_info/ancestor_filter'
|
3
|
+
|
4
|
+
module MethodInfo
|
5
|
+
describe AncestorFilter do
|
6
|
+
it "picks all ancestors when no options are passed" do
|
7
|
+
AncestorFilter.new([Object, Kernel]).picked.should == [Object, Kernel]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has no picked ancestors if all are excluded" do
|
11
|
+
AncestorFilter.new([Enumerable, Kernel], :exclude => [Enumerable, Kernel]).picked.should == []
|
12
|
+
end
|
13
|
+
|
14
|
+
it "keeps ancestors that were not excluded" do
|
15
|
+
AncestorFilter.new([Enumerable, Kernel], :exclude => [Kernel]).picked.should == [Enumerable]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "keeps ancestors that are both excluded and included" do
|
19
|
+
AncestorFilter.new([Enumerable, Kernel],
|
20
|
+
:exclude => [Enumerable, Kernel],
|
21
|
+
:include => [Kernel]).picked.should == [Kernel]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does not pick an ancestor that is included but not in the original list" do
|
25
|
+
AncestorFilter.new([Kernel],
|
26
|
+
:include => [String]).picked.should == [Kernel]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "excludes no ancestors when no options are passed" do
|
30
|
+
AncestorFilter.new([Object, Kernel]).excluded.should == []
|
31
|
+
end
|
32
|
+
|
33
|
+
it "excludes all ancestors if all are excluded" do
|
34
|
+
AncestorFilter.new([Enumerable, Kernel], :exclude => [Enumerable, Kernel]).excluded.should == [Enumerable, Kernel]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "excludes ancestors that were excluded and present in the original list" do
|
38
|
+
AncestorFilter.new([Enumerable, Kernel], :exclude => [Kernel]).excluded.should == [Kernel]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "does not exclude ancestors that were excluded but not in the original list" do
|
42
|
+
AncestorFilter.new([Enumerable, Kernel], :exclude => [String, Enumerable]).excluded.should == [Enumerable]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not exclude ancestors that are both excluded and included" do
|
46
|
+
AncestorFilter.new([Enumerable, Kernel],
|
47
|
+
:exclude => [Enumerable, Kernel],
|
48
|
+
:include => [Kernel]).excluded.should == [Enumerable]
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "with class hierarchy" do
|
52
|
+
it "excludes the modules of a class that is excluded" do
|
53
|
+
AncestorFilter.new([Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel],
|
54
|
+
:exclude => [Integer, Object]).picked.should ==
|
55
|
+
[Fixnum, Numeric, Comparable]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "for a class that is both excluded and included it picks the class itself, but not the modules under it" do
|
59
|
+
AncestorFilter.new([Object, Kernel],
|
60
|
+
:exclude => [Object],
|
61
|
+
:include => [Object]).picked.should == [Object]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "maintains the order of a class that is both excluded and included" do
|
65
|
+
AncestorFilter.new([Fixnum, Numeric, Object],
|
66
|
+
:exclude => [Numeric],
|
67
|
+
:include => [Numeric]).picked.should == [Fixnum, Numeric, Object]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -98,5 +98,17 @@ module MethodInfo
|
|
98
98
|
"Unknown value for :format option. Supported values are: nil, :array, :string")
|
99
99
|
end
|
100
100
|
end
|
101
|
+
|
102
|
+
describe "setting default options" do
|
103
|
+
it "should use a value that is set in the default options" do
|
104
|
+
MethodInfo::OptionHandler.default_options = {
|
105
|
+
:ancestors_to_exclude => [Object]
|
106
|
+
}
|
107
|
+
AncestorMethodStructure.
|
108
|
+
should_receive(:build).
|
109
|
+
with(anything, hash_including(:ancestors_to_exclude => [Object]))
|
110
|
+
MethodInfo::OptionHandler.handle(:foo)
|
111
|
+
end
|
112
|
+
end
|
101
113
|
end
|
102
114
|
end
|
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.1.
|
4
|
+
version: 0.1.2
|
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-22 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,9 +52,11 @@ 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_filter.rb
|
55
56
|
- lib/method_info/ancestor_method_structure.rb
|
56
57
|
- lib/method_info/object_method.rb
|
57
58
|
- lib/method_info/option_handler.rb
|
59
|
+
- spec/method_info/ancestor_filter_spec.rb
|
58
60
|
- spec/method_info/ancestor_method_structure_spec.rb
|
59
61
|
- spec/method_info/object_method_spec.rb
|
60
62
|
- spec/method_info/option_handler_spec.rb
|
@@ -90,6 +92,7 @@ signing_key:
|
|
90
92
|
specification_version: 3
|
91
93
|
summary: Get info about an object's methods
|
92
94
|
test_files:
|
95
|
+
- spec/method_info/ancestor_filter_spec.rb
|
93
96
|
- spec/method_info/ancestor_method_structure_spec.rb
|
94
97
|
- spec/method_info/object_method_spec.rb
|
95
98
|
- spec/method_info/option_handler_spec.rb
|