methodfinder 2.1.1 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a80f6617e6197ecbcbb4415915977ef45089cc70
4
- data.tar.gz: 151f90cc0a3046fbaf12ecee7ff40ee32238ac6e
2
+ SHA256:
3
+ metadata.gz: cc5f10019d05bf88ecadc9ef8f753c8fb24bae5b964e15823eb6235c50ca96f6
4
+ data.tar.gz: bd20ac80dfa26324d3041ad3d0dfca0b2cc15a632f7fff37a285c1fa3663698d
5
5
  SHA512:
6
- metadata.gz: 22d5e8adba4381b0e60cd84fc037ada1163cf26aa7d9e296e5582574cdcfc6cdd95ae85284171b6478d9719ab71d760d64509e42277919b05ea5f9fff5c8d59d
7
- data.tar.gz: 9c755fd27ada3784b0a3fb1c662d6d7104b2ae2e963332bd1b73b1fc36c257b5e41100a1942c99425c06057fb3a041648d113364ababd96db75316bee57ab07a
6
+ metadata.gz: d1c21e4002be10b889ea23d70d16dde3db53e73bf42926f71882fa740a51f0391339eb8e43d42c44c7e692fd8faddb339bb3f07ad2100ef397bd0f4399887775
7
+ data.tar.gz: 599bf95909d58aeb601dc45bd8d3a2ba316a041c550fe2f20aacabe544189d27e35bafe93c10daebcaf37e385cb7e8f561d61ac06f12e699535128f39a452cf1
@@ -0,0 +1,186 @@
1
+ # MethodFinder
2
+
3
+ [![Build Status](https://travis-ci.org/citizen428/methodfinder.svg)](https://travis-ci.org/citizen428/methodfinder)
4
+ [![Gem Version](https://img.shields.io/gem/v/methodfinder.svg)](https://rubygems.org/gems/methodfinder)
5
+
6
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
7
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
8
+
9
+ - [Requirements](#requirements)
10
+ - [Usage](#usage)
11
+ - [MethodFinder.find](#methodfinderfind)
12
+ - [Object#find_method](#objectfind_method)
13
+ - [Blacklists](#blacklists)
14
+ - [MethodFinder.find_classes_and_modules](#methodfinderfind_classes_and_modules)
15
+ - [MethodFinder.find_in_class_or_module](#methodfinderfind_in_class_or_module)
16
+ - [Troubleshooting](#troubleshooting)
17
+ - [Warning](#warning)
18
+ - [Thanks](#thanks)
19
+ - [License](#license)
20
+
21
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
22
+
23
+ This project was originally inspired by Smalltalk's Method Finder, but
24
+ additional features were added over time.
25
+
26
+ ## Requirements
27
+
28
+ Ruby 1.9.3+ (also works with Rubinius in 1.9 mode). Versions of `MethodFinder`
29
+ up to 1.2.5 will also work with Ruby 1.8.7. Note: CI only runs newer versions
30
+ of Ruby.
31
+
32
+ ## Usage
33
+
34
+ ### MethodFinder.find
35
+
36
+ Provided with a receiver, the desired result and possibly some arguments,
37
+ `MethodFinder.find` will list all methods that produce the given result when
38
+ called on the receiver with the provided arguments.
39
+
40
+ ```ruby
41
+ MethodFinder.find(10, 1, 3)
42
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
43
+ MethodFinder.find("abc", "ABC")
44
+ #=> ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
45
+ MethodFinder.find(10, 100, 2)
46
+ #=> ["Fixnum#**"]
47
+ MethodFinder.find(['a', 'b', 'c'], ['A', 'B', 'C']) { |x| x.upcase }
48
+ #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", "Enumerable#flat_map", "Array#map", "Array#map!"]
49
+ ```
50
+
51
+ ### Object#find_method
52
+
53
+ This gem also adds `Object#find_method`, which besides offering an alternative
54
+ interface to pretty much the same functionality as `MethodFinder.find`, also
55
+ allows you to test for state other than the return value of the method.
56
+
57
+ ```ruby
58
+ %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
59
+ #=> ["Array#delete_at", "Array#slice!"]
60
+ 10.find_method { |n| n.unknown(3) == 1 }
61
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
62
+ ```
63
+
64
+ Inside `find_method`'s block, the receiver is available as block argument and
65
+ the special method `unknown` is used as a placeholder for the desired method.
66
+
67
+ You can also call `find_method` without passing a block. This is the same as
68
+ calling `MethodFinder.find`.
69
+
70
+ ```ruby
71
+ 10.find_method(1, 3)
72
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
73
+ ```
74
+
75
+ #### Blacklists
76
+
77
+ You can exclude methods from being tried by editing the hashes
78
+ `MethodFinder::INSTANCE_METHOD_BLACKLIST` and
79
+ `MethodFinder::CLASS_METHOD_BLACKLIST`. Both use the class/module as key and
80
+ an array of method names as values (note that class, module and method names
81
+ have to be symbols).
82
+
83
+ For example, to blacklist the instance method `shutdown` of `Object`, you
84
+ would do
85
+
86
+ ```ruby
87
+ MethodFinder::INSTANCE_METHOD_BLACKLIST[:Object] << :shutdown
88
+ ```
89
+
90
+ This might come in handy when using `MethodFinder` together with other gems as
91
+ such as `interactive_editor`.
92
+
93
+ ### MethodFinder.find_classes_and_modules
94
+
95
+ A simple method to return all currently defined modules and classes.
96
+
97
+ ```ruby
98
+ MethodFinder.find_classes_and_modules
99
+ #=> [ArgumentError, Array, BasicObject, Bignum ... ZeroDivisionError]
100
+ ```
101
+
102
+ ### MethodFinder.find_in_class_or_module
103
+
104
+ Searches for a given name within a class. The first parameter can either be a
105
+ class object, a symbol or a string whereas the optional second parameter can
106
+ be a string or a regular expression:
107
+
108
+ ```ruby
109
+ MethodFinder.find_in_class_or_module('Array', 'shuff')
110
+ #=> [:shuffle, :shuffle!]
111
+ MethodFinder.find_in_class_or_module(Float, /^to/)
112
+ #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
113
+ ```
114
+
115
+ If the second parameter is omitted, all methods of the class or module will be
116
+ returned.
117
+
118
+ ```ruby
119
+ MethodFinder.find_in_class_or_module(Math)
120
+ #=> [:acos, :acosh, :asin ... :tanh]
121
+ ```
122
+
123
+ ## Troubleshooting
124
+
125
+ If the `METHOD_FINDER_DEBUG` environment variable is set, the name of each
126
+ candidate method is printed to `STDERR` before it is invoked. This can be useful
127
+ to identify (and blacklist) misbehaving methods.
128
+
129
+ It can be set on the command line e.g.:
130
+
131
+ ```
132
+ $ METHOD_FINDER_DEBUG=1 irb
133
+ ```
134
+
135
+ Or you can toggle it inside IRB/Pry:
136
+
137
+ ```ruby
138
+ >> MethodFinder.toggle_debug!
139
+ ```
140
+
141
+ ## Warning
142
+
143
+ Common sense not included!
144
+
145
+ While I never had any problems with this, it's still better to be safe than
146
+ sorry, so use this with caution and maybe not on production data.
147
+
148
+ I initially wrote this for the students of the core Ruby course on
149
+ [RubyLearning](http://rubylearning.org), so Rails is not of interest to me (not
150
+ saying it doesn't work there, just that I test in plain IRB/Pry and not with
151
+ the Rails console.
152
+
153
+ ## Thanks
154
+
155
+ * [Matthew Lucas](https://github.com/lucas-matt) for [first packaging this as a gem](https://github.com/citizen428/methodfinder/pull/1).
156
+ * [Ryan Bates](https://github.com/ryanb) for [suggesting](https://github.com/citizen428/methodfinder/issues/closed#issue/3)
157
+ what eventually became `Object#find_method`.
158
+ * [Jan Lelis](https://github.com/janlelis) for [implementing blacklists](https://github.com/citizen428/methodfinder/issues/closed#issue/4).
159
+ * [Brian Morearty](https://github.com/BMorearty) for pointing out an [incompatibility with Ruby 1.8.7](https://github.com/citizen428/methodfinder/pull/5)
160
+ and adding the [blockless version](https://github.com/citizen428/methodfinder/pull/6)
161
+ of `Object#find_method`.
162
+ * [Stefan Kanev](https://github.com/skanev) for [adding Pry support](https://github.com/citizen428/methodfinder/pull/7).
163
+ * [chocolateboy](https://github.com/chocolateboy) for [compatibility fixes and updates](https://github.com/citizen428/methodfinder/pull/8),
164
+ [the initial debug implementation](https://github.com/citizen428/methodfinder/pull/9), and [many smaller fixes](https://github.com/citizen428/methodfinder/pulls?utf8=✓&q=is%3Apr+author%3Achocolateboy).
165
+
166
+ ## License
167
+
168
+ Copyright (c) 2011-2018 Michael Kohl
169
+
170
+ Permission is hereby granted, free of charge, to any person obtaining a copy
171
+ of this software and associated documentation files (the "Software"), to deal
172
+ in the Software without restriction, including without limitation the rights
173
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
174
+ copies of the Software, and to permit persons to whom the Software is
175
+ furnished to do so, subject to the following conditions:
176
+
177
+ The above copyright notice and this permission notice shall be included in all
178
+ copies or substantial portions of the Software.
179
+
180
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
182
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
183
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
184
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
185
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
186
+ SOFTWARE.
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'methodfinder/version'
1
4
  require 'stringio'
2
5
 
3
6
  class Object
@@ -8,7 +11,7 @@ class Object
8
11
  # %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
9
12
  # #=> ["Array#delete_at", "Array#slice!"]
10
13
  # 10.find_method { |n| n.unknown(3) == 1 }
11
- # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
14
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", ...]
12
15
  #
13
16
  # Inside <tt>find_method</tt>'s block, the receiver is available as
14
17
  # block argument and the special method <tt>unknown</tt> is used as
@@ -17,32 +20,24 @@ class Object
17
20
  # <tt>find_method</tt> can be called without passing a block. This
18
21
  # is the same as calling <tt>MethodFinder.find</tt>.
19
22
  #
20
- # 10.find_method(1,3)
21
- # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
22
-
23
- def find_method(*args, debug: ENV['METHOD_FINDER_DEBUG'], &block)
24
- if block
25
- mets = MethodFinder.methods_to_try(self).select do |met|
26
- STDERR.puts met if debug
27
- self.class.class_eval("alias :unknown #{met}")
28
- obj = self.dup rescue self # dup doesn't work for immutable types
29
- block.call(obj) rescue nil
30
- end
31
- mets.map { |m| "#{self.method(m).owner}##{m}" }
32
- else
33
- MethodFinder.find(self, *args, debug: debug)
34
- end
23
+ # 10.find_method(1, 3)
24
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", ...]
25
+ def find_method(*args, &block)
26
+ return MethodFinder.find(self, *args) unless block_given?
27
+ MethodFinder.find_unknown(self, &block)
35
28
  end
36
29
  end
37
30
 
38
31
  module MethodFinder
39
32
  # Default arguments for methods
33
+ # :nodoc:
40
34
  ARGS = {
41
35
  cycle: [1] # prevent cycling forever
42
- }
36
+ }.freeze
43
37
 
44
38
  # Blacklisting methods, e.g. { :Object => [:ri, :vim] }
45
39
  INSTANCE_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
40
+ # Blacklisting class methods
46
41
  CLASS_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
47
42
 
48
43
  INSTANCE_METHOD_BLACKLIST[:Object] << :find_method # prevent stack overflow
@@ -53,89 +48,120 @@ module MethodFinder
53
48
  CLASS_METHOD_BLACKLIST[:Object] << :pry
54
49
  end
55
50
 
56
- # Provided with a receiver, the desired result and possibly some
57
- # arguments, <tt>MethodFinder.find</tt> will list all methods that
58
- # produce the given result when called on the receiver with the
59
- # provided arguments.
60
- #
61
- # MethodFinder.find(10, 1, 3)
62
- # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
63
- # MethodFinder.find("abc","ABC")
64
- # #=> ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
65
- # MethodFinder.find(10, 100, 2)
66
- # #=> ["Fixnum#**"]
67
- # MethodFinder.find(['a','b','c'], ['A','B','C']) { |x| x.upcase }
68
- # #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", "Enumerable#flat_map", "Array#map", "Array#map!"]
69
-
70
- def self.find(obj, res, *args, debug: ENV['METHOD_FINDER_DEBUG'], &block)
71
- redirect_streams
72
-
73
- mets = methods_to_try(obj).select do |met|
74
- o = obj.dup rescue obj
75
- m = o.method(met)
76
- if m.arity <= args.size
77
- STDERR.puts met if debug
78
- a = args.empty? && ARGS.has_key?(met) ? ARGS[met] : args
79
- m.call(*a, &block) == res rescue nil
80
- end
81
- end
82
- mets.map { |m| "#{obj.method(m).owner}##{m}" }
83
- ensure
84
- restore_streams
85
- end
51
+ @debug = ENV['METHOD_FINDER_DEBUG']
86
52
 
87
- # Returns all currently defined modules and classes.
88
- def self.find_classes_and_modules
89
- constants = Object.constants.sort.map { |c| Object.const_get(c) }
90
- constants.select { |c| c.class == Class || c.class == Module}
53
+ # Checkes whether or not debugging is currently enabled
54
+ # :doc:
55
+ def self.debug?
56
+ !!(@debug)
57
+ end
58
+
59
+ # Toggles the debug mode
60
+ def self.toggle_debug!
61
+ @debug = !@debug
62
+ end
63
+
64
+ # Provided with a receiver, the desired result and possibly some
65
+ # arguments, <tt>MethodFinder.find</tt> will list all methods that
66
+ # produce the given result when called on the receiver with the
67
+ # provided arguments.
68
+ #
69
+ # MethodFinder.find(10, 1, 3)
70
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", ...]
71
+ # MethodFinder.find("abc","ABC")
72
+ # #=> ["String#swapcase", "String#swapcase!", "String#upcase", ...]
73
+ # MethodFinder.find(10, 100, 2)
74
+ # #=> ["Fixnum#**"]
75
+ # MethodFinder.find(['a','b','c'], ['A','B','C']) { |x| x.upcase }
76
+ # #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", ...]
77
+ def self.find(obj, res, *args, &block)
78
+ find_methods(obj) do |met|
79
+ o = obj.dup rescue obj
80
+ m = o.method(met)
81
+ next unless m.arity <= args.size
82
+ STDERR.puts(met) if debug?
83
+ a = args.empty? && ARGS.key?(met) ? ARGS[met] : args
84
+ m.call(*a, &block) == res rescue nil
91
85
  end
86
+ end
92
87
 
93
- # Searches for a given name within a class. The first parameter
94
- # can either be a class object, a symbol or a string whereas the
95
- # optional second parameter can be a string or a regular
96
- # expression:
97
- #
98
- # MethodFinder.find_in_class_or_module('Array', 'shuff')
99
- # #=> [:shuffle, :shuffle!]
100
- # MethodFinder.find_in_class_or_module(Float, /^to/)
101
- # #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
102
- #
103
- # If the second parameter is omitted, all methods of the class or
104
- # module will be returned.
105
- #
106
- # MethodFinder.find_in_class_or_module(Math)
107
- # #=> [:acos, :acosh, :asin ... :tanh]
108
-
109
- def self.find_in_class_or_module(c, pattern=/./)
110
- cs = Object.const_get(c.to_s)
111
- class_methods = cs.methods(false) rescue []
112
- instance_methods = cs.instance_methods(false)
113
- all_methods = class_methods + instance_methods
114
- all_methods.grep(/#{pattern}/).sort
88
+ # Returns all currently defined modules and classes.
89
+ def self.find_classes_and_modules
90
+ with_redirected_streams do
91
+ constants = Object.constants.sort.map { |c| Object.const_get(c) }
92
+ constants.select { |c| c.class == Class || c.class == Module }
115
93
  end
94
+ end
116
95
 
117
- # Returns a list of candidate methods for a given object. Added by Jan Lelis.
118
- def self.methods_to_try(obj)
119
- ret = obj.methods
120
- blacklist = obj.is_a?(Module) ? CLASS_METHOD_BLACKLIST : INSTANCE_METHOD_BLACKLIST
121
- klass = obj.is_a?(Module) ? obj : obj.class
96
+ # Searches for a given name within a class. The first parameter
97
+ # can either be a class object, a symbol or a string whereas the
98
+ # optional second parameter can be a string or a regular
99
+ # expression:
100
+ #
101
+ # MethodFinder.find_in_class_or_module('Array', 'shuff')
102
+ # #=> [:shuffle, :shuffle!]
103
+ # MethodFinder.find_in_class_or_module(Float, /^to/)
104
+ # #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
105
+ #
106
+ # If the second parameter is omitted, all methods of the class or
107
+ # module will be returned.
108
+ #
109
+ # MethodFinder.find_in_class_or_module(Math)
110
+ # #=> [:acos, :acosh, :asin ... :tanh]
111
+ # :doc:
112
+ def self.find_in_class_or_module(klass, pattern = /./)
113
+ klasses = Object.const_get(klass.to_s)
114
+ class_methods = klasses.methods(false) rescue []
115
+ instance_methods = klasses.instance_methods(false)
116
+ all_methods = class_methods + instance_methods
117
+ all_methods.grep(/#{pattern}/).sort
118
+ end
122
119
 
123
- klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
120
+ # Returns a list of candidate methods for a given object. Added by Jan Lelis.
121
+ def self.methods_to_try(obj)
122
+ ret = obj.methods
123
+ blacklist = select_blacklist(obj)
124
+ klass = obj.is_a?(Module) ? obj : obj.class
124
125
 
125
- ret.sort
126
+ klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
127
+ ret.sort
128
+ end
129
+ private_class_method :methods_to_try
130
+
131
+ # Used by Object.find_method
132
+ # :nodoc:
133
+ def self.find_unknown(obj, &block)
134
+ find_methods(obj) do |met|
135
+ STDERR.puts(met) if debug?
136
+ obj.class.class_eval("alias :unknown #{met}", __FILE__, __LINE__)
137
+ subject = obj.dup rescue obj # dup doesn't work for immutable types
138
+ block.call(subject) rescue nil
126
139
  end
140
+ end
127
141
 
128
- # :nodoc:
129
- def self.redirect_streams
130
- @orig_stdout = $stdout
131
- @orig_stderr = $stderr
132
- $stdout = StringIO.new
133
- $stderr = StringIO.new
142
+ def self.find_methods(obj)
143
+ with_redirected_streams do
144
+ found = methods_to_try(obj).select { |met| yield(met) }
145
+ found.map { |m| "#{obj.method(m).owner}##{m}" }
134
146
  end
147
+ end
148
+ private_class_method :find_methods
149
+
150
+ def self.with_redirected_streams
151
+ orig_stdout = $stdout
152
+ orig_stderr = $stderr
153
+ $stdout = StringIO.new
154
+ $stderr = StringIO.new
155
+
156
+ yield
157
+ ensure
158
+ $stdout = orig_stdout
159
+ $stderr = orig_stderr
160
+ end
161
+ private_class_method :with_redirected_streams
135
162
 
136
- def self.restore_streams
137
- $stdout = @orig_stdout
138
- $stderr = @orig_stderr
139
- end
140
- private_class_method :redirect_streams, :restore_streams
163
+ def self.select_blacklist(object)
164
+ object.is_a?(Module) ? CLASS_METHOD_BLACKLIST : INSTANCE_METHOD_BLACKLIST
165
+ end
166
+ private_class_method :select_blacklist
141
167
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MethodFinder
4
+ VERSION = '2.2.1'
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: methodfinder
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Kohl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-28 00:00:00.000000000 Z
11
+ date: 2018-05-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Smalltalk-like Method Finder for Ruby with some extra features
14
14
  email: citizen428@gmail.com
@@ -17,8 +17,9 @@ extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
19
  - "./LICENSE"
20
- - "./README.rdoc"
20
+ - "./README.md"
21
21
  - lib/methodfinder.rb
22
+ - lib/methodfinder/version.rb
22
23
  homepage: http://citizen428.github.com/methodfinder/
23
24
  licenses:
24
25
  - MIT
@@ -39,7 +40,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
40
  version: '0'
40
41
  requirements: []
41
42
  rubyforge_project:
42
- rubygems_version: 2.6.13
43
+ rubygems_version: 2.7.6
43
44
  signing_key:
44
45
  specification_version: 4
45
46
  summary: A Smalltalk-like Method Finder for Ruby
@@ -1,135 +0,0 @@
1
- = MethodFinder
2
-
3
- This project was originally inspired by Smalltalk's Method Finder, but additonal features were added over time.
4
-
5
- == Requirements
6
-
7
- Ruby 1.9.3+ (also works with Rubinius in 1.9 mode). Versions of <tt>MethodFinder</tt> up to 1.2.5 will also work with Ruby 1.8.7.
8
-
9
- == Usage
10
-
11
- === MethodFinder.find
12
-
13
- Provided with a receiver, the desired result and possibly some arguments, <tt>MethodFinder.find</tt> will list all methods that produce the given result when called on the receiver with the provided arguments.
14
-
15
- MethodFinder.find(10, 1, 3)
16
- #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
17
- MethodFinder.find("abc","ABC")
18
- #=> ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
19
- MethodFinder.find(10, 100, 2)
20
- #=> ["Fixnum#**"]
21
- MethodFinder.find(['a','b','c'], ['A','B','C']) { |x| x.upcase }
22
- #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", "Enumerable#flat_map", "Array#map", "Array#map!"]
23
-
24
- === Object#find_method
25
-
26
- This gem also adds <tt>Object#find_method</tt>, which besides offering an alternative interface to pretty much the same functionality as <tt>MethodFinder.find</tt>, also allows you to test for state other than the return value of the method.
27
-
28
- %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
29
- #=> ["Array#delete_at", "Array#slice!"]
30
- 10.find_method { |n| n.unknown(3) == 1 }
31
- #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
32
-
33
- Inside <tt>find_method</tt>'s block, the receiver is available as block argument and the special method <tt>unknown</tt> is used as a placeholder for the desired method.
34
-
35
- You can also call <tt>find_method</tt> without passing a block. This is the same as calling <tt>MethodFinder.find</tt>.
36
-
37
- 10.find_method(1,3)
38
- #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
39
-
40
- ==== Blacklists
41
-
42
- You can exclude methods from being tried by editing the hashes <tt>MethodFinder::INSTANCE_METHOD_BLACKLIST</tt> and <tt>MethodFinder::CLASS_METHOD_BLACKLIST</tt>. Both use the class/module as key and an array of method names as values (note that class, module and method names have to be symbols).
43
-
44
- For example, to blacklist the instance method <tt>shutdown</tt> of <tt>Object</tt>, you would do
45
-
46
- MethodFinder::INSTANCE_METHOD_BLACKLIST[:Object] << :shutdown
47
-
48
- This might come in handy when using <tt>MethodFinder</tt> together with other gems as such as <tt>interactive_editor</tt>.
49
-
50
- === MethodFinder.find_classes_and_modules
51
-
52
- A simple method to return all currently defined modules and classes.
53
-
54
- MethodFinder.find_classes_and_modules
55
- #=> [ArgumentError, Array, BasicObject, Bignum ... ZeroDivisionError]
56
-
57
- === MethodFinder.find_in_class_or_module
58
-
59
- Searches for a given name within a class. The first parameter can either be a class object, a symbol or a string whereas the optional second parameter can be a string or a regular expression:
60
-
61
- MethodFinder.find_in_class_or_module('Array', 'shuff')
62
- #=> [:shuffle, :shuffle!]
63
- MethodFinder.find_in_class_or_module(Float, /^to/)
64
- #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
65
-
66
- If the second parameter is omitted, all methods of the class or module will be returned.
67
-
68
- MethodFinder.find_in_class_or_module(Math)
69
- #=> [:acos, :acosh, :asin ... :tanh]
70
-
71
- == Troubleshooting
72
-
73
- If the +METHOD_FINDER_DEBUG+ environment variable is set, the name of each candidate method is printed to stderr before it is invoked. This can be useful to identify (and blacklist) misbehaving methods.
74
-
75
- It can be set on the command line e.g.:
76
-
77
- $ METHOD_FINDER_DEBUG=1 irb
78
-
79
- Or inside IRB/Pry:
80
-
81
- >> ENV['METHOD_FINDER_DEBUG'] = '1'
82
-
83
- Alternatively both <tt>Object#find_method</tt> and <tt>MethodFinder.find</tt> support an optional keyword argument +debug+ to toggle the behavior on a per-call basis (this argument defaults to the value of the environment variable described above):
84
-
85
- >> 'a'.find_method(debug: true) { |n| n.unknown == 'A' }
86
- !
87
- !=
88
- [output shortened]
89
- yellowish
90
- #=> ["String#capitalize", "String#capitalize!", "String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
91
- >> MethodFinder.find('a', 'A', debug: true)
92
- !
93
- !=
94
- [output shortened]
95
- yellowish
96
- #=> ["String#capitalize", "String#capitalize!", "String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
97
-
98
- == Warning
99
-
100
- Common sense not included!
101
-
102
- While I never had any problems with this, it's still better to be safe than sorry, so use this with caution and maybe not on production data.
103
-
104
- I initially wrote this for the students of the core Ruby course on {RubyLearning}[http://rubylearning.org], so Rails is not of interestto me (not saying it doesn't work there, just that I test in plain IRB/Pry and not with the Rails console.
105
-
106
- == Thanks
107
-
108
- * Matthew Lucas for {first packaging this as a gem}[https://github.com/citizen428/methodfinder/pull/1].
109
- * Ryan Bates for {suggesting}[https://github.com/citizen428/methodfinder/issues/closed#issue/3] what eventually became <tt>Object#find_method</tt>.
110
- * Jan Lelis for {implementing blacklists}[https://github.com/citizen428/methodfinder/issues/closed#issue/4].
111
- * Brian Morearty for pointing out an {incompatibility with Ruby 1.8.7}[https://github.com/citizen428/methodfinder/pull/5] and adding the {blockless version}[https://github.com/citizen428/methodfinder/pull/6] of <tt>Object#find_method</tt>.
112
- * Stefan Kanev for {adding Pry support}[https://github.com/citizen428/methodfinder/pull/7].
113
- * chocolateboy for {compatibility fixes and updates}[https://github.com/citizen428/methodfinder/pull/8], {the intitial debug implementation}[https://github.com/citizen428/methodfinder/pull/9], {fixes to keyword argument propagation}[https://github.com/citizen428/methodfinder/pull/11].
114
-
115
- == License
116
-
117
- Copyright (c) 2011-2017 Michael Kohl
118
-
119
- Permission is hereby granted, free of charge, to any person obtaining a copy
120
- of this software and associated documentation files (the "Software"), to deal
121
- in the Software without restriction, including without limitation the rights
122
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
123
- copies of the Software, and to permit persons to whom the Software is
124
- furnished to do so, subject to the following conditions:
125
-
126
- The above copyright notice and this permission notice shall be included in
127
- all copies or substantial portions of the Software.
128
-
129
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
130
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
131
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
132
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
133
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
134
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
135
- THE SOFTWARE.