methodfinder 2.1.0 → 2.2.3

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: 6a9a69705744aeafd4eb6e25c3909a44cdd6e650
4
- data.tar.gz: a5b5f61da2e85b791b95e954fa9355d6f545ffe6
2
+ SHA256:
3
+ metadata.gz: 9870bf45c6bbb10d2fe3c2d5ad509a3dace99d3b0bca753127bfa20a2185f2db
4
+ data.tar.gz: 424c6c14b3ec09c8b20370cb40ec2beb8e9ff9405008606d2a1ffdbc1a88c007
5
5
  SHA512:
6
- metadata.gz: 0a743f6b177ed4adf72fade44e5a84e8b68ae0f813e6410d70333d83fffb6c641881f6b0127dc5e7ac77a4dec979b972e1148a610e46bfcab98af4dabcd0f453
7
- data.tar.gz: 7d6463f11b889aa7728d4c595567fb804ee19f1f5ee06ad5a00a03b2666c30fa174ce01e8d4b98c8be14113a3bba6c2b9e51969a0584bb5d2b4dbf553123df49
6
+ metadata.gz: 475f9808360c53bc6b71861fa4ddb5c405a72ec685bb5517a5ff59704f61e034c56b802c4cc2f14fea18e55bdf811b44e03ed551c257864929294a5f0f4f6066
7
+ data.tar.gz: 6835cb818777f35e343d10f14ba905eb57f797ce251ad5b0120f336a05f2d466dc1658e9dedc4f6378919024b39f29010aa772af5ee18e668e8c6bbc708a7e97
data/CHANGELOG.md ADDED
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased](https://github.com/citizen428/methodfinder/tree/HEAD)
4
+
5
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.2.1...HEAD)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Cast the METHOD\_FINDER\_DEBUG environment variable to a boolean [\#17](https://github.com/citizen428/methodfinder/pull/17) ([chocolateboy](https://github.com/chocolateboy))
10
+ - Switch to Bundler gem structure [\#16](https://github.com/citizen428/methodfinder/pull/16) ([citizen428](https://github.com/citizen428))
11
+
12
+ ## [v2.2.1](https://github.com/citizen428/methodfinder/tree/v2.2.1) (2018-05-02)
13
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.2.0...v2.2.1)
14
+
15
+ ## [v2.2.0](https://github.com/citizen428/methodfinder/tree/v2.2.0) (2018-05-02)
16
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.1.0...v2.2.0)
17
+
18
+ **Implemented enhancements:**
19
+
20
+ - README.md tweaks [\#14](https://github.com/citizen428/methodfinder/pull/14) ([chocolateboy](https://github.com/chocolateboy))
21
+
22
+ **Fixed bugs:**
23
+
24
+ - It's not possible to pass a hash as the last argument [\#10](https://github.com/citizen428/methodfinder/issues/10)
25
+ - Fix failing Travis builds [\#15](https://github.com/citizen428/methodfinder/pull/15) ([chocolateboy](https://github.com/chocolateboy))
26
+ - Propagate keywords \(i.e. :debug\) from find\_method to find [\#11](https://github.com/citizen428/methodfinder/pull/11) ([chocolateboy](https://github.com/chocolateboy))
27
+
28
+ ## [v2.1.0](https://github.com/citizen428/methodfinder/tree/v2.1.0) (2017-02-05)
29
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.0.0...v2.1.0)
30
+
31
+ **Implemented enhancements:**
32
+
33
+ - Allow tested method names to be dumped to STDERR via an environment variable [\#9](https://github.com/citizen428/methodfinder/pull/9) ([chocolateboy](https://github.com/chocolateboy))
34
+ - Compatibility updates, fixes and workarounds [\#8](https://github.com/citizen428/methodfinder/pull/8) ([chocolateboy](https://github.com/chocolateboy))
35
+
36
+ ## [v2.0.0](https://github.com/citizen428/methodfinder/tree/v2.0.0) (2013-10-30)
37
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.5...v2.0.0)
38
+
39
+ ## [v1.2.5](https://github.com/citizen428/methodfinder/tree/v1.2.5) (2011-12-18)
40
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.4...v1.2.5)
41
+
42
+ ## [v1.2.4](https://github.com/citizen428/methodfinder/tree/v1.2.4) (2011-10-26)
43
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.2...v1.2.4)
44
+
45
+ **Implemented enhancements:**
46
+
47
+ - Make methodfinder play nice with Pry [\#7](https://github.com/citizen428/methodfinder/pull/7) ([skanev](https://github.com/skanev))
48
+ - Instance syntax and fix tests [\#6](https://github.com/citizen428/methodfinder/pull/6) ([BMorearty](https://github.com/BMorearty))
49
+
50
+ ## [v1.2.2](https://github.com/citizen428/methodfinder/tree/v1.2.2) (2011-04-23)
51
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.1...v1.2.2)
52
+
53
+ ## [v1.2.1](https://github.com/citizen428/methodfinder/tree/v1.2.1) (2011-04-16)
54
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.0...v1.2.1)
55
+
56
+ **Implemented enhancements:**
57
+
58
+ - Add a method ignore list [\#4](https://github.com/citizen428/methodfinder/pull/4) ([janlelis](https://github.com/janlelis))
59
+
60
+ ## [v1.2.0](https://github.com/citizen428/methodfinder/tree/v1.2.0) (2011-04-08)
61
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.1.1...v1.2.0)
62
+
63
+ ## [v1.1.1](https://github.com/citizen428/methodfinder/tree/v1.1.1) (2011-04-05)
64
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.1.0...v1.1.1)
65
+
66
+ **Implemented enhancements:**
67
+
68
+ - Alternative block interface [\#3](https://github.com/citizen428/methodfinder/issues/3)
69
+
70
+ ## [v1.1.0](https://github.com/citizen428/methodfinder/tree/v1.1.0) (2011-03-31)
71
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.0.1...v1.1.0)
72
+
73
+ **Closed issues:**
74
+
75
+ - Small typo in the readme [\#2](https://github.com/citizen428/methodfinder/issues/2)
76
+
77
+ ## [v1.0.1](https://github.com/citizen428/methodfinder/tree/v1.0.1) (2011-03-11)
78
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.0.0...v1.0.1)
79
+
80
+ ## [v1.0.0](https://github.com/citizen428/methodfinder/tree/v1.0.0) (2011-02-10)
@@ -17,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
17
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
18
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  THE SOFTWARE.
20
-
data/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # MethodFinder
2
+
3
+ ![Build](https://github.com/citizen428/methodfinder/workflows/Build/badge.svg)
4
+ [![Gem Version](https://img.shields.io/gem/v/methodfinder.svg)](https://rubygems.org/gems/methodfinder)
5
+
6
+ <!-- toc -->
7
+
8
+ - [NAME](#name)
9
+ - [INSTALLATION](#installation)
10
+ - [SYNOPSIS](#synopsis)
11
+ - [DESCRIPTION](#description)
12
+ - [Warning](#warning)
13
+ - [API](#api)
14
+ - [MethodFinder.find](#methodfinderfind)
15
+ - [Object#find_method](#objectfind_method)
16
+ - [Ignorelists](#ignorelists)
17
+ - [MethodFinder.find_classes_and_modules](#methodfinderfind_classes_and_modules)
18
+ - [MethodFinder.find_in_class_or_module](#methodfinderfind_in_class_or_module)
19
+ - [TROUBLESHOOTING](#troubleshooting)
20
+ - [DEVELOPMENT](#development)
21
+ - [CONTRIBUTING](#contributing)
22
+ - [SEE ALSO](#see-also)
23
+ - [Gems](#gems)
24
+ - [Misc](#misc)
25
+ - [VERSION](#version)
26
+ - [AUTHOR](#author)
27
+ - [LICENSE](#license)
28
+
29
+ <!-- tocstop -->
30
+
31
+ ## NAME
32
+
33
+ MethodFinder - a Smalltalk-like Method Finder for Ruby
34
+
35
+ ## INSTALLATION
36
+
37
+ $ gem install methodfinder
38
+
39
+ ## SYNOPSIS
40
+
41
+ ```ruby
42
+ Welcome to IRB. # or Pry
43
+
44
+ >> 'Hello, world!'.find_method('HELLO, WORLD!')
45
+ #=> ["String#upcase", "String#upcase!"]
46
+
47
+ >> %w[a b c].find_method('c')
48
+ #=> ["Array#last", "Array#max", "Array#pop"]
49
+
50
+ >> %w[a b c].find_method { |it| it.unknown(2); it == %w[c] }
51
+ #=> ["Array#shift"]
52
+ ```
53
+
54
+ ## DESCRIPTION
55
+
56
+ A Smalltalk-like Method Finder for Ruby for use in your `~/.irbrc` or
57
+ `~/.pryrc`.
58
+
59
+ This project was originally inspired by Smalltalk's Method
60
+ Finder, but additional features have been added over time.
61
+
62
+ ### Warning
63
+
64
+ Common sense not included!
65
+
66
+ While this gem should generally be safe to use, it's still better to be safe
67
+ than sorry, so use this with caution and maybe not on production data.
68
+
69
+ This was initially written for the students of the core Ruby course on
70
+ [RubyLearning](http://web.archive.org/web/20151218180403/http://rubylearning.org/classes/),
71
+ so it's generally not tested in a Rails console, just plain IRB/Pry.
72
+
73
+ ## API
74
+
75
+ ### MethodFinder.find
76
+
77
+ Provided with a receiver, the desired result and possibly some arguments,
78
+ `MethodFinder.find` will list all methods that produce the given result when
79
+ called on the receiver with the provided arguments.
80
+
81
+ ```ruby
82
+ MethodFinder.find(10, 1, 3)
83
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
84
+ MethodFinder.find("abc", "ABC")
85
+ #=> ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
86
+ MethodFinder.find(10, 100, 2)
87
+ #=> ["Fixnum#**"]
88
+ MethodFinder.find(['a', 'b', 'c'], ['A', 'B', 'C']) { |x| x.upcase }
89
+ #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", "Enumerable#flat_map", "Array#map", "Array#map!"]
90
+ ```
91
+
92
+ ### Object#find_method
93
+
94
+ This gem also adds `Object#find_method`, which besides offering an alternative
95
+ interface to pretty much the same functionality as `MethodFinder.find`, also
96
+ allows you to test for state other than the return value of the method.
97
+
98
+ ```ruby
99
+ %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
100
+ #=> ["Array#delete_at", "Array#slice!"]
101
+ 10.find_method { |n| n.unknown(3) == 1 }
102
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
103
+ ```
104
+
105
+ Inside `find_method`'s block, the receiver is available as block argument and
106
+ the special method `unknown` is used as a placeholder for the desired method.
107
+
108
+ You can also call `find_method` without passing a block. This is the same as
109
+ calling `MethodFinder.find`.
110
+
111
+ ```ruby
112
+ 10.find_method(1, 3)
113
+ #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
114
+ ```
115
+
116
+ #### Ignorelists
117
+
118
+ You can exclude methods from being tried by editing the hashes
119
+ `MethodFinder::INSTANCE_METHOD_IGNORELIST` and
120
+ `MethodFinder::CLASS_METHOD_IGNORELIST`. Both use the class/module as key and
121
+ an array of method names as values (note that class, module and method names
122
+ have to be symbols).
123
+
124
+ For example, to ignore the instance method `shutdown` of `Object`, you would do
125
+
126
+ ```ruby
127
+ MethodFinder::INSTANCE_METHOD_IGNORELIST[:Object] << :shutdown
128
+ ```
129
+
130
+ This might come in handy when using `MethodFinder` together with other gems as
131
+ such as `interactive_editor`.
132
+
133
+ ### MethodFinder.find_classes_and_modules
134
+
135
+ A simple method to return all currently defined modules and classes.
136
+
137
+ ```ruby
138
+ MethodFinder.find_classes_and_modules
139
+ #=> [ArgumentError, Array, BasicObject, Bignum ... ZeroDivisionError]
140
+ ```
141
+
142
+ ### MethodFinder.find_in_class_or_module
143
+
144
+ Searches for a given name within a class. The first parameter can either be a
145
+ class object, a symbol or a string whereas the optional second parameter can
146
+ be a string or a regular expression:
147
+
148
+ ```ruby
149
+ MethodFinder.find_in_class_or_module('Array', 'shuff')
150
+ #=> [:shuffle, :shuffle!]
151
+ MethodFinder.find_in_class_or_module(Float, /^to/)
152
+ #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
153
+ ```
154
+
155
+ If the second parameter is omitted, all methods of the class or module will be
156
+ returned.
157
+
158
+ ```ruby
159
+ MethodFinder.find_in_class_or_module(Math)
160
+ #=> [:acos, :acosh, :asin ... :tanh]
161
+ ```
162
+
163
+ ## TROUBLESHOOTING
164
+
165
+ If the `METHOD_FINDER_DEBUG` environment variable is set, the name of each
166
+ candidate method is printed to `STDERR` before it is invoked. This can be useful
167
+ to identify (and consequently ignore) misbehaving methods.
168
+
169
+ It can be set on the command line e.g.:
170
+
171
+ ```
172
+ $ METHOD_FINDER_DEBUG=1 irb
173
+ ```
174
+
175
+ Or you can toggle it inside IRB/Pry:
176
+
177
+ ```ruby
178
+ >> MethodFinder.toggle_debug!
179
+ ```
180
+
181
+ ## DEVELOPMENT
182
+
183
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
184
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
185
+ prompt that will allow you to experiment.
186
+
187
+ To install this gem onto your local machine, run `bundle exec rake install`. To
188
+ release a new version, update the version number in `version.rb`, and then run
189
+ `bundle exec rake release`, which will create a git tag for the version, push
190
+ git commits and tags, and push the `.gem` file to
191
+ [rubygems.org](https://rubygems.org).
192
+
193
+ ## CONTRIBUTING
194
+
195
+ Bug reports and pull requests are welcome on GitHub at
196
+ https://github.com/citizen428/methodfinder.
197
+
198
+ ## SEE ALSO
199
+
200
+ ### Gems
201
+
202
+ - [irbtools](https://github.com/janlelis/irbtools) - improvements for Ruby's IRB console (includes methodfinder)
203
+
204
+ ### Misc
205
+
206
+ - [Other Implementations](https://github.com/citizen428/methodfinder/wiki/Other-Implementations) - a list of related projects in Ruby and other languages
207
+
208
+ ## VERSION
209
+
210
+ 2.2.1
211
+
212
+ ## AUTHOR
213
+
214
+ - [Michael Kohl](https://github.com/citizen428)
215
+
216
+ ## LICENSE
217
+
218
+ The gem is available as open source under the terms of the [MIT
219
+ License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MethodFinder
4
+ VERSION = '2.2.3'
5
+ end
data/lib/methodfinder.rb CHANGED
@@ -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,125 +20,185 @@ 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)
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
+
28
+ MethodFinder.find_unknown(self, &block)
35
29
  end
36
30
  end
37
31
 
38
32
  module MethodFinder
39
33
  # Default arguments for methods
34
+ # :nodoc:
40
35
  ARGS = {
41
36
  cycle: [1] # prevent cycling forever
42
- }
37
+ }.freeze
43
38
 
44
- # Blacklisting methods, e.g. { :Object => [:ri, :vim] }
45
- INSTANCE_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
46
- CLASS_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
39
+ # Ignoring methods, e.g. { :Object => [:ri, :vim] }
40
+ INSTANCE_METHOD_IGNORELIST = Hash.new { |h, k| h[k] = [] }
41
+ # Ignoring class methods
42
+ CLASS_METHOD_IGNORELIST = Hash.new { |h, k| h[k] = [] }
43
+ # IGNORING classes
44
+ CLASS_IGNORELIST = []
47
45
 
48
- INSTANCE_METHOD_BLACKLIST[:Object] << :find_method # prevent stack overflow
49
- INSTANCE_METHOD_BLACKLIST[:Object] << :gem # funny testing stuff w/ Bundler
46
+ if RUBY_VERSION.start_with?('3')
47
+ CLASS_IGNORELIST << :SortedSet # this moved to a gem
48
+ end
49
+
50
+ INSTANCE_METHOD_IGNORELIST[:Object] << :find_method # prevent stack overflow
51
+ INSTANCE_METHOD_IGNORELIST[:Object] << :gem # funny testing stuff w/ Bundler
50
52
 
51
53
  if defined?(Pry)
52
- INSTANCE_METHOD_BLACKLIST[:Object] << :pry
53
- CLASS_METHOD_BLACKLIST[:Object] << :pry
54
+ INSTANCE_METHOD_IGNORELIST[:Object] << :pry
55
+ CLASS_METHOD_IGNORELIST[:Object] << :pry
54
56
  end
55
57
 
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
58
+ # true if METHOD_FINDER_DEBUG is truthy, false otherwise e.g.:
59
+ #
60
+ # $ METHOD_FINDER_DEBUG=1 irb # true
61
+ # $ METHOD_FINDER_DEBUG=0 irb # false
62
+ # $ METHOD_FINDER_DEBUG=false irb # false
63
+ # $ METHOD_FINDER_DEBUG= irb # false
64
+ @debug = !ENV.fetch('METHOD_FINDER_DEBUG', '').match(/\A(0|false)?\z/i)
65
+
66
+ # Checks whether or not debugging is currently enabled
67
+ # :doc:
68
+ def self.debug?
69
+ @debug
70
+ end
71
+
72
+ # Toggles the debug mode
73
+ def self.toggle_debug!
74
+ @debug = !@debug
75
+ end
76
+
77
+ # Provided with a receiver, the desired result and possibly some
78
+ # arguments, <tt>MethodFinder.find</tt> will list all methods that
79
+ # produce the given result when called on the receiver with the
80
+ # provided arguments.
81
+ #
82
+ # MethodFinder.find(10, 1, 3)
83
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", ...]
84
+ # MethodFinder.find("abc","ABC")
85
+ # #=> ["String#swapcase", "String#swapcase!", "String#upcase", ...]
86
+ # MethodFinder.find(10, 100, 2)
87
+ # #=> ["Fixnum#**"]
88
+ # MethodFinder.find(['a','b','c'], ['A','B','C']) { |x| x.upcase }
89
+ # #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", ...]
90
+ def self.find(obj, res, *args, &block)
91
+ find_methods(obj) do |met|
92
+ o = begin
93
+ obj.dup
94
+ rescue StandardError
95
+ obj
96
+ end
97
+ m = o.method(met)
98
+ next unless m.arity <= args.size
99
+
100
+ warn(met) if debug?
101
+ a = args.empty? && ARGS.key?(met) ? ARGS[met] : args
102
+ begin
103
+ m.call(*a, &block) == res
104
+ rescue StandardError
105
+ nil
81
106
  end
82
- mets.map { |m| "#{obj.method(m).owner}##{m}" }
83
- ensure
84
- restore_streams
85
107
  end
108
+ end
86
109
 
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}
110
+ # Returns all currently defined modules and classes.
111
+ def self.find_classes_and_modules
112
+ with_redirected_streams do
113
+ candidates = Object.constants - CLASS_IGNORELIST
114
+ constants = candidates.sort.map { |c| Object.const_get(c) }
115
+ constants.select do |c|
116
+ c.instance_of?(Class) || c.instance_of?(Module)
117
+ end
91
118
  end
119
+ end
92
120
 
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
121
+ # Searches for a given name within a class. The first parameter
122
+ # can either be a class object, a symbol or a string whereas the
123
+ # optional second parameter can be a string or a regular
124
+ # expression:
125
+ #
126
+ # MethodFinder.find_in_class_or_module('Array', 'shuff')
127
+ # #=> [:shuffle, :shuffle!]
128
+ # MethodFinder.find_in_class_or_module(Float, /^to/)
129
+ # #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
130
+ #
131
+ # If the second parameter is omitted, all methods of the class or
132
+ # module will be returned.
133
+ #
134
+ # MethodFinder.find_in_class_or_module(Math)
135
+ # #=> [:acos, :acosh, :asin ... :tanh]
136
+ # :doc:
137
+ def self.find_in_class_or_module(klass, pattern = /./)
138
+ klasses = Object.const_get(klass.to_s)
139
+ class_methods = begin
140
+ klasses.methods(false)
141
+ rescue StandardError
142
+ []
115
143
  end
144
+ instance_methods = klasses.instance_methods(false)
145
+ all_methods = class_methods + instance_methods
146
+ all_methods.grep(/#{pattern}/).sort
147
+ end
116
148
 
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
122
-
123
- klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
149
+ # Returns a list of candidate methods for a given object. Added by Jan Lelis.
150
+ def self.methods_to_try(obj)
151
+ ret = obj.methods
152
+ ignorelist = select_ignorelist(obj)
153
+ klass = obj.is_a?(Module) ? obj : obj.class
124
154
 
125
- ret.sort
155
+ klass.ancestors.each { |ancestor| ret -= ignorelist[ancestor.to_s.intern] }
156
+ ret.sort
157
+ end
158
+ private_class_method :methods_to_try
159
+
160
+ # Used by Object.find_method
161
+ # :nodoc:
162
+ def self.find_unknown(obj, &block)
163
+ find_methods(obj) do |met|
164
+ warn(met) if debug?
165
+ obj.class.class_eval("alias :unknown #{met}", __FILE__, __LINE__)
166
+ subject = begin
167
+ obj.dup
168
+ rescue StandardError # dup doesn't work for immutable types
169
+ obj
170
+ end
171
+ begin
172
+ block.call(subject)
173
+ rescue StandardError
174
+ nil
175
+ end
126
176
  end
177
+ end
127
178
 
128
- # :nodoc:
129
- def self.redirect_streams
130
- @orig_stdout = $stdout
131
- @orig_stderr = $stderr
132
- $stdout = StringIO.new
133
- $stderr = StringIO.new
179
+ def self.find_methods(obj, &block)
180
+ with_redirected_streams do
181
+ found = methods_to_try(obj).select(&block)
182
+ found.map { |m| "#{obj.method(m).owner}##{m}" }
134
183
  end
184
+ end
185
+ private_class_method :find_methods
186
+
187
+ def self.with_redirected_streams
188
+ orig_stdout = $stdout
189
+ orig_stderr = $stderr
190
+ $stdout = StringIO.new
191
+ $stderr = StringIO.new
192
+
193
+ yield
194
+ ensure
195
+ $stdout = orig_stdout
196
+ $stderr = orig_stderr
197
+ end
198
+ private_class_method :with_redirected_streams
135
199
 
136
- def self.restore_streams
137
- $stdout = @orig_stdout
138
- $stderr = @orig_stderr
139
- end
140
- private_class_method :redirect_streams, :restore_streams
200
+ def self.select_ignorelist(object)
201
+ object.is_a?(Module) ? CLASS_METHOD_IGNORELIST : INSTANCE_METHOD_IGNORELIST
202
+ end
203
+ private_class_method :select_ignorelist
141
204
  end
metadata CHANGED
@@ -1,28 +1,118 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: methodfinder
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.3
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-02-05 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: github_changelog_generator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '6.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.22'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.22'
13
97
  description: A Smalltalk-like Method Finder for Ruby with some extra features
14
- email: citizen428@gmail.com
98
+ email:
99
+ - citizen428@gmail.com
15
100
  executables: []
16
101
  extensions: []
17
102
  extra_rdoc_files: []
18
103
  files:
19
- - "./LICENSE"
20
- - "./README.rdoc"
104
+ - CHANGELOG.md
105
+ - LICENSE.txt
106
+ - README.md
21
107
  - lib/methodfinder.rb
108
+ - lib/methodfinder/version.rb
22
109
  homepage: http://citizen428.github.com/methodfinder/
23
110
  licenses:
24
111
  - MIT
25
- metadata: {}
112
+ metadata:
113
+ bug_tracker_uri: https://github.com/citizen428/methodfinder/issues
114
+ source_code_uri: https://github.com/citizen428/methodfinder
115
+ changelog_uri: https://github.com/citizen428/methodfinder/blob/master/CHANGELOG.md
26
116
  post_install_message:
27
117
  rdoc_options: []
28
118
  require_paths:
@@ -31,15 +121,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
31
121
  requirements:
32
122
  - - ">="
33
123
  - !ruby/object:Gem::Version
34
- version: '0'
124
+ version: '2.6'
35
125
  required_rubygems_version: !ruby/object:Gem::Requirement
36
126
  requirements:
37
127
  - - ">="
38
128
  - !ruby/object:Gem::Version
39
129
  version: '0'
40
130
  requirements: []
41
- rubyforge_project:
42
- rubygems_version: 2.5.2
131
+ rubygems_version: 3.2.22
43
132
  signing_key:
44
133
  specification_version: 4
45
134
  summary: A Smalltalk-like Method Finder for Ruby
data/README.rdoc DELETED
@@ -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] as well as {the intitial debug implementation}[https://github.com/citizen428/methodfinder/pull/9].
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.