保存动态Ruby类

时间:2009-06-11 23:08:03

标签: ruby

我有一个好奇的问题。如果我有一个ruby类,然后我在执行期间动态地添加类方法,类变量等,那么我仍然保存更改的类定义,以便下次启动我的应用程序时我可以再次使用它?

5 个答案:

答案 0 :(得分:4)

没有内置方法可以做到这一点。元帅无法保存方法。如果以某种系统方式生成这些方法和变量,则可以保存类重新创建它们所需的数据。例如,如果您有一个定义这些方法的make_special_method(purpose, value)方法,请创建一个需要传递给这些方法的参数数组,并在想要重新构建类的状态时将其读入。

答案 1 :(得分: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

这与我们在第一个例子中所做的完全不同。这段代码为程序中的每个字符串赋予了自身腐烂的能力。此代码仅授予名称“greeting”引用的对象的权力。在内部,Ruby通过创建String的匿名Singleton子类,向其添加rot13方法,以及将greeting的类更改为该匿名子类来实现此目的。

这里的问题是单身人士不能成为元帅(要知道为什么,当任何对Marshal.load的调用可以生成现存的Singleton对象的副本时,试着弄清楚如何维护Singleton不变量)。现在问候语在其继承层次结构中有一个Singleton,所以如果你想保存并加载它,你就会受到冲击。改为创建一个子类:

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

答案 2 :(得分:1)

答案 3 :(得分: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

因此我们可以调用普通方法'test'和动态方法'foo'。让我们看看如果我们编写一个加载保存到磁盘的Example实例的程序会发生什么:

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,并在它包含在类中时让它查找这些成员变量。

答案 4 :(得分:-1)

你正在动态编辑课程,你想要保存吗?您可以尝试使用Marshal模块,它允许您将对象保存到文件中,并在内存中动态读取它们。