2009-06-11 9 views
5

私は好奇心の質問があります。 Rubyクラスを持っていて、実行中にクラスメソッド、クラス変数などを動的に追加すると、変更されたクラス定義を保存することができますので、次にアプリケーションを起動するときに再び使用できます。動的Rubyクラスを保存する

答えて

1

オブジェクトをマーシャリングするだけで(他の人が言ったように)動作しません。例を見てみましょう。

class Extras 
    attr_accessor :contents 
    def test 
    puts "This instance of Extras is OK. Contents is: " + @contents.to_s 
    end 

    def add_method(name) 
    self.class.send :define_method, name.to_sym do 
     puts "Called " + name.to_s 
    end 
    end 
end 

今すぐインスタンスを作成するプログラムを書くことができます

がそれにメソッドを追加し、それをディスクに保存します:

require 'extras' 

fresh = Extras.new 
fresh.contents = 314 
fresh.test # outputs "This instance of Extras is OK. Contents is: 314" 
fresh.add_method(:foo) 
fresh.foo # outputs "Called foo" 

serial = Marshal.dump(fresh) 
file = File.new "dumpedExample", 'w' 
file.write serial 

だから我々は、通常のメソッドを呼び出すことができる「試験」と、このクラスを考えてみましょう動的メソッド 'foo'。

require 'extras' 

file = File.new 'dumpedExample', 'r' 
serial = file.read 

reheated = Marshal.load(serial) 
reheated.test # outputs "This instance of Extras is OK. Contents is 314" 
reheated.foo # throws a NoMethodError exception 

だから我々は(メンバ変数の値を含む)のインスタンスながら、動的メソッドを保存されたことを確認できます。私たちは、ディスクに保存された例のインスタンスをロードするプログラムを書くとどうなるかを見てみましょうではなかった。

デザインの観点からすると、追加したすべてのコードをモジュールに入れて、次にプログラムを実行するときに、そのコードをクラスに再度ロードする方がよいでしょう。実際にこれを知るためには、どのように使用したいかという良い例が必要です。

メソッドを再作成するために追加情報が必要な場合は、モジュールにメンバー変数として保存させます。モジュールにincludedを実装し、クラスに含まれるときにこれらのメンバー変数を検索させます。

-1

オンザフライでクラスを編集していますが、保存しますか? Marshalモジュールを使用すると、オブジェクトをファイルに保存してメモリに動的に読み込むことができます。

4

これを行うには、組み込みの方法はありません。マーシャルはメソッドを保存できません。これらのメソッドと変数が系統的な方法で生成された場合は、クラスに必要なデータを保存して再作成することができます。たとえば、これらのメソッドを定義するmake_special_method(purpose, value)メソッドがある場合、これらのメソッドに渡す必要がある引数の配列を作成し、クラスの状態を再構成するときに読み込みます。

2

正確に何を意味するかによって、これについてはいくつかの方法があります。

最も単純なケースでは、この例のように、既存のクラスに変数やメソッドを追加したものです:

class String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 

ここでは、StringクラスにROT13メソッドを追加しました。このコードが実行されると、プログラム内のすべての文字列は#rot13できるようになります。したがって、rot13対応の文字列を必要とするコードがある場合は、上記のコードが問題のコードの前に実行されていることを確認してください。 rot13のコードをどこかのファイルに入れてrequire()することで実現できます。非常に簡単!

しかし、多分あなたはクラスにクラス変数を追加した、とあなたはのように、その存在が、その値だけではなく、残しておきたい:

class String 
    @@number_of_tr_calls_made = 0 
    # Fix up #tr so that it increments @@number_of_tr_calls_made 
end 

今、あなたはの値を保存したい場合は、@ @number_of_tr_calls_madeでは、他のシリアライズ可能なRuby値と同じ方法で、Marshalライブラリを使用することができます。また簡単!

しかし、あなたはあなたの質問を言葉で表現方法で、何かが私になりますが、あなたがこのような何かをやっていると思われる:

greeting = "Hello" 
class <<greeting 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
encrypted_greeting = greeting.rot13 

これは、我々は最初の例で行ったものとは非常に異なっています。そのコードは、プログラム内のすべてのStringにrot13自体の力を与えました。このコードは、「挨拶」という名前で参照されるオブジェクトだけにその権限を与えます。内部的には、RubyはStringの匿名シングルトンサブクラスを作成し、rot13メソッドを追加し、挨拶のクラスをその匿名サブクラスに変更することでこれを行います。

ここで問題となるのは、SingletonsはMarshal'dできないということです(Marshal.loadの呼び出しによって既存のSingletonオブジェクトのコピーが生成される場合、Singletonの不変条件を維持する方法を理解してください)。挨拶はその継承階層にシングルトンを持っていますので、保存してロードしたい場合はホースします。代わりにサブクラスを作成します。

class HighlySecurableString < String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
greeting = HighlySecurableString.new("hello") 
+0

私は、質問者が実行中にクラスに追加されたメソッドを参照していたと思います。私。メタプログラムされたメソッド。私は誤解しているかもしれません。 – toholio

関連する問題