methodfinder 1.2.5 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6956d01fde38cb630cad9346d877e060fff4920c7163016ff8b97cf20020ef27
4
+ data.tar.gz: 695b0fd1fa89f26ab09dc6f30bda1b650d2ce6d0e9617c0ac5a8207f402ec575
5
+ SHA512:
6
+ metadata.gz: 24d990971ab3dbdfbc3a7568b7145637dc8b222897200ee01d03364528248edcb1d7acd57db8b4afaab2949cb4b7dfa31ef3dfd5778ac1f6d4360afc9b2f0619
7
+ data.tar.gz: 894bdbb10df681feae1dbd03892d436ce2faec0009414fa50cafab92dba1079dfb52e722bb9a763b21af6971cca007081b9bcff6c111718e349d7c97e92dd07a
data/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
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
+ - Add a changelog [\#19](https://github.com/citizen428/methodfinder/pull/19) ([chocolateboy](https://github.com/chocolateboy))
10
+ - Cast the METHOD\_FINDER\_DEBUG environment variable to a boolean [\#17](https://github.com/citizen428/methodfinder/pull/17) ([chocolateboy](https://github.com/chocolateboy))
11
+ - Switch to Bundler gem structure [\#16](https://github.com/citizen428/methodfinder/pull/16) ([citizen428](https://github.com/citizen428))
12
+
13
+ **Merged pull requests:**
14
+
15
+ - Documentation tweaks [\#22](https://github.com/citizen428/methodfinder/pull/22) ([chocolateboy](https://github.com/chocolateboy))
16
+ - Bump activesupport from 5.2.0 to 6.0.3.1 [\#21](https://github.com/citizen428/methodfinder/pull/21) ([dependabot[bot]](https://github.com/apps/dependabot))
17
+ - Update rake requirement from ~\> 10.0 to ~\> 13.0 [\#20](https://github.com/citizen428/methodfinder/pull/20) ([dependabot[bot]](https://github.com/apps/dependabot))
18
+
19
+ ## [v2.2.1](https://github.com/citizen428/methodfinder/tree/v2.2.1) (2018-05-02)
20
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.2.0...v2.2.1)
21
+
22
+ ## [v2.2.0](https://github.com/citizen428/methodfinder/tree/v2.2.0) (2018-05-02)
23
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.1.0...v2.2.0)
24
+
25
+ **Implemented enhancements:**
26
+
27
+ - README.md tweaks [\#14](https://github.com/citizen428/methodfinder/pull/14) ([chocolateboy](https://github.com/chocolateboy))
28
+
29
+ **Fixed bugs:**
30
+
31
+ - It's not possible to pass a hash as the last argument [\#10](https://github.com/citizen428/methodfinder/issues/10)
32
+ - Fix failing Travis builds [\#15](https://github.com/citizen428/methodfinder/pull/15) ([chocolateboy](https://github.com/chocolateboy))
33
+ - Propagate keywords \(i.e. :debug\) from find\_method to find [\#11](https://github.com/citizen428/methodfinder/pull/11) ([chocolateboy](https://github.com/chocolateboy))
34
+
35
+ ## [v2.1.0](https://github.com/citizen428/methodfinder/tree/v2.1.0) (2017-02-05)
36
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v2.0.0...v2.1.0)
37
+
38
+ **Implemented enhancements:**
39
+
40
+ - 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))
41
+ - Compatibility updates, fixes and workarounds [\#8](https://github.com/citizen428/methodfinder/pull/8) ([chocolateboy](https://github.com/chocolateboy))
42
+
43
+ ## [v2.0.0](https://github.com/citizen428/methodfinder/tree/v2.0.0) (2013-10-30)
44
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.5...v2.0.0)
45
+
46
+ ## [v1.2.5](https://github.com/citizen428/methodfinder/tree/v1.2.5) (2011-12-18)
47
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.4...v1.2.5)
48
+
49
+ ## [v1.2.4](https://github.com/citizen428/methodfinder/tree/v1.2.4) (2011-10-26)
50
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.2...v1.2.4)
51
+
52
+ **Implemented enhancements:**
53
+
54
+ - Make methodfinder play nice with Pry [\#7](https://github.com/citizen428/methodfinder/pull/7) ([skanev](https://github.com/skanev))
55
+ - Instance syntax and fix tests [\#6](https://github.com/citizen428/methodfinder/pull/6) ([BMorearty](https://github.com/BMorearty))
56
+
57
+ ## [v1.2.2](https://github.com/citizen428/methodfinder/tree/v1.2.2) (2011-04-23)
58
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.1...v1.2.2)
59
+
60
+ ## [v1.2.1](https://github.com/citizen428/methodfinder/tree/v1.2.1) (2011-04-16)
61
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.2.0...v1.2.1)
62
+
63
+ **Implemented enhancements:**
64
+
65
+ - Add a method blacklist [\#4](https://github.com/citizen428/methodfinder/pull/4) ([janlelis](https://github.com/janlelis))
66
+
67
+ ## [v1.2.0](https://github.com/citizen428/methodfinder/tree/v1.2.0) (2011-04-08)
68
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.1.1...v1.2.0)
69
+
70
+ ## [v1.1.1](https://github.com/citizen428/methodfinder/tree/v1.1.1) (2011-04-05)
71
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.1.0...v1.1.1)
72
+
73
+ **Implemented enhancements:**
74
+
75
+ - Alternative block interface [\#3](https://github.com/citizen428/methodfinder/issues/3)
76
+
77
+ ## [v1.1.0](https://github.com/citizen428/methodfinder/tree/v1.1.0) (2011-03-31)
78
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.0.1...v1.1.0)
79
+
80
+ **Closed issues:**
81
+
82
+ - Small typo in the readme [\#2](https://github.com/citizen428/methodfinder/issues/2)
83
+
84
+ ## [v1.0.1](https://github.com/citizen428/methodfinder/tree/v1.0.1) (2011-03-11)
85
+ [Full Changelog](https://github.com/citizen428/methodfinder/compare/v1.0.0...v1.0.1)
86
+
87
+ ## [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).
data/lib/methodfinder.rb CHANGED
@@ -1,91 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'methodfinder/version'
1
4
  require 'stringio'
2
5
 
3
6
  class Object
7
+ # An alternative interface to the functionality of
8
+ # <tt>MethodFinder.find</tt>. Also allows to test for state other
9
+ # than the return value of the method.
10
+ #
11
+ # %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
12
+ # #=> ["Array#delete_at", "Array#slice!"]
13
+ # 10.find_method { |n| n.unknown(3) == 1 }
14
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", ...]
15
+ #
16
+ # Inside <tt>find_method</tt>'s block, the receiver is available as
17
+ # block argument and the special method <tt>unknown</tt> is used as
18
+ # a placeholder for the desired method.
19
+ #
20
+ # <tt>find_method</tt> can be called without passing a block. This
21
+ # is the same as calling <tt>MethodFinder.find</tt>.
22
+ #
23
+ # 10.find_method(1, 3)
24
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", ...]
4
25
  def find_method(*args, &block)
5
- if block_given?
6
- mets = MethodFinder.methods_to_try(self).select do |met|
7
- self.class.class_eval %{ alias :unknown #{met} }
8
- obj = self.dup rescue self
9
- yield obj rescue nil
10
- end
11
- mets.map { |m| [self.method(m).owner, m].join("#") }
12
- else
13
- MethodFinder.find(self, *args)
14
- end
26
+ return MethodFinder.find(self, *args) unless block_given?
27
+ MethodFinder.find_unknown(self, &block)
15
28
  end
16
29
  end
17
30
 
18
- class MethodFinder
31
+ module MethodFinder
32
+ # Default arguments for methods
33
+ # :nodoc:
19
34
  ARGS = {
20
- :cycle => [1] # prevent cycling forever
21
- }
35
+ cycle: [1] # prevent cycling forever
36
+ }.freeze
22
37
 
23
- # Blacklisting methods, e.g. { :Object => [:ri, :vim] }
24
- INSTANCE_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
25
- CLASS_METHOD_BLACKLIST = Hash.new { |h, k| h[k] = [] }
38
+ # Ignoring methods, e.g. { :Object => [:ri, :vim] }
39
+ INSTANCE_METHOD_IGNORELIST = Hash.new { |h, k| h[k] = [] }
40
+ # Ignoring class methods
41
+ CLASS_METHOD_IGNORELIST = Hash.new { |h, k| h[k] = [] }
26
42
 
27
- INSTANCE_METHOD_BLACKLIST[:Object] << :find_method # prevent stack overflow
28
- INSTANCE_METHOD_BLACKLIST[:Object] << :gem # funny testing stuff w/ Bundler
43
+ INSTANCE_METHOD_IGNORELIST[:Object] << :find_method # prevent stack overflow
44
+ INSTANCE_METHOD_IGNORELIST[:Object] << :gem # funny testing stuff w/ Bundler
29
45
 
30
- if defined? Pry
31
- INSTANCE_METHOD_BLACKLIST[:Object] << :pry
32
- CLASS_METHOD_BLACKLIST[:Object] << :pry
46
+ if defined?(Pry)
47
+ INSTANCE_METHOD_IGNORELIST[:Object] << :pry
48
+ CLASS_METHOD_IGNORELIST[:Object] << :pry
33
49
  end
34
50
 
35
- class << self
36
- def find(obj, res, *args, &block)
37
- redirect_streams
38
-
39
- mets = methods_to_try(obj).select do |met|
40
- o = obj.dup rescue obj
41
- m = o.method(met)
42
- if m.arity <= args.size
43
- a = args.empty? && ARGS.has_key?(met) ? ARGS[met] : args
44
- m.call(*a, &block) == res rescue nil
45
- end
46
- end
47
- mets.map { |m| [obj.method(m).owner, m].join("#") }
48
- ensure
49
- restore_streams
50
- end
51
+ # true if METHOD_FINDER_DEBUG is truthy, false otherwise e.g.:
52
+ #
53
+ # $ METHOD_FINDER_DEBUG=1 irb # true
54
+ # $ METHOD_FINDER_DEBUG=0 irb # false
55
+ # $ METHOD_FINDER_DEBUG=false irb # false
56
+ # $ METHOD_FINDER_DEBUG= irb # false
57
+ @debug = !ENV.fetch('METHOD_FINDER_DEBUG', '').match(/\A(0|false)?\z/i)
51
58
 
52
- # Added by Jan Lelis
53
- def methods_to_try(obj)
54
- ret = obj.methods.map(&:intern)
55
- blacklist = obj.is_a?(Module) ? CLASS_METHOD_BLACKLIST : INSTANCE_METHOD_BLACKLIST
56
- klass = obj.is_a?(Module) ? obj : obj.class
59
+ # Checks whether or not debugging is currently enabled
60
+ # :doc:
61
+ def self.debug?
62
+ @debug
63
+ end
57
64
 
58
- klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
65
+ # Toggles the debug mode
66
+ def self.toggle_debug!
67
+ @debug = !@debug
68
+ end
59
69
 
60
- # 1.8.7 lacks Symbol#<=>
61
- ret.sort_by(&:to_s)
70
+ # Provided with a receiver, the desired result and possibly some
71
+ # arguments, <tt>MethodFinder.find</tt> will list all methods that
72
+ # produce the given result when called on the receiver with the
73
+ # provided arguments.
74
+ #
75
+ # MethodFinder.find(10, 1, 3)
76
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", ...]
77
+ # MethodFinder.find("abc","ABC")
78
+ # #=> ["String#swapcase", "String#swapcase!", "String#upcase", ...]
79
+ # MethodFinder.find(10, 100, 2)
80
+ # #=> ["Fixnum#**"]
81
+ # MethodFinder.find(['a','b','c'], ['A','B','C']) { |x| x.upcase }
82
+ # #=> ["Array#collect", "Array#collect!", "Enumerable#collect_concat", ...]
83
+ def self.find(obj, res, *args, &block)
84
+ find_methods(obj) do |met|
85
+ o = obj.dup rescue obj
86
+ m = o.method(met)
87
+ next unless m.arity <= args.size
88
+ STDERR.puts(met) if debug?
89
+ a = args.empty? && ARGS.key?(met) ? ARGS[met] : args
90
+ m.call(*a, &block) == res rescue nil
62
91
  end
92
+ end
63
93
 
64
- def find_classes_and_modules
94
+ # Returns all currently defined modules and classes.
95
+ def self.find_classes_and_modules
96
+ with_redirected_streams do
65
97
  constants = Object.constants.sort.map { |c| Object.const_get(c) }
66
- constants.select { |c| c.class == Class || c.class == Module}
98
+ constants.select { |c| c.class == Class || c.class == Module }
67
99
  end
100
+ end
68
101
 
69
- def find_in_class_or_module(c, pattern=/./)
70
- cs = Object.const_get(c.to_s)
71
- class_methods = cs.methods(false) rescue []
72
- instance_methods = cs.instance_methods(false)
73
- all_methods = class_methods + instance_methods
74
- all_methods.grep(/#{pattern}/).sort
75
- end
102
+ # Searches for a given name within a class. The first parameter
103
+ # can either be a class object, a symbol or a string whereas the
104
+ # optional second parameter can be a string or a regular
105
+ # expression:
106
+ #
107
+ # MethodFinder.find_in_class_or_module('Array', 'shuff')
108
+ # #=> [:shuffle, :shuffle!]
109
+ # MethodFinder.find_in_class_or_module(Float, /^to/)
110
+ # #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
111
+ #
112
+ # If the second parameter is omitted, all methods of the class or
113
+ # module will be returned.
114
+ #
115
+ # MethodFinder.find_in_class_or_module(Math)
116
+ # #=> [:acos, :acosh, :asin ... :tanh]
117
+ # :doc:
118
+ def self.find_in_class_or_module(klass, pattern = /./)
119
+ klasses = Object.const_get(klass.to_s)
120
+ class_methods = klasses.methods(false) rescue []
121
+ instance_methods = klasses.instance_methods(false)
122
+ all_methods = class_methods + instance_methods
123
+ all_methods.grep(/#{pattern}/).sort
124
+ end
125
+
126
+ # Returns a list of candidate methods for a given object. Added by Jan Lelis.
127
+ def self.methods_to_try(obj)
128
+ ret = obj.methods
129
+ ignorelist = select_ignorelist(obj)
130
+ klass = obj.is_a?(Module) ? obj : obj.class
76
131
 
77
- def redirect_streams
78
- @orig_stdout = $stdout
79
- @orig_stderr = $stderr
80
- $stdout = StringIO.new
81
- $stderr = StringIO.new
132
+ klass.ancestors.each { |ancestor| ret -= ignorelist[ancestor.to_s.intern] }
133
+ ret.sort
134
+ end
135
+ private_class_method :methods_to_try
136
+
137
+ # Used by Object.find_method
138
+ # :nodoc:
139
+ def self.find_unknown(obj, &block)
140
+ find_methods(obj) do |met|
141
+ STDERR.puts(met) if debug?
142
+ obj.class.class_eval("alias :unknown #{met}", __FILE__, __LINE__)
143
+ subject = obj.dup rescue obj # dup doesn't work for immutable types
144
+ block.call(subject) rescue nil
82
145
  end
146
+ end
83
147
 
84
- def restore_streams
85
- $stdout = @orig_stdout
86
- $stderr = @orig_stderr
148
+ def self.find_methods(obj)
149
+ with_redirected_streams do
150
+ found = methods_to_try(obj).select { |met| yield(met) }
151
+ found.map { |m| "#{obj.method(m).owner}##{m}" }
87
152
  end
88
153
  end
89
- private_class_method :redirect_streams, :restore_streams
90
- end
154
+ private_class_method :find_methods
155
+
156
+ def self.with_redirected_streams
157
+ orig_stdout = $stdout
158
+ orig_stderr = $stderr
159
+ $stdout = StringIO.new
160
+ $stderr = StringIO.new
91
161
 
162
+ yield
163
+ ensure
164
+ $stdout = orig_stdout
165
+ $stderr = orig_stderr
166
+ end
167
+ private_class_method :with_redirected_streams
168
+
169
+ def self.select_ignorelist(object)
170
+ object.is_a?(Module) ? CLASS_METHOD_IGNORELIST : INSTANCE_METHOD_IGNORELIST
171
+ end
172
+ private_class_method :select_ignorelist
173
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MethodFinder
4
+ VERSION = '2.2.2'
5
+ end
metadata CHANGED
@@ -1,47 +1,121 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: methodfinder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
5
- prerelease:
4
+ version: 2.2.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Michael Kohl
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2011-12-18 00:00:00.000000000 Z
13
- dependencies: []
14
- description:
15
- email: citizen428@gmail.com
11
+ date: 2021-05-12 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.1.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.1.0
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.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.14'
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.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.0'
83
+ description: A Smalltalk-like Method Finder for Ruby with some extra features
84
+ email:
85
+ - citizen428@gmail.com
16
86
  executables: []
17
87
  extensions: []
18
88
  extra_rdoc_files: []
19
89
  files:
90
+ - CHANGELOG.md
91
+ - LICENSE.txt
92
+ - README.md
20
93
  - lib/methodfinder.rb
21
- - ./LICENSE
22
- - ./README.markdown
23
- homepage: https://github.com/citizen428/MethodFinder
24
- licenses: []
94
+ - lib/methodfinder/version.rb
95
+ homepage: http://citizen428.github.com/methodfinder/
96
+ licenses:
97
+ - MIT
98
+ metadata:
99
+ bug_tracker_uri: https://github.com/citizen428/methodfinder/issues
100
+ source_code_uri: https://github.com/citizen428/methodfinder
101
+ changelog_uri: https://github.com/citizen428/methodfinder/blob/master/CHANGELOG.md
25
102
  post_install_message:
26
103
  rdoc_options: []
27
104
  require_paths:
28
105
  - lib
29
106
  required_ruby_version: !ruby/object:Gem::Requirement
30
- none: false
31
107
  requirements:
32
- - - ! '>='
108
+ - - ">="
33
109
  - !ruby/object:Gem::Version
34
110
  version: '0'
35
111
  required_rubygems_version: !ruby/object:Gem::Requirement
36
- none: false
37
112
  requirements:
38
- - - ! '>='
113
+ - - ">="
39
114
  - !ruby/object:Gem::Version
40
115
  version: '0'
41
116
  requirements: []
42
- rubyforge_project:
43
- rubygems_version: 1.8.11
117
+ rubygems_version: 3.1.4
44
118
  signing_key:
45
- specification_version: 3
119
+ specification_version: 4
46
120
  summary: A Smalltalk-like Method Finder for Ruby
47
121
  test_files: []
data/README.markdown DELETED
@@ -1,138 +0,0 @@
1
- [![Build Status](https://secure.travis-ci.org/citizen428/methodfinder.png)](http://travis-ci.org/citizen428/methodfinder)
2
-
3
- (tested with MRI 1.8.7 and newer)
4
-
5
- Description
6
- ---
7
-
8
- This project was originally inspired by Smalltalk's Method Finder, but
9
- additonal features were added over time.
10
-
11
- Usage
12
- ---
13
-
14
- ### MethodFinder.find
15
-
16
- Provided with a receiver, the desired result and possibly some
17
- arguments, `MethodFinder.find` will list all methods that produce the
18
- given result when called on the receiver with the provided arguments.
19
-
20
- >> MethodFinder.find(10,1,3)
21
- => ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
22
- >> MethodFinder.find("abc","ABC")
23
- => ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
24
- >> MethodFinder.find(10,100,2)
25
- => ["Fixnum#**"]
26
- >> MethodFinder.find(['a','b','c'],['A','B','C']) { |x| x.upcase }
27
- => ["Array#collect", "Array#collect!", "Enumerable#collect_concat", "Enumerable#flat_map", "Array#map", "Array#map!"]
28
-
29
- ### Object#find_method
30
-
31
- This gem also adds `Object#find_method`, which besides offering an
32
- alternate interface to pretty much the same functionality as
33
- `MethodFinder.find`, also allows you to test for state other than
34
- the return value of the method.
35
-
36
- >> %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
37
- => ["Array#delete_at", "Array#slice!"]
38
- >> 10.find_method { |n| n.unknown(3) == 1 }
39
- => ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
40
-
41
- Inside `find_method`'s block, the receiver is available as block
42
- argument and the special method `unknown` is used as a placeholder for
43
- the desired method.
44
-
45
- You can also call `find_method` without passing a block. This is the
46
- same as calling `MethodFinder.find`.
47
-
48
- >> 10.find_method(1,3)
49
- => ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
50
-
51
- #### Blacklists
52
-
53
- You can exclude methods from being tried by editing the hashes
54
- `MethodFinder::INSTANCE_METHOD_BLACKLIST` and
55
- `MethodFinder::CLASS_METHOD_BLACKLIST`. Both use the class/module
56
- as key and an array of method names as values (note that class, module
57
- and method names have to be symbols).
58
-
59
- For example, to blacklist the instance method `shutdown` of `Object`,
60
- you would do
61
-
62
- MethodFinder::INSTANCE_METHOD_BLACKLIST[:Object] << :shutdown
63
-
64
- This might come in handy when using `MethodFinder` together with other
65
- gems as such as `interactive_editor`.
66
-
67
- ### MethodFinder.find\_classes\_and_modules
68
-
69
- A simple method to return all currently defined modules and classes.
70
-
71
- >> MethodFinder.find_classes_and_modules
72
- => [ArgumentError, Array, BasicObject, Bignum ... ZeroDivisionError]
73
-
74
- ### MethodFinder.find\_in\_class\_or_module
75
-
76
- Searches for a given name within a class. The first parameter can
77
- either be a class object, a symbol or a string whereas the optional
78
- second parameter can be a string or a regular expression:
79
-
80
- >> MethodFinder.find_in_class_or_module('Array', 'shuff')
81
- => [:shuffle, :shuffle!]
82
- >> MethodFinder.find_in_class_or_module(Float, /^to/)
83
- => [:to_f, :to_i, :to_int, :to_r, :to_s]
84
-
85
- If the second parameter is omitted, all methods of the class or module
86
- will be returned.
87
-
88
- >> MethodFinder.find_in_class_or_module(Math)
89
- => [:acos, :acosh, :asin ... :tanh]
90
-
91
- Warning
92
- ---
93
-
94
- Common sense not included!
95
-
96
- While I never had any problems with this, it's still better to be
97
- safe than sorry, so use this with caution and maybe not on production
98
- data.
99
-
100
- I initially wrote this for the students of the core Ruby course on
101
- [RubyLearning](http://rubylearning.org), so Rails is not of interest
102
- to me (not saying it doesn't work there, just that I test in plain
103
- IRB, not with `script/console`).
104
-
105
- Thanks
106
- ---
107
-
108
- * Matthew Lucas for [first packaging this as a gem](https://github.com/citizen428/methodfinder/pull/1).
109
- * Ryan Bates for
110
- [suggesting](https://github.com/citizen428/methodfinder/issues/closed#issue/3)
111
- what eventually became `Object#find_method`.
112
- * Jan Lelis for [implementing blacklists](https://github.com/citizen428/methodfinder/issues/closed#issue/4).
113
- * Brian Morearty for pointing out an
114
- [incompatibility with Ruby 1.8.7](https://github.com/citizen428/methodfinder/pull/5)
115
- and adding the [blockless version](https://github.com/citizen428/methodfinder/pull/6) of `Object#find_method`.
116
- * Stefan Kanev for [adding Pry support](https://github.com/citizen428/methodfinder/pull/7).
117
- License
118
- ---
119
-
120
- Copyright (c) 2011 Michael Kohl
121
-
122
- Permission is hereby granted, free of charge, to any person obtaining a copy
123
- of this software and associated documentation files (the "Software"), to deal
124
- in the Software without restriction, including without limitation the rights
125
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
126
- copies of the Software, and to permit persons to whom the Software is
127
- furnished to do so, subject to the following conditions:
128
-
129
- The above copyright notice and this permission notice shall be included in
130
- all copies or substantial portions of the Software.
131
-
132
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
133
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
134
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
135
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
136
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
137
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
138
- THE SOFTWARE.