Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically open a method in Ruby

I want to dynamically open a method and return a value based on the input field. I am trying to ask what I want with an example here. If I could succeed this example, I would do what I want.

Assume I have a class called Greetings which has a method called greet() which takes message as argument.

class Greetings
   def self.greet(message)
      return "good morning" if message=="gm"
      return "evening" if message=="ge"
      return "good afternoon" if message=="ga"
   end
end

When I do a Greetings.greet("ge"), I get "evening" as the output. I want to change this behavior without changing the above Greetings class (obvious reason is that its an external library).

My question here is simple. What should I do when say I call Greetings.greet("ge") should return me "A Very Good Evening" and for all the other inputs, it should return what the original class returns. I know something about dynamically opening a class in Ruby but how would I delegate the method to parent for the other cases?

And I would be writing this inside the config/initializers folder since I am using Rails.

like image 398
bragboy Avatar asked Feb 27 '26 03:02

bragboy


1 Answers

Method aliasing

You can alias your old method as old_greet for example, and redefine with your own:

class Greetings
  class << self
    alias_method :old_greet, :greet

    def greet(message)
      (message == "ge") ? "A Very Good Evening" : old_greet(message)
    end
  end
end

and then you can:

puts Greetings.greet("ge")

Method chaining

With the Rails alias_method_chain feature:

class Greetings
  class << self
    def greet_with_modifications(message)
      (message == "ge") ? "A Very Good Evening" : greet_without_modifications(message)
    end

    alias_method_chain :greet, :modifications
  end
end

and then you can:

puts Greetings.greet("ge")

Extending class

You can create your own class which extends the original like this:

module My
  class Greetings < ::Greetings
    def self.greet(message)
      case message
        when "ge"
          "A Very Good Evening"
        else
          super(message)
      end
    end
  end
end

and then you can:

puts My::Greetings.greet("ge")
like image 197
KARASZI István Avatar answered Mar 01 '26 17:03

KARASZI István