Ruby - 在Ruby中扩展内置变量

时间:2012-08-27 17:39:05

标签: ruby oop types metaprogramming

我想在Ruby中扩展变量的功能。原因是我正在研究类似系统或值检查器的东西(这听起来有点疯狂,但整个想法是长期解释,只是我想扩展默认变量的原因)。

我已经读过,在Ruby中,一切都是对象;所以变量就是对象。对于可以通过元编程改变的东西,Ruby应该是非常自由的。

是否存在某种与我可以扩展的局部变量相关联的“类”?

我想为每个包含字符串表示形式的变量关联一个字符串变量。此外,我想拦截变量赋值,并在每次为变量赋值时执行一个方法。这是我可以检查,如果新值根据类型是正确的(在变量中存储为字符串)。

如果Ruby中的局部变量被定义为类的对象,我可以扩展该类或通过ruby mixin修改它。

解决方法是为我的变量创建一个新类(而不是使用Ruby的局部变量中的构建)。该类可以具有值属性,类型的属性(存储为字符串)以及get-和set-方法。这样我可以解决我的问题,但是如果可能的话,我想在ruby中扩展内置变量。

当前正在进行的工作

class Fixnum
        attr_accessor :tp
        @tp

        def mytype ( type )
                @tp = type
        end
        def typecheck
                #call typechecker
                puts "checked"
        end
end

测试代码:

a = 3
a.mytype("nat")
puts a.tp
a.typecheck

还有两个问题。 首先,我认为不可能向Fixnum添加新的构造函数。 Second ,我想拦截变量访问,即“b = a”调用a的方法'typecheck'。但这需要类似于面向方面编程的东西,我不确定这是否可以通过Ruby的元编程方便解决。

3 个答案:

答案 0 :(得分:4)

  

我已经读过Ruby,一切都是对象

这取决于您对“ object ”和每个 - “ thing ”的定义。 “对象”可以表示“可以由程序操作的实体”(我将从现在开始称之为对象)或“< em>作为对象系统成员的值“(从现在开始我将称之为Object。)

在Ruby中,程序可以操作的所有内容(即每个对象)也是Object,即类的实例。这与Java不同,例如, primitives 可以由程序操作(即在该词的意义上对象),但不是{{1} }。在Ruby中,这种区别不存在:每个对象都是Objects,每个Object也是对象

但是,语言中有的东西不能被程序操纵,哪些不是类的实例,即它们都不是对象 s和Object。例如,这些是方法,变量,语法,参数列表,参数列表,关键字。

注意:您可以使用Ruby的反射API为您提供表示方法或参数列表的对象,但该对象只是一个代理,它不是真实的。

所以,当我们说“一切都是对象”时,我们真正的意思是“每个对象都是Object”,即一切可以由程序操纵的也是对象系统的成员,或者换句话说,在对象系统之外没有值(与Java中的原语不同)。我们 not 意味着该语言中存在的所有内容也可以在程序运行时进行操作。

  

所以变量是对象

不,不幸的是,它们既不是对象,也不是Object

Ruby语言规范中也清楚地说明了这一点(我强调):

  

6.2变量

     

6.2.1一般说明

     

变量用名称表示,表示对象,称为变量的值。   变量本身不是对象

第2页上的The Ruby Programming Language by Matz and David Flanagan一书中提到:

  

每个值都是一个对象

注意,它并不是说每个事物,只是每个

另见问题Is variable is object in ruby?

答案 1 :(得分:1)

你可以做几件事。对于初学者来说,所有(或几乎所有)Ruby类(包括诸如数字的“基元”)都支持to_s方法,该方法返回对象的字符串表示。对于数字,to_s将仅返回该数字的字符串表示(例如,42表示“42”)。为其他类返回的字符串值会有所不同。好的是你可以override a class's methods via "monkey patching"。这是一个非常人为的例子:

class Array
  def to_s
    return "An array of size #{self.size}."
  end
end

a = [1, 2, 3, 4]
puts a.to_s
# => "An array of size 4."

关于每次设置变量值时执行方法的其他问题,处理此问题的方法是始终通过其访问器方法与变量进行交互。这样,您就可以在属性的getter和setter方法中实现自定义代码(或者只是从访问器内部调用另一个方法)。像这样:

class MyClass
  # Use the default getter for var.
  attr_reader :var      

  def initialize
    @var = 1
  end

  # Custom setter for var.
  def var= v
    @var = v
    puts "var changed to #{v}"
  end
end

mc = MyClass.new
mc.var = 9
# => "var chaged to 9"

答案 2 :(得分:0)

你可以这样做,但它只适用于全局:

$type_checked = {:$a => String, :$b => Array}
$type_checked.keys.each do |var|
  trace_var(var) do |obj|
    puts "hey, don't assign #{var} to a #{obj.class}" unless $type_checked[var] == obj.class
    #or raise an Error
  end
end

$a = 1
$a = "a"
$b = 1

#output:
#hey, don't assign $a to a Fixnum
#hey, don't assign $b to a Fixnum

但这明显违背了语言的含义。