我有一个类,它将传入的字符串解构为嵌套数组cascade
。
例如,对于输入abcde
,它将生成[[[[a,b],c],d],e]
数组。
刚才,如果我访问设置cascade
的任何顶级值,我的类的[]=(index, value)
方法将被调用。但是我还需要在任意级别的cascade
内捕获对嵌套数组的访问。
请参阅下面的示例,其中访问x[0][0]
显然不会调用类方法[]=
。那么,是否可以在类方法中捕获该访问权限(或者至少以不同的方式)?
class MyClass
attr_accessor :cascade
def initialize string
build_cascade string.split(//)
end
def build_cascade array
if array.length > 2
array[0] = array[0..1]
array.delete_at(1)
build_cascade array
else
@cascade = array
end
end
def []=(index, value)
puts 'You\'ve just tried to set \''+value.to_s+'\' for \''+index.to_s+'\' of @cascade!'
end
def [](index)
@cascade[index]
end
end
x = MyClass.new('abcdefghigk')
puts x.inspect
x[0] = 5 # => You've just tried to set '5' for '0' of @cascade!
x[0][0] = 10 #= > ~ no output ~
答案 0 :(得分:1)
问题是你在主数组中包含的子数组上调用[] =。
换句话说,你在你的类上调用[],你实现它来返回那个数组元素,然后在一个通用数组上调用[] =你没有阻止写入访问权限。
你可以实现这个结构让你的类通过使用MyClass的其他实例来创建它的子数组,或者你可以覆盖Array的[] =方法来限制访问。
还值得注意的是,取决于如何使用它,在像Array这样的类上覆盖方法通常不是一个好主意,所以你可能想要像我的第一个建议那样。
答案 1 :(得分:0)
在Ruby中,您可以修改对象,添加新方法,自由重新定义旧方法。因此,您可以修补您创建的所有阵列,以便他们告诉您何时访问它们。
class A
def patch_array(arr)
class << arr
alias old_access_method []=
def []= (i, v)
@cascade_object.detect_access(self)
old_access_method(i,v)
end
end
s = self
arr.instance_eval {
@cascade_object = s
}
end
def detect_access(arr)
p 'access detected!'
end
end
a = A.new
arr = [1, 2]
a.patch_array(arr)
arr[1] = 3 # prints 'access detected!'
p arr
new_arr = [1,4]
new_arr[1] = 5 #prints nothing
p new_arr
答案 2 :(得分:0)
#!/usr/bin/ruby1.8
require 'forwardable'
class MyClass
extend Forwardable
attr_accessor :cascade
def initialize string
@cascade = decorate(build_cascade string.split(//))
end
private
def build_cascade array
if array.length <= 2
array
else
build_cascade([array[0..1]] + array[2..-1])
end
end
def decorate(array)
return array unless array.is_a?(Array)
class << array
alias old_array_assign []=
def []=(index, value)
puts "#{self}[#{index}] = #{value}"
old_array_assign(index, value)
end
end
array.each do |e|
decorate(e)
end
array
end
def_delegators :@cascade, :[], :[]=
end
x = MyClass.new('abcdefghigk')
p x.cascade
# => [[[[[[[[[["a", "b"], "c"], "d"], "e"], "f"], "g"], "h"], "i"], "g"], "k"]
x[0][1] = 5 # => abcdefghig[1] = 5
x[0][0][1] = 10 # => abcdefghi[1] = 10
x[0][0][0][1] = 100 # => abcdefgh[1] = 100
p x.cascade
# => [[[[[[[[[["a", "b"], "c"], "d"], "e"], "f"], "g"], 100], 10], 5], "k"]