如何运行一个ruby类 中的方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何运行一个ruby类 中的方法相关的知识,希望对你有一定的参考价值。

参考技术A 在Ruby中,有多种方法可以实现方法的动态调用。
1.
使用send方法
第一种实现动态方法调用是使用send方法,send方法在Object类中定义,方法的第一个参数是一个符号用来表示所要调用的方法,后面则是所调用方法需要的参数。
“This
is
a
dog1″.send(:length)
=>
14
上面的代码中通过send方法去对一个字符串执行length操作,返回字符串的长度。
class
TestClass
def
hello(*args)
”Hello

+
args.join(‘
‘)
end
end
a
=
TestClass.new
puts
a.send
:hello,
“This”,
“is”,
“a”,
“dog!”
执行结果为:
Hello
This
is
a
dog!
2.
使用Method类和UnboundMethod类
另一种实现动态方法调用是使用Object类的method方法,这个方法返回一个Method类的对象。我们可以使用call方法来执行方法调用。
test1
=
“This
is
a
dog1″.method(:length)
test1.call
=>
14
class
Test
def
initialize(var)
@var
=
var
end
def
hello()
”Hello,
@var
=
#@var”
end
end
k
=
Test.new(10)
m
=
k.method(:hello)
m.call
#=>
“Hello,
@iv
=
99″
l
=
Test.new(‘Grant’)
m
=
l.method(“hello”)
m.call
#=>
“Hello,
@iv
=
Fred”
可以在使用对象的任何地方使用method对象,当调用call方法时,参数所指明的方法会被执行,这种行为有些像C语言中的函数指针。你也可以把method对象作为一个迭代器使用。
def
square(a)
a*a
end
mObj
=
method(:square)
[1,
2,
3,
4].collect(&mObj)
=>
[1
4
9
16]
Method对象都是和某一特定对象绑定的,也就是说你需要通过某一对象使用Method对象。你也可以通过UnboundMethod类创建对象,然后再把它绑定到某个具体的对象中。如果UnboundMethod对象调用时尚未绑定,则会引发异常。
class
Double
def
get_value
2
*
@side
end
def
initialize(side)
@side
=
side
end
end
a
=
Double.instance_method(:get_value)
#返回一个UnboundMethod对象
s
=
Double.new(50)
b
=
a.bind(s)
puts
b.call
执行结果为:
100
看下面一个更具体的例子:
class
CommandInterpreter
def
do_2()
print
“This
is
2
”;
end
def
do_1()
print
“This
is
1
”;
end
def
do_4()
print
“This
is
4
”;
end
def
do_3()
print
“This
is
3
”;
end
Dispatcher
=

?2
=>
instance_method(:do_2),
?1
=>
instance_method(:do_1),
?4
=>
instance_method(:do_4),
?3
=>
instance_method(:do_3)

def
interpret(string)
string.each_byte
|i|
Dispatcher[i].bind(self).call

end
end
interpreter
=
CommandInterpreter.new
interpreter.interpret(’1234′)
执行结果为:
This
is
1
This
is
2
This
is
3
This
is
4
3.
使用eval方法
我们还可以使用eval方法实现方法动态调用。eval方法在Kernel模块中定义,有多种变体如class_eval,module_eval,instance_eval等。Eval方法将分析其后的字符串参数并把这个字符串参数作为Ruby代码执行。
str
=
“Hello”
eval
“str
+

World!’”
=>
Hello
World!
sentence
=
%q“This
is
a
test!”.length
eval
sentence
=>
15
当我们在使用eval方法时,我们可以通过eval方法的第二个参数指明eval所运行代码的上下文环境,这个参数可以是Binding类对象或Proc类对象。Binding类封装了代码在某一环境运行的上下文,可以供以后使用。
class
BindingTest
def
initialize(n)
@value
=
n
end
def
getBinding
return
binding()
#使用Kernel#binding方法返回一个Binding对象
end
end
obj1
=
BindingTest.new(10)
binding1
=
obj1.getBinding
obj2
=
BindingTest.new(“Binding
Test”)
binding2
=
obj2.getBinding
puts
eval(“@value”,
binding1)
#=>
10
puts
eval(“@value”,
binding2)
#=>
Binding
Test
puts
eval(“@value”)
#=>
nil
可以看到上述代码中,@value在binding1所指明的上下文环境中值为10,在binding2所指明的上下文环境中值为Binding
Test。当eval方法不提供binding参数时,在当前上下文环境中@value并未定义,值为nil。

如何列出从 Ruby 中的类创建的所有对象? [复制]

【中文标题】如何列出从 Ruby 中的类创建的所有对象? [复制]【英文标题】:How do I list all objects created from a class in Ruby? [duplicate] 【发布时间】:2012-12-28 09:23:31 【问题描述】:

Ruby 中有没有办法让一个类知道它存在多少个实例并列出它们?

这是一个示例类:

class Project

  attr_accessor :name, :tasks

  def initialize(options)
    @name = options[:name]
    @tasks = options[:tasks]
  end

  def self.all
    # return listing of project objects
  end

    def self.count
          # return a count of existing projects
    end


end

现在我创建这个类的项目对象:

options1 = 
  name: 'Building house',
  priority: 2,
  tasks: []


options2 = 
  name: 'Getting a loan from the Bank',
  priority: 3,
  tasks: []


@project1 = Project.new(options1)
@project2 = Project.new(options2)

我想要的是有像Project.allProject.count 这样的类方法来返回当前项目的列表和计数。

我该怎么做?

【问题讨论】:

【参考方案1】:

您可以使用ObjectSpace 模块来执行此操作,特别是each_object 方法。

ObjectSpace.each_object(Project).count

为了完整起见,以下是您在课堂上使用它的方式(向sawa 致敬)

class Project
  # ...

  def self.all
    ObjectSpace.each_object(self).to_a
  end

  def self.count
    all.count
  end
end

【讨论】:

你需要在课堂上include ObjectSpace 才能使用吗? @HunterStevens 不,我们没有将模块混合到我们的类中,只是在其上调用一个方法 警告:这个解决方案可以很容易地射中自己的脚。如果您不保留对对象的引用(例如,如果您在没有将结果分配给某物的情况下执行 Project.new),它们将在某个时候被垃圾收集,ObjectSpace.each_object 显然会停止报告它们。使用 @@instances = [] 而不是像 rohit89 的答案那样通过保留对这些对象的引用来解决这个问题。【参考方案2】:

一种方法是在创建新实例时跟踪它。

class Project

    @@count = 0
    @@instances = []

    def initialize(options)
           @@count += 1
           @@instances << self
    end

    def self.all
        @@instances.inspect
    end

    def self.count
        @@count
    end

end

如果你想使用ObjectSpace,那么它

def self.count
    ObjectSpace.each_object(self).count
end

def self.all
    ObjectSpace.each_object(self).to_a
end

【讨论】:

这就是我要做的。它肯定适用于所有 Ruby 实现,并且可以根据需要扩展用于不同目的。【参考方案3】:
class Project
    def self.all; ObjectSpace.each_object(self).to_a end
    def self.count; all.length end
end

【讨论】:

【参考方案4】:

也许这会起作用:

class Project
  class << self; attr_accessor :instances; end

  attr_accessor :name, :tasks

  def initialize(options)
    @name = options[:name]
    @tasks = options[:tasks]

    self.class.instances ||= Array.new
    self.class.instances << self
  end

  def self.all
    # return listing of project objects
    instances ? instances.dup : []
  end

  def self.count
    # return a count of existing projects
    instances ? instances.count : 0 
  end

  def destroy
    self.class.instances.delete(self)
  end
end

但您必须手动销毁这些对象。也许可以基于 ObjectSpace 模块构建其他解决方案。

【讨论】:

我喜欢这个,但是应该有一些内置的反射 - ruby​​ 中不存在吗?我不知道如何使用 ObjectSpace 模块。例子真的很有帮助 好吧。 ObjectSpace 允许您与垃圾收集器交互。这是我在代码中尽量不做的事情。你可以试试ObjectSpace.each_object(Project).to_a,但我不能再帮你了。 有什么特别的理由可以避免这种情况吗? 例如在doc 中写到方法count_objects 是“除了C Ruby 之外预计不会工作”。所以你必须小心。 count_objects 仅适用于 MRI(又名 C Ruby)。 each_object 适用于 MRI、Rubinius 和 JRuby(在 1.9.3 变体上测试)。

以上是关于如何运行一个ruby类 中的方法的主要内容,如果未能解决你的问题,请参考以下文章

Ruby 中的“猴子补丁”到底是啥意思?

如何创建一个 cron 作业来运行 ruby​​ 脚本?

如何从 Ruby 中的实例方法访问受保护的类方法?

如何在 Ruby 脚本中运行 Rake 任务?

cron作业中的Rails类方法在弹性beantalk中不起作用

如何运行使用我的 Rails 模型的 Ruby 任务?