2

I am trying to reduce the amount of code in on of my Ruby Classes by Iterating through a constant hash in order to produce al the wanted methods with a reduced amount of coding.

Here is my code (Please feel free to add additional pointers as I'm new to Ruby):

ENTRY_HASHES = {
    "disbursement" => {
        :description => TRANSACTION_DESCRIPTIONS[:disbursement]
    }
}

public

    ENTRY_HASHES.each do |key, value|
        def "#{value}?(amount)"
            single_entry(
              ENTRY_HASHES[:description]
              amount
            )

            @entry.save
        end
    end

What I'm expecting from the above is something like this (for each of the hashes in ENTRY_HASHES):

def disbursement?(value)
  single_entry(
     "XXXXX",
      amount
  )
end

Instead, I'm presented with a syntax error. Any help will be appreciated!

Nakilon
  • 34,866
  • 14
  • 107
  • 142
HermannHH
  • 1,732
  • 1
  • 27
  • 57

3 Answers3

3

Here is the example for you:

ENTRY_HASHES = {
  "disbursement" => {
    :description => 'smth'
  }
}

ENTRY_HASHES.each do |key, value|
  define_method("#{key}?") do |argument|
    puts "#{key}? method called with #{argument}"
    puts "you can use hash values: #{value} of course"
  end
end

disbursement?('my_arg')

it will output:

disbursement? method called with my_arg
you can use hash values: {:description=>"smth"} of course
Rustam Gasanov
  • 15,290
  • 8
  • 59
  • 72
  • In Rails 3.1.6 console, Please advise regarding, NoMethodError: undefined method `define_method' for main:Object – rhunal Jan 05 '18 at 07:40
2

Here you can look at an example:

(class << self; self; end).instance_eval do
                define_method(key) do |message|
                  @@logger_dictionary[key].send(key,message)
                end
              end

Here I add to a class (class as instance) methods. (add Class Methods)

Also, I like to add method to instances of class (or objects) (add Instance Methods)

class YourClass
 def setupMethod
  self.class.send(:define_method,key){
                        |*args|
                        @dictionary[key]
                }

                self.class.send(:define_method,key + '='){
                    |*args|
                    @dictionary[key] = args.first if args.first
                }
 end
end

Maybe you can catch an answer from my answer :)

ENTRY_HASHES.each do |key, value|
        self.class.send(:define_method, "#{value}?(amount)") {
            |*args|
            single_entry(
              ENTRY_HASHES[:description]
              amount
            )

            @entry.save
        }
    end
gaussblurinc
  • 3,642
  • 9
  • 35
  • 64
1

The technique you want involves meta-programming, you should take a look at this example, taken from the Ruby Monk:

class Doctor
  define_method("perform_rhinoplasty") do |argument|
        "performing rhinoplasty on #{argument}"
  end

  define_method("perform_checkup") do |argument|
        "performing checkup on #{argument}"
  end

  define_method("perform_interpretive_dance") do |argument|
    "performing interpretive dance on #{argument}"
  end
end

doctor = Doctor.new
puts doctor.perform_rhinoplasty("nose")
puts doctor.perform_checkup("throat")
puts doctor.perform_interpretive_dance("in da club")
Paulo Fidalgo
  • 21,709
  • 7
  • 99
  • 115