3

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 would 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?

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.