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 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.0
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, method_owner(object, 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
- 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
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, ancestor)
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.to_s, @ancestor_methods[ancestor].sort.join(', ')]
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: " + methodless_ancestors.join(', ') + "\n"
85
+ s += "#{message_color}Methodless:#{reset_color} " + methodless_ancestors.join(', ') + "\n"
85
86
  end
86
- if @options[:include_name_of_excluded_ancestors] && ! @excluded_ancestors.empty?
87
- s += "Excluded: " + @excluded_ancestors.join(', ') + "\n"
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
- @ancestors.
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.0
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-18 00:00:00 +00:00
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