How to find all methods available in Smalltalk and search by name?
Asked Answered
E

4

5

In Smalltalk, is there a way to search for all methods available (of any object), say, that contain the word convert (case insensitive search), and also contain the word string? (the method name, not the source code)

Emir answered 20/12, 2015 at 17:32 Comment(4)
Can you tell us which dialect you are using?Antinomian
hm... preferably a more standard way of doing it... otherwise... GNU Smalltalk, Dolphin, Squeak, or PharoEmir
By "contain" you mean in the method's source code, or the method's name?Munda
method's name... added to the questionEmir
M
9

In Smalltalk you have direct access to all classes, their methods and their source code, so you can go through them.

Pharo

Go over all the classes and then from each class select all methods that match your needs (or use the Finder tool).

Object withAllSubclasses flatCollect: [ :cls |
    cls methods select: [ :method |
        (method selector includesSubstring: 'convert' caseSensitive: false) and: [
        (method selector includesSubstring: 'string' caseSensitive: false) ]
    ]
].

GNU Smalltalk

GST doesn't have as nice API, but it can be done also.

(Object withAllSubclasses collect: [ :cls |
    cls methodDictionary ifNotNil: [ :dict |
        dict values select: [ :method |
            (method selector asLowercase indexOfSubCollection: 'convert' asLowercase) > 0 and: [
            (method selector asLowercase indexOfSubCollection: 'string' asLowercase) > 0 ]
        ]
    ]
]) join

VisualWorks

(also Pharo and Squeak, and with ifNotNil: also GNU Smalltalk)

VW doesn't have #flatten, so it's implemented explicitly. For case-insensitive search #findSameAs:startingAt:wildcard: can also be used.

(Object withAllSubclasses collect: [ :cls |
    cls methodDictionary values select: [ :method |
        (method selector asLowercase findString: 'convert' asLowercase startingAt: 1) > 0 and: [
        (method selector asLowercase findString: 'string' asLowercase startingAt: 1) > 0 ]
    ]
]) inject: #() into: [ :arr :each | arr, each ]

Dolphin

Dolphin seems to have different object model, see Leandro's answer below.

Munda answered 20/12, 2015 at 18:41 Comment(14)
can it be done by something like Object withAllSubclasses map [allMethods] inject [concatArray] contain 'keyword' contain 'keyword2' (this is just pseudocode)Emir
#collect: is the smalltalk equivalent of map, however I am not sure what you mean by [concatArray]. What are you adding there?Munda
get all arrays, add them up to form one big array... (is it inject or can you just use some kind of join)Emir
I've added alternative code to the answer, is this what you had in mind? Always having it as a single collection and then applying filters on it?Munda
so i see... kind of wanted to do it in one line. what i meant by inject is like in Ruby [[1,3,5], [2,4,6], ["hello", "world"]].inject(:concat) => [1, 3, 5, 2, 4, 6, "hello", "world"] Interesting... I think I can understand inject better than before: it is like to inject an operator in between the elements: [1,3,5].inject(:+) => 9 and [1,3,5].inject(:-) => -7Emir
Smalltalk has inject:into:, that is equivalent to ruby's inject(initial) { |memo, obj| block }. So you could use that to concat collections... e.g. #(#(1 3 5) #(2 4 6) #('hello' 'world')) inject: OrderedCollection new into: [ :injected :next | injected addAll: next; yourself ]. (it's bit more heavy handed, but normally you would flatten it with #(#(1 3 5) #(2 4 6) #('hello' 'world')) flattened)Munda
Peter, I think that your code is not looking at class methods.Knotting
@LeandroCaniglia why wouldn't it? Class is an Object.Munda
The enumeration you get from #withAllSubclasses will visit only classes, not metaclasses. Therefore the methodDictionaries your code will select from will correspond to methods in the instance side of each class.Knotting
@LeandroCaniglia How so? It will include all subclasses of Object, which means also metaclasses (because in Smalltalk everything is Object). Try String class isKindOf: Object or Object withAllSubclasses includes: String class.Munda
This is interesting. In Pharo #withAllSubclasses also includes the metaclasses (I didn't know that.) It looks like this is a dialect-dependent behavior. In some dialects (e.g., Dolphin) only classes (and not metaclasses) are collected by #withAllSubclasses.Knotting
I've tested it in Pharo and GNU Smalltalk. If Dolphin behaves differently I question their decision for reasons explained above (everything should be an Object).Munda
if anybody can provide one that works on VisualWorks... I think for example, the :cls does not work thereEmir
@太極者無極而生 I've added VW example (which also works in other dialects). Note that [ :cls | ... ] is a regular BlockClosure syntax supported by all mentioned dialects, including VW.Munda
F
2

This may not work on all smalltalk dialects, but it works at least with squeak and pharo (other smalltalks may have similar tools/classes)

SystemNavigation default browseAllSelect:[:e |
(e selector includesSubstring:'convert' caseSensitive:false)
    and:[e selector includesSubstring:'string' caseSensitive:false]]
Fission answered 22/12, 2015 at 9:34 Comment(0)
K
1

This is more a complement to the answer given by @Peter.

Be aware that in some dialects (e.g., Dolphin) the message #withAllSubclasses will only collect classes, and not metaclasses. Because of that the enumerations in @Peter's answer should add all metaclasses in an explicit way.

For instance,

selectors := OrderedCollection new.
Object withAllSubclasses do: [:class | | matching |
  matching := class selectors select: [:s |
    (s includesString: 'onvert') and: [s includesString: 'tring']].
  selectors addAll: matching.
  matching := class class selectors select: [:s |
    (s includesString: 'onvert') and: [s includesString: 'tring']].
  selectors addAll: matching].
^selectors

Note BTW that I've removed the first letter from both 'convert' and 'string' to cheaply prevent case mismatches.

Another difference with my code is that it iterates over the selectors of a class rather than over its methods.

UPDATE

Note that I've used two enumerations because we cannot do this:

class selectors , class class selectors select: [:s |

etc. The reason is that the selectors of a class come in a Set and these do not understand #,.

We could have done instead:

all := class selectors addAll: class class selectors; yourself.
all selectors select: [:s |

etc. (note the use of #yourself)

Knotting answered 21/12, 2015 at 15:9 Comment(2)
Wouldn't Object withAllSubclasses, Class withAllSubclasses work also? (So then the matching would be done on a single collection)Munda
@Peter I'm afraid no. The class Class has no subclasses. It has no instances either! The only reason for Class to exist is as a mean to put behavior common to all classes (but not to metaclasses)Knotting
L
0

This is to add different flavor to the list above.

@Smalltalk/X

Object withAllSubclasses flatCollect: [ :cls |
    cls methodDictionary values select: [ :method |
        (method selector includesSubstring: 'convert' caseSensitive: false) and: [
        (method selector includesSubstring: 'string' caseSensitive: false) ]
    ]
].               
Lumberjack answered 25/1, 2022 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.