0

アップデート

読者を混乱させたことをお詫びしなければなりません。コードに完全に没頭した後、Mercurialリポジトリからすべての変更を元に戻し、以前と同じロジックを慎重に適用しました。これで機能しました。以下の回答は、(私にとっては新しい)概念をよりよく理解するのに役立ち、そのために私は彼らに賛成票を投じました。

結論:欠落しているメソッドの呼び出しがクロージャ内で発生し、解決がDELEGATE_FIRSTに設定されている場合、methodMissing()がデリゲートで呼び出されます。そうでない場合は、自分のコードを確認してください。どこかにタイプミスがあります。

どうもありがとう!

4

2 に答える 2

1

編集: OK、あなたが何をしているのかを明確にしたので(やや;--))

別のアプローチ (私が DSL に使用するもの) は、クロージャー グループを解析して、次のように ClosureToMap ユーティリティを介してマップすることです。

// converts given closure to map method => value pairs (1-d, if you need nested, ask)
class ClosureToMap {
    Map map = [:]
    ClosureToMap(Closure c) {
        c.delegate = this
        c.resolveStrategy = Closure.DELEGATE_FIRST
        c.each{"$it"()}
    }
    def methodMissing(String name, args) {
        if(!args.size()) return
        map[name] = args[0]
    }
    def propertyMissing(String name) { name }
}

// Pass your closure to the utility and access the generated map
Map map = new ClosureToMap(your-closure-here)?.map

これで、マップを反復処理して、おそらく該当する MCL インスタンスにメソッドを追加できます。たとえば、私のドメインの一部には、次のような動的ファインダーがあります。

def finders = {
    userStatusPaid = { Boolean active = true->
        eq {
            active    "$active"
            paid      true
        }
    }
}

ClosureToMap ユーティリティを使用してマップを作成し、マップ キー (「userStatus」などのメソッド) と値 (この場合はクロージャー「eq」) をドメイン インスタンス MCL に追加して反復処理し、クロージャーを ORM に委譲します。それで:

def injectFinders(Object instance) {
    if(instance.hasProperty('finders')) {
        Map m = ClosureToMap.new(instance.finders).map
        m?.each{ String method, Closure cl->
            cl.delegate = instance.orm
            cl.resolveStrategy = Closure.DELEGATE_FIRST
            instance.orm.metaClass."$method" = cl
        }
    }
}

このようにして、コントローラースコープで次のことができます。

def actives = Orders.userStatusPaid()

また、「eq」クロージャーは、MME が発生するドメイン Orders ではなく、ORM に委任されます。

うまくいけば、問題を解決する方法についていくつかのアイデアを提供できます。Groovy では、ある方法でそれができない場合は、別の方法を試してください ;--)

幸運を!

オリジナル: missingMethod は文字列メタクラスで定義されています。それを呼び出すには、「someString」.foo() が必要です。

クロージャー内で単に foo() を単独で呼び出すと、使用されている委譲戦略に関係なく、失敗します。つまり、(String) デリゲートを使用しない場合は、幸運を祈ります。適切な例として、 "".foo() を実行すると機能します。

私も問題を完全には理解していません。クロージャーのデリゲートにアクセスできないのはなぜですか? クロージャーのデリゲートを設定していて、クロージャーを呼び出します。つまり、クロージャー自体のデリゲートにアクセスできます (そして、delegate.foo() だけが可能です)。

于 2011-05-23T14:36:21.797 に答える
1

いいえ、不足しているメソッドをキャッチして、メタクラス マジックでデリゲートにリダイレクトすることはありません。
クロージャー デリゲートはこれらの呼び出しをキャプチャし、バッキング ドメインに適応させるチャンスです。
つまり...
DSL に必要なメソッドを使用して独自のデリゲートを作成する必要があります。
クラスがタスク用に設計されていない場合は、クラスに委任作業を強制しようとしないでください。そうしないと、コードがすぐにめちゃくちゃになります。
特別に設計されたデリゲート クラスのセットに関連するすべての DSL を保持すると、すべてが突然、ばかげて単純明快になります。

于 2011-05-24T00:42:24.577 に答える