2009-06-11 55 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 

在这里,我们已经添加了ROT13方法String类。只要运行此代码,程序中的每个字符串都可以#rot13。因此,如果您的某些代码需要具有rot13功能的字符串,则只需确保上述代码在相关代码之前运行,例如通过将rot13代码放置在某个文件的某个位置并需要()它。好简单!

但是,也许你已经添加了一个类变量的一类,并且要保留不只是它的存在,但它的价值,如:

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 

这是我们在第一个例子做了很大的不同。这段代码给你的程序中的每个字符串赋予rot13本身的权力。此代码只将权限赋予名称“greeting”引用的对象。在内部,Ruby通过创建String的匿名Singleton子类,将rot13方法添加到它以及将问候类更改为该匿名子类来实现此目的。

这里的问题是单身人士不能被编组(看看为什么,当任何对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 2009-06-12 00:49:12