开发者

Ruby: overloading indexed assignment to instance attributes

For the instances of a class that I'm writing (an ActiveRecord model), I'd like to be able to overload assignments like this:

m.rank['foo'] = 1
m.rank['bar'] = 2

In other words, I don't want the numbers to be written into an actual @rank hash, but rather I'd like to have some setter method called with 'foo' and 1 as its parameters.

A naive way to get this functionality wo开发者_StackOverflow中文版uld be to define set_rank(key, rank) and get_rank(key), but the syntax isn't very sugary. For nicer syntax, one could define a helper class that defines [] and []=, and have the rank method return an instance of that class.

Is there an established pattern to write this in a concise manner? Or is it a bad idea in the first place, and I should just use set_rank and get_rank?


You can achieve this by initialising your rank attribute like so:

@rank = {}

def @rank.[] key
    puts "Retrieving key #{key}" #put code to execute when key is retrieved here
    begin
        self.fetch key
    rescue
        puts "Key not found" #put code to execute when key is not found here
        nil
    end
end

def @rank.[]= key, val
    puts "Setting key #{key} to #{val}" #put code to execute when key is set here
    self.store key, val
end

You will need to do this in your initialize method and use attr_reader :rank (recommended) or attr_accessor :rank.

Explanation

This uses a feature of Ruby called singleton methods. Singleton methods are where you define methods on specific objects rather than on all instances of a class. You can define singleton methods on any object. The syntax is, as above, def identifier.method ... end.


I think it's pretty ugly and totally useless. My solution:

class Test
    attr_accessor :rank

    def initialize
        @rank = Rank.new
    end

    def meth(key, rank)
        print key, " ", rank
    end 

    class Rank
        def []=(key, rank)
            @test = Test.new
            @test.meth(key, rank)
        end
    end

end

m = Test.new
m.rank["key"] = "rank" # => key rank
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜