corsel
corsel

Reputation: 325

How can i treat functions like objects in ruby?

In my ruby project, i want to create a task manager class which will periodically iterate through an array of registered functions. I need to pass functions as argument to the register function, create a thread and when the thread timer fires, it needs to call each function in array.

class TaskMan

    @@func_array = Array.new

    def self.register_func &arg_func
        @@func_array.push arg_func
    end

    def self.run_server
        loop do
            @@func_array.each do |func|
                func.call
            end
            sleep 60 
        end
    end

end

class Callee

    def self.func_0
       puts "func_0 called."
    end

    def self.func_1
        puts "func_1 called."
    end

end

TaskMan.register_func Callee.func_0
TaskMan.register_func Callee.func_1

taskman_thread = Thread.new do
    TaskMan.run_server
end
taskman_thread.join

Basically, this is what i want to do, but i'm not sure how to use to_proc and call, to push in the functions and call them.

Other solutions are also appreciated, but i don't want to avoid learning passing functions as arguments, putting them in array and calling them.

Thanks.

Upvotes: 0

Views: 76

Answers (3)

mu is too short
mu is too short

Reputation: 434755

Use the method method to get the class methods as callable objects (Method instances in this case) and then apply & to those objects:

TaskMan.register_func &Callee.method(:func_0)
TaskMan.register_func &Callee.method(:func_1)

Now you can throw all sorts of things into the func_array:

TaskMan.register_func &SomeClass.method(:m)   # class method
TaskMan.register_func &some_object.method(:m) # an instance method
TaskMan.register_func &some_lambda            # a lambda function
TaskMan.register_func { puts "pancakes" }     # a block
# etc.

Upvotes: 2

bjhaid
bjhaid

Reputation: 9762

You can instead pass the receiver and the function you intend calling as below:

class TaskMan

  @@func_array = Array.new

  def self.register_func(receiver, func)
    @@func_array.push([receiver, func])
  end

  def self.run_server
    loop do
      @@func_array.each do |(receiver, func)|
        receiver.method(func).call
      end
      sleep 60
    end
  end

end

class Callee

  def self.func_0
    puts "func_0 called."
  end

  def self.func_1
    puts "func_1 called."
  end

end

TaskMan.register_func Callee, :func_0
TaskMan.register_func Callee, :func_1

taskman_thread = Thread.new do
  TaskMan.run_server
end
taskman_thread.join

Upvotes: 1

Eli Sadoff
Eli Sadoff

Reputation: 7308

Let's say you have methods func_0 and func_1. To call them using array iteration you can do this

methods = [:func_0, :func_1]
methods.each do |m|
  send(m)
end

Upvotes: 0

Related Questions