有没有一个gem可以提供检测本地ruby类型实例更改的支持



尽管我同意扩展本机类型和对象是一种糟糕的做法,但从它们继承不应该是。

在一个所谓的支持gem(我找不到)中,原生类型的使用方式如下:

require 'cool-unkown-light-gem'
class MyTypedArray < CoolArray # would love to directly < Array
def initialize(*args)
super(*args)
# some inits for DataArray
@caches_init = false
end
def name?(name)
init_caches unless !@caches_init
!!@cache_by_name[name]
end
def element(name)
init_caches unless !@caches_init
@cache_by_name[name]
end
private
# overrides the CoolArray method:
# CoolArray methods that modify self will call this method
def on_change
@caches_init = false
super
end
def init_caches
return @cache_by_name if @caches_init
@caches_init = true
@cache_by_name = self.map do |elem|
[elem.unique_name, elem]
end.to_h
end
end

父类的任何未被修改self的子类重写的方法都将调用on_change函数。这将允许不必重新定义这些方法中的每一个,以避免丢失对更改的跟踪。

假设MyTypedArray将对Foo对象进行数组:

class Foo
attr_reader :unique_name
def initialize(name)
@unique_name = name
end
end

它的使用预期行为的一个简短例子:

my_array = MyTypedArray.new
my_array.push( Foo.new("bar") ).push( Foo.new("baz") )
my_array.element("bar").unique_name
# => "bar"
my_array.shift # a method that removes the first element from self
my_array.element("bar").unique_name
# => undefined method `unique_name' for nil:NilClass (NoMethodError)
my_array.name?("bar")
# => false

我知道我们应该搜索不可变的类,但这些本机类型支持对同一对象的更改,我们希望有一种尽可能简单的正确方法来进行继承。

当然,任何想法、方法或建议都是非常受欢迎的。我不认为我是唯一一个对此有想法的人。

我之所以搜索维护的gem,是因为不同的ruby版本可能为本机类型/类提供不同的支持方法或选项。

[编辑]

以上的目的是找出一个行之有效的模式。我可以遵循其他帖子的规则和建议,但不会让事情按照我的意图和我认为合适的方式进行(编码语言是由人类创造的,是为人类而创造的,而不是人类为编码语言而创造的)。我知道每个人都为自己在学习、发展和创造社区知名模式方面取得的成就感到骄傲。

上述目标是因为Array的所有methods都非常受欢迎。我不在乎在Ruby的20版本中,他们是否删除了Array的一些方法。到那时,我的应用程序将被淘汰,或者有人将用更少的代码实现同样的结果。

为什么选择Array

因为秩序很重要。

为什么是内部Hash

因为就我想使用它而言,总的来说,构建哈希的成本补偿了它提供的优化。

为什么不只是include Enumerable

因为我们只是减少了更改对象的方法的数量,但实际上我们没有允许将@caches_init更改为false的模式,所以Hash在下次使用时重建(与Array的问题相同)

为什么不只是白名单并包括目标Array方法

因为这并不能让我达到我想要的水平。如果我希望任何人仍然使用popshift,但我不想重新定义它们,或者甚至不得不费力地管理我的mixin并不断地使用responds_to?,该怎么办?

我想去哪里

我想处于一个可以重用/继承任何,我重复,任何类的位置(无论它是否是原生的)。这是面向对象语言的基础。如果我们不是在谈论OOP语言(而是在它的顶部放一些糖,使它看起来像OOP),然后,让我们保持开放的心态,分析应该能很好地工作的模式(无论它们是否奇怪——对我来说,更奇怪的是没有中间级别;这是许多传统模式的症状,而这反过来又是对某些功能支持不足的症状,这些功能的需求比公认的更广泛)。

为什么宝石应该提供上述

好吧,让我们谦虚一点。以上是一个非常简单的案例(尽管没有涵盖)。通过使用一些人想要称之为的Ruby方式,您可能会在某个时候获得灵活性。但当你转向更大的体系结构时,会付出代价。如果我想创建要从中继承的中间类,该怎么办?丰富的本机类促进了简单的代码,同时使其与语言保持一致。说这不是Ruby的方式比试图让语言更接近从底层升级的东西更容易。

Rails和Ruby几乎被许多人"模糊地"使用,我对此并不感到惊讶。因为在某种程度上,如果没有Rails的支持,Ruby就会遇到很多麻烦。因此,我对Rails如此维护并不感到惊讶。

为什么要重新定义poplastfirst方法?为了什么?它们已经实施。为什么我应该将方法列入白名单并创建mixin?这是面向对象编程还是面向方法编程?

不管怎样。。。我不希望有人会同意我的看法。我确实看到了其他的模式,我会一直让我的大脑去寻找它们。如果有人足够开放,请随意分享。有人可能会批评这种方法,而且是对的,但如果你做到了,那是因为它奏效了。

要回答您的问题,没有,没有gem。无论是在纯Ruby中还是在内部使用的C中,这种语言都不可能实现。

self改变时,没有检测机制,也没有任何方法来检测一种方法是纯的(不改变自身)还是不纯的(改变自身)。你似乎想要一种方法来"自动"知道一个方法是什么,简单地说,这是不可能的,我所知道的任何语言都不可能。

在内部(使用您的示例),Array由C中的RArray结构支持。结构是简单的存储空间:一种查看任意内存块的方法。C不在乎你选择如何看待内存,我可以很容易地抛出这个结构的指针,说它现在是一个指向整数数组的指针,然后用这种方式更改它,它会很高兴地按照我的指示操作内存,没有什么可以检测到我这样做了。现在再加上一个事实,任何人、任何脚本或任何gem都可以这样做,而你无法控制它,这恰恰表明,这一解决方案在根本上和客观上都存在缺陷。

这就是为什么在对象更改时需要通知的大多数(所有?)语言都使用observer模式的原因。您可以创建一个函数,当某个内容发生更改时"通知"该函数,并在需要时手动调用该函数。如果有人决定将你的类子类化,他们只需要在改变对象状态的情况下继续该模式来引发该函数。

没有自动的方法如前所述,这是一个"选择加入"或"白名单"解决方案。如果您想对现有对象进行子类化,而不是从头开始使用自己的对象,那么您需要相应地修改其行为。

也就是说,如果您使用module_evalclass_eval等巧妙的别名和元编程,添加功能并不像您想象的那样令人生畏。

# This is 100% untested and not even checked for syntax, just rough idea
def on_changed
# Do whatever you need here when object is changed
end
# Unpure methods like []=, <<, push, map!, etc, etc
unpure_methods.each do |name|
class_eval <<-EOS
alias #{name}_orig #{name}
def #{name}(*args, &block)
#{name}_orig(*args, &block)
on_changed
end
EOS
end

最新更新