我有一个好奇的问题。如果我有一个ruby类,然后我在执行期间动态地添加类方法,类变量等,那么我仍然保存更改的类定义,以便下次启动我的应用程序时我可以再次使用它?
答案 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模块,它允许您将对象保存到文件中,并在内存中动态读取它们。