2011-12-23 4 views
1

ルールエンジンでRubyコードで書かれたルールを評価する方法として、eval()を使用するアプリケーションでメンテナンスを継承しました。 ロット他の方法がありますが、これまでのコードベースは非常に大きく、それを何か他のものに変更することは、この時点では非常に時間がかかるでしょう。今のところ私はeval()を使用して立ち往生していると仮定します。Rubyのevalと「既に初期化された定数」を回避するにはどうすればよいですか?

通常、書き込まれたルールは、データベースから同じオブジェクトの一部を呼び出し、ルールライターは、ルール内の変数に互いに同じ名前を付けます。これは、開発中にコンソール内のページやページに「既に初期化された定数」の警告を表示します。 は、DEV環境でのプログラムの実行速度を遅くしているもののようを感じている場合は、

まず、それがで大きなパフォーマンスヒットだ場合ので、私は思ったんだけど:

私はカップルの事を思ったんだけどプロダクション環境、具体的には、私が知っているeval()自体ではなく、それらの警告がポップであることがヒットしています。

第2に、各ルールの実行を「ネームスペース」する方法はありますか。そのため、要求内の他のすべてのエバリュと同じスコープでその変数を定義していないため、私は||=構文を使用するか、名前がすでに定義されているかどうかを確認するためにすべてのルールを書き直すことができると知っていますが、可能であればeval()を実行するコードからやっています。

**例ルールで更新** 質問には、ユーザーに表示するタイミングに関する規則があります。たとえば、ユーザーがアパートに住んでいると述べた場合は、アパートメントの大きさを確認するために別の質問を表示する必要があります。

UserLivesInApartment = Question.find_by_name "UserLivesInApartment" 
UserLivesInApartment.answer_for(current_user) 

評価に先立っ範囲でCURRENT_USER変数がありますが保証はevalを呼び出すコード:だから2番目の質問のrule_textは、次のようになります。

+0

サンプルとサンプルコードを見るのに役立ちます。つまり、これは主観的な質問であり、助けの能力を弱めるコードを推測する必要があります。 –

+0

これはちょうど正しいルビーではなく、警告を正しく生成するはずです。なぜあなたは変数に定数を代入しますか?コードをリファクタリングして、クラス変数@user_lives_in_apartmentまたは単純な変数user_lives_in_apartmentにする必要があると思います。それ以外の場合は、アクティブなレコード照会の結果でグローバル名前空間を汚染します。 – sunkencity

+0

これは、私が継承したシステム内の数百のルールの1つの例です。あなたが提案しているリファクタリングを行う最もクリーンな方法は何ですか? – Paul

答えて

1

ええと、evalはおそらく標準の最も金色ではありません。おそらく、drbインスタンスを起動して、evalの代わりにそのことを実行して、自分の名前空間を汚染しないように、少なくとも何らかの制御をするでしょう。

http://segment7.net/projects/ruby/drb/introduction.html


編集:同じプロセス内でコードを実行するための別の答えを追加しました:

を私はあなたのルールのコードがどのように見えるか知りませんが、モジュールをラップすることは可能かもしれませんそれは周り:

# create a module 
module RuleEngineRun1;end 
# run code in module 
RuleEngineRun1.module_eval("class Foo;end") 

# get results 
#.... 

# cleanup 
Object.send(:remove_const, :RuleEngineRun1) 

また、あなたが並列でコードを実行する必要がある場合は{モジュールeval'dをする#BLOCK} Module.newとの匿名のモジュールを作成することができます。


後のルビーでは、印刷警告なしにあなたのコードを実行するために-W0を追加できますが、これは可能性のあるエラーが見過ごさ作ることができます。

$ cat foo.rb 
FOO = :bar 
FOO = :bar 

$ ruby foo.rb 
foo.rb:2: warning: already initialized constant FOO 

$ ruby -W0 foo.rb 

また、カーネルの中にあなたのevalを実行することができます。silence_warningsブロックがありますが、実際にevalされたコードで実際の問題に遭遇した場合には壊滅的かもしれません。 Suppress Ruby warnings when running specs

+0

私はe/eval()問題があることを知っています。私が質問で言ったように、これは継承されたコードであり、それはすでに行われている方法です。しかし、私は何か他のものに切り替えるのは気にしませんが、DBから文字列としてスクリプトを読み込んで評価するために、drbを使ってどうすればいいのか分かりません。 – Paul

+0

考え方は、異なるプロセスでルールを実行することを防御することです。それを好きなのは、それを再起動したり消去したりすることです。そうすることで、ルールエンジンを実行するためのクリーンスレートを得ることができます。 – sunkencity

+0

Ruby 1.9.3には、Bindingで評価できるいくつかのクールなものがあります。しかし、私は従来のアプリケーションでは使いにくいと思う1.9.3 http://www.ruby-doc.org/core-1.9.3/Binding.html – sunkencity

関連する問題