methodfinder 1.2.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +107 -0
  3. data/lib/methodfinder.rb +72 -22
  4. metadata +13 -13
  5. data/README.markdown +0 -138
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1f711364eaf7e9772fcdba37d1080618579f7e6f
4
+ data.tar.gz: b9bdf0bbdd9c32b299a778fbc80747b9b157adc7
5
+ SHA512:
6
+ metadata.gz: 55acd3f55bb995667eca8053582cfb34f82a2f83c6a5bbd510ba473c5df15c08d0525ed6027b6d3cae433ac1b6b72912ac59e655055415dfa5656249d5a0ed4b
7
+ data.tar.gz: 0f445f405f1d393e8ad8e0338b46997faf89635e78fe3ad85c9a2630e2676956f0d9dbbc0d96542c18d1ec090f63184773b25276928f4ceada1016cf934989d3
@@ -0,0 +1,107 @@
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
+ == Warning
72
+
73
+ Common sense not included!
74
+
75
+ 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.
76
+
77
+ 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.
78
+
79
+ == Thanks
80
+
81
+ * Matthew Lucas for {first packaging this as a gem}[https://github.com/citizen428/methodfinder/pull/1].
82
+ * Ryan Bates for {suggesting}[https://github.com/citizen428/methodfinder/issues/closed#issue/3] what eventually became <tt>Object#find_method</tt>.
83
+ * Jan Lelis for {implementing blacklists}[https://github.com/citizen428/methodfinder/issues/closed#issue/4].
84
+ * 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>.
85
+ * Stefan Kanev for {adding Pry support}[https://github.com/citizen428/methodfinder/pull/7].
86
+
87
+ == License
88
+
89
+ Copyright (c) 2011 Michael Kohl
90
+
91
+ Permission is hereby granted, free of charge, to any person obtaining a copy
92
+ of this software and associated documentation files (the "Software"), to deal
93
+ in the Software without restriction, including without limitation the rights
94
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
95
+ copies of the Software, and to permit persons to whom the Software is
96
+ furnished to do so, subject to the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be included in
99
+ all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
102
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
103
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
104
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
105
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
106
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
107
+ THE SOFTWARE.
@@ -1,23 +1,43 @@
1
1
  require 'stringio'
2
2
 
3
3
  class Object
4
+ # An alternative interface to the functionality of
5
+ # <tt>MethodFinder.find</tt>. Also allows to test for state other
6
+ # than the return value of the method.
7
+ #
8
+ # %w[a b c].find_method { |a| a.unknown(1) ; a == %w[a c] }
9
+ # #=> ["Array#delete_at", "Array#slice!"]
10
+ # 10.find_method { |n| n.unknown(3) == 1 }
11
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
12
+ #
13
+ # Inside <tt>find_method</tt>'s block, the receiver is available as
14
+ # block argument and the special method <tt>unknown</tt> is used as
15
+ # a placeholder for the desired method.
16
+ #
17
+ # <tt>find_method</tt> can be called without passing a block. This
18
+ # is the same as calling <tt>MethodFinder.find</tt>.
19
+ #
20
+ # 10.find_method(1,3)
21
+ # #=> ["Fixnum#%", "Fixnum#<=>", "Fixnum#>>", "Fixnum#[]", "Integer#gcd", "Fixnum#modulo", "Numeric#remainder"]
22
+
4
23
  def find_method(*args, &block)
5
- if block_given?
24
+ if block
6
25
  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
26
+ self.class.class_eval("alias :unknown #{met}")
27
+ obj = self.dup rescue self # dup doesn't work for immutable types
28
+ block.call(obj) rescue nil
10
29
  end
11
- mets.map { |m| [self.method(m).owner, m].join("#") }
30
+ mets.map { |m| "#{self.method(m).owner}##{m}" }
12
31
  else
13
32
  MethodFinder.find(self, *args)
14
33
  end
15
34
  end
16
35
  end
17
36
 
18
- class MethodFinder
37
+ module MethodFinder
38
+ # Default arguments for methods
19
39
  ARGS = {
20
- :cycle => [1] # prevent cycling forever
40
+ cycle: [1] # prevent cycling forever
21
41
  }
22
42
 
23
43
  # Blacklisting methods, e.g. { :Object => [:ri, :vim] }
@@ -27,12 +47,26 @@ class MethodFinder
27
47
  INSTANCE_METHOD_BLACKLIST[:Object] << :find_method # prevent stack overflow
28
48
  INSTANCE_METHOD_BLACKLIST[:Object] << :gem # funny testing stuff w/ Bundler
29
49
 
30
- if defined? Pry
50
+ if defined?(Pry)
31
51
  INSTANCE_METHOD_BLACKLIST[:Object] << :pry
32
52
  CLASS_METHOD_BLACKLIST[:Object] << :pry
33
53
  end
34
54
 
35
55
  class << self
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
+
36
70
  def find(obj, res, *args, &block)
37
71
  redirect_streams
38
72
 
@@ -44,28 +78,33 @@ class MethodFinder
44
78
  m.call(*a, &block) == res rescue nil
45
79
  end
46
80
  end
47
- mets.map { |m| [obj.method(m).owner, m].join("#") }
81
+ mets.map { |m| "#{obj.method(m).owner}##{m}" }
48
82
  ensure
49
83
  restore_streams
50
84
  end
51
85
 
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
57
-
58
- klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
59
-
60
- # 1.8.7 lacks Symbol#<=>
61
- ret.sort_by(&:to_s)
62
- end
63
-
86
+ # Returns all currently defined modules and classes.
64
87
  def find_classes_and_modules
65
88
  constants = Object.constants.sort.map { |c| Object.const_get(c) }
66
89
  constants.select { |c| c.class == Class || c.class == Module}
67
90
  end
68
91
 
92
+ # Searches for a given name within a class. The first parameter
93
+ # can either be a class object, a symbol or a string whereas the
94
+ # optional second parameter can be a string or a regular
95
+ # expression:
96
+ #
97
+ # MethodFinder.find_in_class_or_module('Array', 'shuff')
98
+ # #=> [:shuffle, :shuffle!]
99
+ # MethodFinder.find_in_class_or_module(Float, /^to/)
100
+ # #=> [:to_f, :to_i, :to_int, :to_r, :to_s]
101
+ #
102
+ # If the second parameter is omitted, all methods of the class or
103
+ # module will be returned.
104
+ #
105
+ # MethodFinder.find_in_class_or_module(Math)
106
+ # #=> [:acos, :acosh, :asin ... :tanh]
107
+
69
108
  def find_in_class_or_module(c, pattern=/./)
70
109
  cs = Object.const_get(c.to_s)
71
110
  class_methods = cs.methods(false) rescue []
@@ -74,6 +113,18 @@ class MethodFinder
74
113
  all_methods.grep(/#{pattern}/).sort
75
114
  end
76
115
 
116
+ # Returns a list of candidate methods for a given object. Added by Jan Lelis.
117
+ def methods_to_try(obj)
118
+ ret = obj.methods
119
+ blacklist = obj.is_a?(Module) ? CLASS_METHOD_BLACKLIST : INSTANCE_METHOD_BLACKLIST
120
+ klass = obj.is_a?(Module) ? obj : obj.class
121
+
122
+ klass.ancestors.each { |ancestor| ret -= blacklist[ancestor.to_s.intern] }
123
+
124
+ ret.sort
125
+ end
126
+
127
+ # :nodoc:
77
128
  def redirect_streams
78
129
  @orig_stdout = $stdout
79
130
  @orig_stderr = $stderr
@@ -88,4 +139,3 @@ class MethodFinder
88
139
  end
89
140
  private_class_method :redirect_streams, :restore_streams
90
141
  end
91
-
metadata CHANGED
@@ -1,17 +1,16 @@
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.0.0
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
11
+ date: 2013-11-06 00:00:00.000000000 Z
13
12
  dependencies: []
14
- description:
13
+ description: A Smalltalk-like Method Finder for Ruby with some extra features
15
14
  email: citizen428@gmail.com
16
15
  executables: []
17
16
  extensions: []
@@ -19,29 +18,30 @@ extra_rdoc_files: []
19
18
  files:
20
19
  - lib/methodfinder.rb
21
20
  - ./LICENSE
22
- - ./README.markdown
23
- homepage: https://github.com/citizen428/MethodFinder
24
- licenses: []
21
+ - ./README.rdoc
22
+ homepage: http://citizen428.github.com/methodfinder/
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
25
26
  post_install_message:
26
27
  rdoc_options: []
27
28
  require_paths:
28
29
  - lib
29
30
  required_ruby_version: !ruby/object:Gem::Requirement
30
- none: false
31
31
  requirements:
32
- - - ! '>='
32
+ - - '>='
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  required_rubygems_version: !ruby/object:Gem::Requirement
36
- none: false
37
36
  requirements:
38
- - - ! '>='
37
+ - - '>='
39
38
  - !ruby/object:Gem::Version
40
39
  version: '0'
41
40
  requirements: []
42
41
  rubyforge_project:
43
- rubygems_version: 1.8.11
42
+ rubygems_version: 2.0.3
44
43
  signing_key:
45
- specification_version: 3
44
+ specification_version: 4
46
45
  summary: A Smalltalk-like Method Finder for Ruby
47
46
  test_files: []
47
+ has_rdoc:
@@ -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.