フィールドとメソッド探しにちょっと便利な関数を作ってみた

SLIMEで開発している際に、Javaのクラスが持つフィールドやメソッド名を調べたい事がある。
例えば、文字列を大文字に変換するメソッドを忘れてしまって、uppercaseだったかな?toUpperだったかな?なんて時に、ちょっと便利な関数。

使い方

(inspect 調べたいオブジェクトまたはクラス マッチ文字列)

すべてのフィールド・メソッドを表示したい場合は

(inspect 調べたいオブジェクトまたはクラス)

とする。

使用例

user> (use 'tools) ; tools名前空間をuseする
nil
user> (inspect String "upper") ; Stringクラスをupperで調べる
String toUpperCase(Locale)
String toUpperCase()
nil
user> (inspect Integer) ; Integerクラスの全てのフィールド・メソッドを調べる
Integer MIN_VALUE
Integer MAX_VALUE
Integer TYPE
Integer SIZE
int hashCode()
int reverseBytes(int)
boolean equals(Object)
...略...
user> (inspect 1.0 "infi") ; オブジェクトを指定しても良い
Double NEGATIVE_INFINITY
Double POSITIVE_INFINITY
boolean isInfinite(double)
boolean isInfinite()
nil
user> 

コード

(ns tools
  (:use [clojure.contrib.str-utils :only (str-join)]))

(defn to-class [obj]
  (if (class? obj) obj (class obj)))

(defn- filter-name [coll s]
  (filter #(not= (.. % getName toUpperCase (indexOf s)) -1)
	  (sort-by #(. % getName) coll)))

(defn- match-field [cls s]
  (let [fields (. cls getFields)]
    (if s
      (filter-name fields s)
      fields)))

(defn- match-method [cls s]
  (let [methods (. cls getMethods)]
    (if s
      (filter-name methods s)
      methods)))

(defn inspect
  ([obj] (inspect obj nil))
  ([obj s]
     (let [cls (to-class obj)
	   mstr (if s (. s toUpperCase))]
       (doseq [field (match-field cls mstr)]
	 (let [field-name (. field getName)
	       class-name (.. field getDeclaringClass getSimpleName)]
	   (println (str class-name " " field-name))))
       (doseq [method (match-method cls mstr)]
	 (let [method-name (. method getName)
	       return-class-name (.. method getReturnType getSimpleName)
	       param-class-names (for [param-class (. method getParameterTypes)]
				   (. param-class getSimpleName))]
	   (println (str return-class-name " " method-name
			 "(" (str-join ", " param-class-names) ")")))))))