methodfinder 2.1.1 → 2.2.1

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.
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.