メソッド名一覧の表示
Posted feedbacks - Nested
Flatten Hidden1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import types
class A:
def __init__(self):
self.bar = 0
self.test_bar = 1
self.baz = []
self.test_baz = {}
def foo(self):
print "foo"
def test_foo(self):
print "test_foo"
def boo(self):
print "boo"
def test_boo(self):
print "test_boo"
def call_tests(obj):
for name in dir(obj):
if name.startswith("test_"):
attr = getattr(obj, name)
if isinstance(attr, types.MethodType):
attr()
def main():
call_tests(A())
if __name__ == '__main__':
main()
|
上のコードをJavaScriptに移植。IE6とFirefox2で動作確認。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | function A()
{
this.bar = 1;
this.test_bar = 2;
this.baz = [];
this.test_baz = {};
}
A.prototype.foo = function()
{
alert("foo");
}
A.prototype.test_foo = function()
{
alert("test_foo");
}
A.prototype.boo = function()
{
alert("boo");
}
A.prototype.test_boo = function()
{
alert("test_boo");
}
function call_tests(obj)
{
for (var name in obj)
{
var attr = obj[name];
if (attr instanceof Function && name.indexOf("test_") == 0)
{
attr();
}
}
}
call_tests(new A());
|
1 2 3 4 5 6 7 8 9 | class Foo
private; def test_foo() puts("test_foo_private") end
public; def test_foo2() puts("test_foo_public") end
protected; def test_fuga() puts("test_fuga") end
public; def public_foo() puts("public_foo") end
end
obj = Foo.new
["methods","private_methods"].collect{|m| obj.send(m).grep(/^test_/)}.flatten.each{|m| obj.instance_eval m}
|
1 | info commands target::test_*
|
呼び出すって実行するところまでだと気づいたので修正。引数はなしで。
1 | foreach cmd [info commands target::test_*] { $cmd }
|
Common Lispのメソッドはクラス内の概念ではないので「複数の関数への参照を持っているようなオブジェクト(たとえばパッケージとかモジュールとか)から"test_"で始まる関数をすべて呼び出す」
関数名はLisp的にはtest-なんだけどね~
1 2 3 4 5 6 7 | (require :cl-ppcre)
(defun test_1 () 1)
(defun test_2 () 2)
(defun test_3 () 3)
(loop for f in (ppcre:regex-apropos-list "^test_" *package*)
collect (cons f (funcall f))) ; => ((TEST_1 . 1) (TEST_3 . 3) (TEST_2 . 2))
|
変数の定義でもシンボルはインターンされるので fboundp を。ついでに大文字小文字を区別する別回答。
funcall は関数を探しにいきますので symbol-function は不要ですがなんとなく。
1 2 3 4 | (defun call-test (pakcage)
(do-symbols (symbol pakcage)
(when (and (fboundp symbol) (ppcre:scan "^test_" (symbol-name symbol)))
(format t "~A => ~A~%" symbol (funcall (symbol-function symbol))))))
|
ぎゃぁ、fboundpが抜けてたorzorzorz
1 2 3 4 5 6 7 8 9 | (require :cl-ppcre)
(defun test_1 () 1)
(defun test_2 () 2)
(defun test_3 () 3)
(defparameter test_var 0)
(loop for f in (ppcre:regex-apropos-list "^test_" *package*)
when (fboundp f)
collect (cons f (funcall f))) ; => ((TEST_1 . 1) (TEST_3 . 3) (TEST_2 . 2))
|
get_class_methods関数を使うと簡単にメソッド一覧を取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php
class Doukaku
{
function Doukaku()
{
}
function test_Doukaku()
{
}
function hello()
{
print("hello world!");
}
function test_hello()
{
}
}
$doukaku = new Doukaku();
$result = array();
foreach (get_class_methods($doukaku) as $method) {
if (strpos($method, "test_") === 0) {
$result[] = $method;
}
}
var_dump($result);
?>
|
実行するとこが抜けてたorz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php
class Doukaku
{
function php()
{
print("php\n");
}
function test_php()
{
print("test_php\n");
}
function hello()
{
print("hello\n");
}
function test_hello()
{
print("test_hello\n");
}
}
$doukaku = new Doukaku();
$result = array();
foreach (get_class_methods($doukaku) as $method) {
if (strpos($method, "test_") === 0) {
$doukaku->$method();
}
}
?>
|
環境選びますがfnmatchとかいかがざんすか?
1 2 3 4 5 | foreach (get_class_methods($doukaku) as $method) {
if (fnmatch("test_*", $method)) {
$doukaku->$method();
}
}
|
setAccessibleしないといけないのがなんとも。
1 2 3 4 5 6 7 8 9 10 | class Foo {
private def test_foo = println("test_foo_private")
def test_foo2 = println("test_foo_public")
protected def test_fuga = println("test_fuga")
def public_foo = println("public_foo")
}
val foo = new Foo
foo.getClass.getDeclaredMethods.filter(_.getName.startsWith("test_"))
.map(x=>{x.setAccessible(true);x}).foreach(_.invoke(foo,Array()))
|
inspect モジュールの出番。
classmethod も呼んでしまうのはどうにかならんかな。
1 2 3 4 5 | import inspect
def call_tests(target):
methods = [method for name, method in inspect.getmembers(target, inspect.ismethod) if name.startswith('test_')]
for method in methods: method()
|
Pythonのクラスメソッドはあくまで 「呼んだときに第一引数にクラスオブジェクトが渡されるメソッド」 というだけなので、 単純に「xのメソッド」と言った場合には classmethodやstaticmethodでラップしてあるメソッドも含まれるわけです。 なのでもしそれらを省きたければim_selfがインスタンス自身かどうかをチェックすればいいと思います。 下のコードならばtest_methodだけが呼ばれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import inspect
class Foo():
@classmethod
def test_classmethod(cls):
print cls
@staticmethod
def test_staticmethod(x):
print x
def test_method(self):
print self
target = Foo()
for name, method in inspect.getmembers(target):
if inspect.ismethod(method):
if method.im_self == target:
print "call", name
method()
|
気づいたのですが、同一性の判定には、 if method.im_self is target: のように ==よりisを使った方がいいかもしれません。
なるほど、たしかに__eq__がオーバーライドされて同じインスタンスではなくてもTrueを返すようになっている可能性があるので==で判定してはダメですね。
おぉ。なるほど。と、おもったら、im_self をチェックするというのネタを以前自分のブログに書いていた orz
それはそれとして、「x のメソッド」と表現したときに、メッセージのレシーバが x でないものを含めるかどうかというのはなかなか微妙な話かもしれない。
微妙な話ですね。 「単純に「xのメソッド」と言った場合には classmethodやstaticmethodで ラップしてあるメソッドも含まれる」 というのは言い過ぎだったかも。 「メソッド」という言葉がの定義と、 classmethodやstaticmethodの実装を 追わないと正確なことは言えなかったですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import java.lang.reflect.Method;
public class TestMethods {
public static void test(Object target) {
Class targetClass = target.getClass();
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("test_")) {
try {
method.invoke(target);
}
catch (Exception e) {}
}
}
}
public static void main(String[] args) {
test(new Test());
}
}
class Test {
public void test_public() {
System.out.println("public method");
}
protected void test_protected() {
System.out.println("protected method");
}
void test_package_private() {
System.out.println("package private method");
}
private void test_private() {
System.out.println("private method");
}
}
|
setAccessible(true);
が抜けているので、 private メソッドを実行すると IllegalAccessException が発生すると思います。
もっとも、Exception を握りつぶしていらっしゃるので、実行結果からは private メソッドがスルーされているように見えますが。
Squeak Smalltalk で。
1 | target class selectors select: [:sel | sel beginsWith: #test]
|
スーパークラス定義のメソッドを考慮するのをすっかり 忘れていました(^_^;)。 ということで改めて。
1 | target class allSelectors select: [:sel | sel beginsWith: #test]
|
以下の特徴を持つ。 ・call_tests()の第一引数にはクラスとインスタンスのどちらでも渡せる。 ・ベースクラスのメソッドも呼ぶか、指定したクラスのみのメソッドしか呼ばないかを指定可能。 ・staticmethodを呼ぶかどうかを指定可能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | import types
class A:
a1 = 1
test_a1 = 1
def __init__(self):
self.a2 = 2
self.test_a2 = 2
def a3(self):
print "a3 called!"
def test_a3(self):
print "test_a3 called!"
class B(A):
def b1(self):
print 'b1 called!'
def test_b1(self):
print 'test_b1 called!'
@staticmethod
def test_b2():
print 'test_b2 called!'
def call_tests(obj, single_level=False, call_static=True):
if isinstance(obj, types.InstanceType):
cls = obj.__class__
elif isinstance(obj, types.ClassType):
cls = obj
obj = obj() # obj is bound to instance object.
else:
return
# make dict of attributes
names = cls.__dict__
for base in cls.__bases__:
names.update(base.__dict__)
if single_level:
for base in cls.__bases__:
for name in base.__dict__:
if hasattr(base, name):
del names[name]
for name in sorted(names):
if name[:5] == 'test_':
if call_static:
try:
getattr(obj, name)() # EAFP
except:
continue
else:
f = names[name]
if callable(f):
f(obj)
if __name__ == '__main__':
call_tests(B, 0, 0)
print '==='
call_tests(B, 1, 0)
print '==='
call_tests(B, 0, 1)
print '==='
call_tests(B, 1, 1)
# output:
# test_a3 called!
# test_b1 called!
# ===
# test_b1 called!
# ===
# test_a3 called!
# test_b1 called!
# test_b2 called!
# ===
# test_b1 called!
# test_b2 called!
|
以下を修正。 ・cls.__bases__で、1つ上の階層のベースクラスしかとれていなかったので、再帰的にベースクラスを探すようにした。 ・継承階層で同じ名称のメソッドをオーバーライドしていた場合、一番子供側のメソッドを呼び出すようにした。 ・新型クラスに対して、 isinstance(obj, types.InstanceType) と isinstance(obj, types.ClassType) の 両方ともFalseになってしまって対応していなかったので対応した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | def call_tests(obj, single_level=False, call_static=True):
if hasattr(obj, '__bases__'):
# class object
cls = obj
obj = obj() # obj is bound to instance object.
else:
if not hasattr(obj, '__class__'): return # non class type
# instance object
cls = obj.__class__
# make dict of attributes
bases = []
def base_classes(cls):
if cls.__bases__:
bases.extend(cls.__bases__)
for base in cls.__bases__:
base_classes(base)
base_classes(cls)
names = {}
names.update(cls.__dict__)
for base in bases:
for attr, val in base.__dict__.items():
if not names.has_key(attr):
names[attr] = val
if single_level:
for base in bases:
for name in base.__dict__:
if names.has_key(name):
del names[name]
# call function of attributes
for name in sorted(names):
if name[:5] == 'test_':
if call_static:
f = getattr(obj, name)
if callable(f): f()
else:
f = names[name]
if callable(f): f(obj)
|
すみません。PrologとPythonの言語の選択間違えました(;_;)。にしおさん、修正お願いします。
だいぶ言語が増えてきたので選びづらいですよね。JavaScriptとかで 今までに投稿したことのある言語を簡単に選べるようにしようとは思いつつ まだできていません。
引数つきのメソッドでも呼び出せるようにしてみました。プリミティブ型なら 0(または false)、参照型なら null を渡すようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import java.lang.reflect.Method;
public class Sample {
public static void callTest(Object target) throws Exception {
Class c = target.getClass();
Method[] ms = c.getMethods();
for (int i = 0; i < ms.length; i++) {
if (ms[i].getName().startsWith("test_")) {
Class[] argTypes = ms[i].getParameterTypes();
Object[] args = new Object[argTypes.length];
for (int j = 0; j < argTypes.length; j++) {
if (argTypes[j] == Character.TYPE) {
args[j] = Character.valueOf((char) 0);
} else if (argTypes[j] == Boolean.TYPE) {
args[j] = Boolean.valueOf(false);
} else if (argTypes[j].isPrimitive()) {
args[j] = Byte.valueOf((byte)0);
} else {
args[j] = null;
}
}
ms[i].invoke(target, args);
}
}
}
public void test_1(int i) {
System.out.println("test_1 called");
}
private int test_2() {
System.out.println("test_2 called");
return 0;
}
public static void test_3(char c) {
System.out.println("test_3 called");
}
public void test_4(byte by, boolean b, short s, String str, double d) {
System.out.println("test_4 called");
}
public static void main(String[] args) throws Exception {
callTest(new Sample());
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using System;
using System.Reflection;
class Program
{
class Test
{
void test_1() { Console.WriteLine("1"); }
static void test_2() { Console.WriteLine("2"); }
}
static void Main()
{
CallTest(new Test());
}
static void CallTest(object o)
{
foreach (MethodInfo mi in o.GetType().GetMethods(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
if (mi.Name.StartsWith("test_")) mi.Invoke(o, new object[0]);
}
}
|
題意の解釈によって色々書き方があると思いますが、一例として。
1 2 3 4 5 6 7 8 9 10 | obj <- list(
test_f1 = function(){ print("f1") }, # OK
text_f2 = function(){ print("f2") }, # NG
txet_f3 = function(){ print("f3") }, # NG
tesx_f4 = function(){ print("f4") }, # NG
test_f5 = function(){ print("f5") }, # OK
test_f6 = "f6" # NG (not a function)
)
dummy <- sapply(obj[grep("^test_", names(obj))], function(f){if(is.function(f)) f()})
|
もう少し題意を反映した感じで書いてみました。 Rのメソッドは、初めにgenericなメソッドを定義した後 「generic method名.クラス名」という形式で定義します。 generic methodを実行すると、第一引数のクラスによって 適切なメソッドが実行されます。 > test_f1(target) [1] "f1"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # define generic methods
test_f1 <- function(x){ UseMethod("test_f1") }
text_f2 <- function(x){ UseMethod("text_f2") }
txet_f3 <- function(x){ UseMethod("txet_f3") }
tesx_f4 <- function(x){ UseMethod("tesx_f4") }
test_f5 <- function(x){ UseMethod("test_f5") }
# define class and object
setClass("doukaku", representation(x ="numeric", y="numeric"))
target <- new("doukaku", x=1, y=2)
# define methods
test_f1.doukaku <- function(x){ print("f1") } # OK
text_f2.doukaku <- function(x){ print("f2") } # NG
txet_f3.doukaku <- function(x){ print("f3") } # NG
tesx_f4.doukaku <- function(x){ print("f4") } # NG
test_f5.doukaku <- function(x){ print("f5") } # OK
dummy <- sapply(grep("^test_", methods(class=attr(target, "class")), value=TRUE),
(function(x) do.call(x, c(target))))
|
C言語にメソッドはないので共有ライブラリの関数を列挙し、呼び出すようにしました。 1. 共有ライブラリをコンパイルします。 % gcc --shared call_tests.c -o tests.so 2. 本体をコンパイルします。 % gcc call_tests.c -o call_tests -ldl -lbfd 3. 実行します % ./call_tests ./tests.so hello2 hello1 hello3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <bfd.h>
void test_hello1()
{
printf("hello1\n");
}
void test_hello2()
{
printf("hello2\n");
}
void test_hello3()
{
printf("hello3\n");
}
int main(int argc, char *argv[]){
void *handle;
void (*func)();
bfd *abfd;
asymbol *store;
int symcount;
void *minisyms;
size_t size;
int i;
bfd_byte *from, *fromend;
asymbol *sym;
const char *name;
if(argc < 2) return EXIT_FAILURE;
handle = dlopen(argv[1], RTLD_LAZY);
if(!handle) return EXIT_FAILURE;
abfd = bfd_openr(argv[1], NULL);
if(!abfd) return EXIT_FAILURE;
bfd_check_format(abfd, bfd_object);
store = bfd_make_empty_symbol(abfd);
symcount = bfd_read_minisymbols(abfd, 0, &minisyms, &size);
from = (bfd_byte *)minisyms;
fromend = from + symcount * size;
for (; from < fromend; from += size){
sym = bfd_minisymbol_to_symbol(abfd, 0, from, store);
if(sym->flags != (BSF_FUNCTION | BSF_GLOBAL)) continue;
name = bfd_asymbol_name(sym);
if(strncmp(name, "test_", 5)) continue;
func = dlsym(handle, name);
func();
}
bfd_close(abfd);
dlclose(handle);
return EXIT_SUCCESS;
}
|
GaucheではCommonLispと同様に、メソッドはクラスでなく総称関数に所属します。 ここではモジュールの中から探してみることにします。 使い方の例: (define-module foo (define (test_1) (print 1)) (define (test_2) (print 2)) (define test_3 "I'm variable!") (define (test_4) (print 4))) (call-tests (find-module 'foo))
1 2 3 4 5 6 7 | (define (call-tests module)
(hash-table-for-each (module-table module)
(lambda (k v)
(and-let* ([ (#/^test_/ (x->string k)) ]
[val (global-variable-ref module k)]
[ (procedure? val) ])
(val)))))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Object
def call_test(prvt = false)
test_methods = self.methods.grep(/\Atest_/)
test_methods += self.private_methods.grep(/\Atest_/) if prvt
test_methods.each{|method|
yield method, self.__send__(method)
}
end
end
if $0 == __FILE__
class Sample
def test_a
true
end
end
o = Sample.new
o.call_test{|m, r|
puts "#{m} #{r}"
}
end
|
CPANだよりですが。。。^^;
1 2 3 4 5 6 7 8 9 | #!/usr/local/bin/perl
use target;
use Class::Inspector;
foreach my $f (@{(Class::Inspector->functions( 'target' ))[0]}) {
print eval{target->$f()} if ($f =~ /^test_.+$/);
}
exit;
|
Class::Inspector, Scalar::Util使用版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/usr/bin/perl
package Foo;
{
no strict 'refs';
for my $method (qw/foo bar baz test_foo test_bar test_baz/) {
*{"Foo::$method"} = sub {
print $method . "\n";
};
}
}
sub new {
bless {} => shift;
}
package main;
use strict;
use warnings;
use Scalar::Util qw(blessed);
use Class::Inspector;
sub call_methods_by_regex {
my ($target, $regex) = @_;
return unless (my $class = blessed($target));
return unless (ref $regex eq 'Regexp');
my @methods = grep { /$regex/o } @{Class::Inspector->methods($class, 'public')};
for my $method (@methods) {
$target->$method();
}
}
call_methods_by_regex(Foo->new, qr/^test_/);
|
CPANに頼らない版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #!/usr/bin/perl
package Foo;
{
no strict 'refs';
for my $method (qw/foo bar baz test_foo test_bar test_baz/) {
*{"Foo::$method"} = sub {
print $method . "\n";
};
}
}
sub new {
bless {} => shift;
}
package main;
use strict;
use warnings;
{
no strict 'refs';
sub call_methods_by_regex {
my ($target, $regex) = @_;
my $class = ref $target;
return if (!$class || $class =~ /^(SCALAR|ARRAY|HASH|CODE|GLOB|LVALUE)$/);
return unless (ref $regex eq 'Regexp');
my @methods =
grep { *{${$class . "::"}{$_}}{CODE} }
grep { /$regex/o }
keys %{$class . "::"};
for my $method (@methods) {
$target->$method();
}
}
}
call_methods_by_regex(Foo->new, qr/^test_/);
|
いけるのはpublishedで宣言されたもののみです。 ちなみにお題のタイトルのようにメソッド名一覧を表示する場合は、 Pos関数内で使ってるPShortString(...)^をWritelnしてやればOKです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | program EnumMethodNames;
{$APPTYPE CONSOLE}
type
THoge = class(TObject)
published
procedure test_foo;
end;
THogeEx = class(THoge)
published
procedure test_bar;
procedure foobar;
end;
THogeMethod = procedure of object;
procedure THoge.test_foo;
begin
Writeln('foo');
end;
procedure THogeEx.test_bar;
begin
Writeln('bar');
end;
procedure THogeEx.foobar;
begin
Writeln('foobar');
end;
procedure EnumMethods(target: TObject);
var
ref: TClass;
table: PChar;
count: Word;
method: TMethod;
begin
ref := target.ClassType;
while ref <> nil do begin
table := PPointer(PChar(ref) + vmtMethodTable)^;
if Assigned(table) then begin
count := PWord(table)^;
Inc(table, SizeOf(Word));
while count > 0 do begin
if Pos('test_', PShortString(table+SizeOf(Word)+SizeOf(Pointer))^) = 1 then begin
method.Code := PPointer(table+SizeOf(Word))^;
method.Data := target;
THogeMethod(method);
end;
Inc(table, PWord(table)^);
Dec(count);
end;
end;
ref := ref.ClassParent;
end;
end;
var
Hoge: THoge;
begin
Hoge := THogeEx.Create;
try
EnumMethods(Hoge);
finally
Hoge.Free;
end;
end.
|
コンパイルには -package ghc が必要。 引数で指定されたモジュールが export し、且つ test_ で始まる全部の IO モナドを実行する。 型は IO () でなければならず、そうでないものが存在したら実行時エラーになる。 GHC 6.6.1 以外の GHC を使う場合は ghcLibDir の値を訂正する事。 % ghc --make Main -package ghc % ./Main Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import qualified GHC
import qualified DynFlags
import qualified Name
import Data.List
import System
{-
例: Test.hs
module Test where
test_foo :: IO ()
test_foo = putStrLn "called test_foo"
test_bar :: IO ()
test_bar = putStrLn "called test_bar"
% ghc --make Test -package-name test
% ar cqs libHSTest.a Test.o
% ld -r --whole-archive -o HSTest.o libHSTest.a (MacOS X 以外の場合)
% ld -r -all_load -o HSTest.o libHSTest.a (MacOS X の場合)
-}
ghcLibDir :: String
ghcLibDir = "/usr/local/lib/ghc-6.6.1" -- % ghc --print-libdir
main = GHC.defaultErrorHandler DynFlags.defaultDynFlags $
do [modName] <- getArgs
session <- GHC.newSession GHC.Interactive (Just ghcLibDir)
f0 <- GHC.getSessionDynFlags session
GHC.setSessionDynFlags session f0 { GHC.hscTarget = GHC.HscInterpreted }
t <- GHC.guessTarget modName Nothing
GHC.addTarget session t
f <- GHC.getSessionDynFlags session
sf <- GHC.defaultCleanupHandler f (GHC.load session GHC.LoadAllTargets)
case sf of
GHC.Failed
-> fail "Failed to load the module!"
GHC.Succeeded
-> do self <- GHC.findModule session (GHC.mkModuleName modName) Nothing
runNullaryIOMonads session self (any (== "test_") . inits)
runNullaryIOMonads :: GHC.Session -> GHC.Module -> (String -> Bool) -> IO ()
runNullaryIOMonads session self f
= do Just modInfo <- GHC.getModuleInfo session self
let allFuncs = map Name.getOccString $ GHC.modInfoExports modInfo
selectedFuncs = filter f allFuncs
GHC.setContext session [self] []
mapM_ run selectedFuncs
where
run :: String -> IO ()
run fName
= GHC.runStmt session (fName ++ " :: IO ()")
>> return ()
|
1 2 3 4 5 6 7 8 9 10 11 | class Foo {
test_foo(){println("test_foo")}
test_foo2(){println("test_foo2")}
test_foo3(){println("test_foo3")}
public_foo(){println("public_foo")}
}
f = Foo()
for(m:f.class.methods[{m->m.name.startsWith("test_")}]){
m.invoke(f, [])
}
|
1 2 3 | $target | get-member |
where { $_.name -like "test_*" } |
foreach { invoke-expression ("`$target." + $_.name + "()") }
|
誰でも思いつく単純な回答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class Target
def test_foo
p "foo"
end
def test_bar
p "bar"
end
def test_baz
p "baz"
end
def not_test
p "not test!!"
end
end
#=> nil
target = Target.new
#=> #<Target:0x107d1d0>
target.methods.grep(/^test_.*$/).each {|i| target.__send__ i }
"baz"
"foo"
"bar"
#=> ["test_baz", "test_foo", "test_bar"]
|
引数0で。
see: 型に指定した名前のメンバがあるか調べる
1 2 3 4 5 | Public Sub CallMethods(ByVal obj As Object)
For Each m As MethodInfo In obj.GetType.GetMember("test_*", MemberTypes.Method, BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Static)
m.Invoke(obj, Nothing)
Next
End Sub
|
指定された *.awk ファイルをサーチして、 test_XXX という関数をすべて実行するような .awk ファイルを作り、 その .awk ファイルを実行します。 対象にするのは、 ^function +test_.* というパターンにマッチする関数定義だけです。 ex) > gawk -f testrunner.awk *.awk test_XXX をすべて呼び出すために、_tmp_runner.awk というファイルを 生成します。このファイルは削除せず残します。 _tmp_runner.awk と同時に、test_XXX が含まれていた .awk ファイルをすべて、 読み込みます。それ以外の .awk ファイルは読みません。 このあたりの仕様は、実用性を考えると検討したほうがいいかも。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | BEGIN {
TMPFILE = "_tmp_runner.awk"
awk_cmd = ARGV[0]
targets = " "
print "BEGIN {" > TMPFILE
}
/^function +test_.*\(/ {
fname = gensub(/^function +(test_[^(]*)\(.*$/, "\\1", "")
printf "\t%s()\n", fname >> TMPFILE
if(index(targets, " -f " FILENAME " ") == 0) {
targets = targets "-f " FILENAME " "
}
}
END {
print "}" >> TMPFILE
close(TMPFILE)
CMD = sprintf("%s -f%s %s", awk_cmd, TMPFILE, targets)
system(CMD)
}
|
とりあえず、シェル内で既に定義されている全ての関数の中から、test_ で始まるものを実行してみました。
1 2 3 | declare -fp | grep '^test_.*() $' | while read func paren; do
$func
done
|
super クラスも検索するようにしてみました。 「bar: || "bar".p」というのは引数なしの lambda 関数を bar に束縛しているような感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | String::start_with: method(sub) {
return this.split("").take(sub.length).to_a.join("") == sub;
}
TargetTest: class {
test_foo: || "test_foo".p;
test_bar: || "test_bar".p;
foo: || "foo".p;
bar: || "bar".p;
}
TargetTest2: class(TargetTest) {
test_foo: || "test_foo_sub".p;
test_baz: || "test_baz".p;
}
TestRunner: class {
suite: method(target, inherited_too: true) fiber {
klasses: [target];
if (inherited_too) {
klasses ~= target.each_ancestor.to_a;
}
override: Map();
klasses {|klass|
klass.each_member {|name, x, meth|
if (! override[name] && name.start_with("test_")) {
yield meth;
}
override[name] = true;
}
}
}
run: method(target) {
suite(target) {
it();
}
}
}
runner: TestRunner();
"---".p;
runner.run(TargetTest2);
"---".p;
runner.run(TargetTest);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | :- module(target, []).
test_a :- writeln(test_a).
test_b :- writeln(test_b).
test_x(_) :- writeln(test_x).
no_test :- writeln(no_test).
% 指定されたモジュールの'test_'で始まる引数0の述語を全て実行
call_tests(Module) :-
forall(( current_predicate(Module:Predicate/0),
atom_prefix(Predicate, test_)),
Module:Predicate).
:- call_tests(target).
%=> test_a test_b
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Object callMethods := method(str,
self slotNames foreach(slotname,
if(slotname beginsWithSeq(str),
self perform(slotname)
)
)
)
obj := Object clone
obj test_1 := method(
"test_1" println
)
obj foobar := method(
"foobar" println
)
obj test_2 := method(
"test_2" println
)
obj test3 := method(
"test3" println
)
obj test_4 := "fuga"
obj callMethods("test_")
|
Perlでワンライナーで書いているブログがあったのでリンク。
see: ■[Perl]メソッド名一覧どーかく?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #import <Foundation/Foundation.h>
#import <objc/objc-class.h>
@interface TestClass : NSObject {
}
+ (void)test_class_method;
+ (void)testClassMethod;
- (void)test_instance_method;
- (void)testInstanceMethod;
@end
@implementation TestClass
+ (void)test_class_method {
NSLog( @"test_class_method called" );
}
+ (void)testClassMethod {
NSLog( @"testClassMethod called" );
}
- (void)test_instance_method {
NSLog( @"test_instance_method called" );
}
- (void)testInstanceMethod {
NSLog( @"testInstanceMethod called" );
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Class cls[2] = { [TestClass class]->isa, [TestClass class] };
TestClass* testClass = [[[TestClass alloc] init] autorelease];
//forループ1回目はクラスメソッド、2回目はインスタンスメソッドの実行
for ( int i = 0; i < 2; i++ ) {
void* iterator = 0;
struct objc_method_list* mlist;
while ( mlist = class_nextMethodList( cls[i], &iterator ) ) {
for ( int j = 0; j < mlist->method_count; j++ ) {
Method method = mlist->method_list + j;
NSString* methodName = [NSString stringWithUTF8String:(const char*)method->method_name];
if ( [methodName hasPrefix:@"test_"] ) {
if ( i == 0 )
[TestClass performSelector:method->method_name];
else
[testClass performSelector:method->method_name];
} else
NSLog( @"Skip %@", methodName );
}
}
}
[pool release];
return 0;
}
|
foo:get(erlang). とかで使えます。
1 2 3 4 5 6 | -module(foo).
-export([get/1]).
get(PackageName) ->
[X || {X, Y} <- proplists:get_value(exports, PackageName:module_info()),
lists:suffix("_test", atom_to_list(X))].
|
お題を誤って理解してしまった為、前回投稿したコードは、_test が関数名の末尾に付いた関数の一覧を返します。 今回、投稿するコードは、test_ が関数名の先頭に付いた関数の一覧を返します。 修正箇所は、lists:suffix/2 を lists:prefix/2 にかえただけです。
1 2 3 4 5 6 | -module(foo).
-export([get/1]).
get(PackageName) ->
[X || {X, Y} <- proplists:get_value(exports, PackageName:module_info()),
lists:prefix("test_", atom_to_list(X))].
|
[obj].class.Operations で、[obj]のクラスのメソッド一覧を取得できます。 上記で取得できるのはOperationクラスで、 Operation.Name でオペレーション名を取得できます。
念のためoperation, functionの両方で試しましたが、 両方ともOperationsで取得できました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import java.lang.System;
public class TestClass {
public function test_function();
public operation test_operation();
public function notest_function();
public operation notest_operation();
}
var a = new TestClass();
var testNames = select op.Name from op in a.class.Operations
where op.Name.startsWith("test_");
for(name in testNames) {
System.out.println(name);
}
|
Privateメソッドも実行するために.
1 2 3 4 5 6 7 | STR = 'test_'
module ExeTest_
def exe_test_(x); eval(x) end
end
target = Object.new
target.extend ExeTest_
target.methods.grep(/\A#{STR}/).each{|x| target.exe_test_(x)}
|
1 2 3 4 5 | outputMethod( target, "test_" )
def outputMethod(object, prefix){
object.class.metaClass.methods.findAll{ it.name.startsWith(prefix) }.each{ println it.name }
}
|
暇潰しにやってみた。
反則っちゃ反則なんだけどPCLベースのCLOS実装やってる処理系だと似たようなことできるんちゃうかな
1 2 3 4 5 6 7 8 9 10 11 | (use-package :sb-mop)
(defclass c0 ()
((x :initarg :x :accessor x)
(y :initarg :y :accessor y)))
(defgeneric magnitude (obj))
(defmethod magnitude ((obj c0))
(sqrt (+ (expt (x obj) 2) (expt (y obj) 2))))
(mapcar #'(lambda (m)
(slot-value (slot-value m 'SB-PCL::%GENERIC-FUNCTION)
'SB-PCL::NAME))
(car (slot-value (find-class 'c0) 'SB-PCL::DIRECT-METHODS)))
|
ここでまさかのC++。ええと、WindowsでCOM使っています。VBやスクリプト言語用のIDispatch/ITypeInfoでリフレクションに相当する情報が得られるので、そこからメソッド名test_で始まるものを選び、IDipatchのInvokeメソッドで呼び出しています。
main関数より後ろはヘルパ群、ITypeInfoの型情報やIDispatch対応オブジェクトの作成などといった関数が並んでいます。
ITypeInfoはIDLから作るしかないと思っていたところ、このプログラムのようにCreateDispTypeInfo関数を使うとC++ソースコードの記述だけでITypeInfoを作れることを知りました。これを知らなければこの課題をC++でやることはなかったでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | //#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <ole2.h>
#include <windows.h>
#include <comdef.h>
#include <boost/implicit_cast.hpp>
using boost::implicit_cast;
// ここでは再発明しましたが、COMSTL (WinSTLの兄弟)のcom_exceptionがお薦め
class ComException
{
public:
explicit ComException(HRESULT hr) : hr(hr) {}
ComException(const ComException& rhs) : hr(rhs.hr) {}
ComException& operator =(const ComException& rhs)
{
hr = rhs.hr;
return *this;
}
HRESULT GetErrorCode() const
{
return hr;
}
//swapは使わないので省略
public:
HRESULT hr;
};
void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
throw ComException(hr);
}
}
// COM関係のヘッダに#define interface structとある。
interface __declspec(uuid("c70cd2de-1285-4ec5-a78a-5600cf6fc79a")) __declspec(novtable)
ITest : IUnknown
{
STDMETHOD(test_Hello)() PURE;
STDMETHOD(test_Goodbye)() PURE;
STDMETHOD(piyo_Dummy)() PURE;
// マクロを全て展開するとこうなる。
// virtual __declspec(nothrow) HRESULT __stdcall test_Hello() = 0;
};
// ITestの実装例
class TestImpl : public ITest
{
public:
TestImpl() : refCount(1) {}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
{
if (riid == __uuidof (IUnknown))
{
*ppv = implicit_cast<IUnknown*>(this);
}
else if (riid == __uuidof (ITest))
{
*ppv = implicit_cast<ITest*>(this);
}
else
{
*ppv = 0;
return E_NOTIMPL;
}
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return ++refCount;
}
ULONG STDMETHODCALLTYPE Release()
{
if (--refCount)
{
delete this;
return 0;
}
return refCount;
}
HRESULT STDMETHODCALLTYPE test_Hello()
{
std::cout << "Hello, world!" << std::endl;
return S_OK;
}
HRESULT STDMETHODCALLTYPE test_Goodbye()
{
std::cout << "Goodbye!" << std::endl;
return S_OK;
}
HRESULT STDMETHODCALLTYPE piyo_Dummy()
{
return E_NOTIMPL;
}
private:
ULONG refCount;
};
// もし、IホゲPtrが無くてエラーになるなら。
//_COM_SMARTPTR_TYPEDEF(ITypeInfo, __uuidof (ITypeInfo));
//_COM_SMARTPTR_TYPEDEF(IUnknown, __uuidof (IUnknown));
//_COM_SMARTPTR_TYPEDEF(IDispatch, __uuidof (IDispatch));
ITypeInfoPtr GetFirstInterfaceTypeInfo(ITypeInfo* pti);
IDispatchPtr CreateDispTest(ITypeInfo* pti);
ITypeInfoPtr GetTestTypeInfo();
int main()
{
try
{
ThrowIfFailed(OleInitialize(0));
ITypeInfoPtr pti = GetTestTypeInfo(); //クラスを表すITypeInfo
IDispatchPtr target = CreateDispTest(pti); //オブジェクトの作成
ITypeInfoPtr ptiInterface = GetFirstInterfaceTypeInfo(pti); //ITestを表すITypeInfo
TYPEATTR* pta;
ThrowIfFailed(ptiInterface->GetTypeAttr(&pta));
//DISPPARAMS dp2 = {};
//ThrowIfFailed(pdisp->Invoke(2, IID_NULL, LOCALE_SYSTEM_DEFAULT,
// DISPATCH_METHOD, &dp2, 0, 0, 0));
for (int i = 0; i < pta->cFuncs; ++i)
{
// i個目の関数のMEMIDを取得
FUNCDESC* pfd;
ThrowIfFailed(ptiInterface->GetFuncDesc(i, &pfd));
// その関数の名前を取得
_bstr_t name;
UINT count;
ThrowIfFailed(ptiInterface->GetNames(pfd->memid, name.GetAddress(), 1, &count));
if (wmemcmp(name, L"test_", 5) == 0)
{
// その関数がtest_で始まっていれば引数なしで呼び出す
DISPPARAMS dp = {};
ThrowIfFailed(target->Invoke(pfd->memid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp, 0, 0, 0));
}
ptiInterface->ReleaseFuncDesc(pfd);
}
ptiInterface->ReleaseTypeAttr(pta);
}
catch(ComException const& e)
{
LPSTR msg;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, e.GetErrorCode(), LANG_USER_DEFAULT,
reinterpret_cast<LPSTR>(&msg), 0, 0);
std::cerr << msg << std::endl;
LocalFree(msg);
}
OleUninitialize();
}
// CreateDispTypeInfoを使ったお手軽ITypeInfoの作成。
ITypeInfoPtr GetTestTypeInfo()
{
static METHODDATA md[] =
{
{
/* szName = */ L"test_Hello",
/* ppdata = */ 0, //引数情報
/* dispid = */ 1, //IDispatch::Invokeで呼び出すときの識別番号。適当な正の値で良い。
/* iMeth = */ 3, //VTBL上のインデックス
/* cc = */ CC_STDCALL, //呼出規約
/* cArgs = */ 0, //引数の個数
/* wFlags = */ DISPATCH_METHOD, //メソッド・プロパティの種別
/* vtReturn = */ VT_EMPTY, //戻り値の型
},
{
/* szName = */ L"test_Goodbye",
/* ppdata = */ 0,
/* dispid = */ 2,
/* iMeth = */ 4,
/* cc = */ CC_STDCALL,
/* cArgs = */ 0,
/* wFlags = */ DISPATCH_METHOD,
/* vtReturn = */ VT_EMPTY,
},
{
/* szName = */ L"piyo_Dummy",
/* ppdata = */ 0,
/* dispid = */ 3,
/* iMeth = */ 5,
/* cc = */ CC_STDCALL,
/* cArgs = */ 0,
/* wFlags = */ DISPATCH_METHOD,
/* vtReturn = */ VT_EMPTY,
},
};
static INTERFACEDATA id =
{
md, ARRAYSIZE(md), // ARRAYSIZEは<windows.h>の中で定義されている配列の要素数を求めるマクロ
};
ITypeInfoPtr pti;
ThrowIfFailed(CreateDispTypeInfo(&id, LOCALE_SYSTEM_DEFAULT, &pti));
return pti;
}
// TestImplのディスパッチオブジェクトを作成。
// ただし、ITypeInfを引数として与えること。
IDispatchPtr CreateDispTest(ITypeInfo* pti)
{
TestImpl* p = new TestImpl;
IUnknown* punkDispObj;
ThrowIfFailed(CreateStdDispatch(p, p, pti, &punkDispObj));
return punkDispObj;
}
// あるITypeInfoから、1番目に継承もしくは実装しているインタフェースを返すヘルパ。
ITypeInfoPtr GetFirstInterfaceTypeInfo(ITypeInfo* pti)
{
ITypeInfoPtr res;
HREFTYPE hrt;
ThrowIfFailed(pti->GetRefTypeOfImplType(0, &hrt));
ThrowIfFailed(pti->GetRefTypeInfo(hrt, &res));
return res;
}
|






にしお
#3388()
Rating1/1=1.00
「ある与えられたオブジェクトtargetのメソッドのうち、 "test_"で始まるものをすべて呼びだす」というコードを書いてください。 引数に関しては都合のいいように仮定して構いません(全部0個、など)。
メソッドという概念がない言語の場合は、 「複数の関数への参照を持っているようなオブジェクト(たとえばパッケージとかモジュールとか)から"test_"で始まる関数をすべて呼び出す」と読み替えても構いません。
[ reply ]