method_info 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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