Extending an instance using methods from another instance of another class

I am currently doing something like the following to have the Runnable

classes method accessors run

for ExecutionContext

:

class ExecutionContext
  def message(text)
    puts "ExecutionContext.message: #{text}"
  end 
  def answer?
    puts "ExecutionContext.answer called"
    true
  end
end

class Controller
  def do_run(context)
    @context = context
    run
    @context = nil
  end

  def method_missing(mth, *args)
    @context.send(mth, *args)
  end
end

class Runnable < Controller
  def run
    if answer?
      message "Runnable block executing!"
    end
  end
end

runnable = Runnable.new

context = ExecutionContext.new
runnable.do_run(context)

      

The idea is that the class is Runnable

written by "end users" who want to access the functions (eg, methods message

and answer?

) of an instance ExecutionContext

that is provided from other sources. In fact, a class Runnable

is the entire "end user" and should be as small and simple as possible.

The above code works as expected, that all methods called Runnable.run

are provided ExecutionContext

.

However, I'm wondering if there is a more elegant way to achieve the same, where I can avoid using method_missing

and defining a temporary variable @context

.

Ideally I would like to change the code to something similar to this ( ExecutionContext

remains unchanged):

class Controller
  def do_run(context, runnable)
    runnable.extend_from_instance(context)
    runnable.run
  end
end

class Runnable
  def run
    if answer?
      message "Runnable block executing!"
    end
  end
end

runnable = Runnable.new
context = ExecutionContext.new
Controller.new.do_run(context, runnable)

      

Is there such a thing as extend_from_instance

?

Update

Thank you everyone for looking at this.

Since it appeared in the two answers I've received so far, I realized that I should mention the following restrictions: Unfortunately, neither Runnable

, nor ExecutionContext

can be turned into module

s. They should be class

es as their instances will behave differently for different cases (both will have their own instance variables, etc.).

I really need a method run

to execute as if it were part of an instance ExecutionContext

( context

in code).

+3


source to share


2 answers


Yes, you don't want to use method_missing

in this case.

I really don't understand what you are trying to achieve. Perhaps define_block

not the correct name ...?

However, the module appears to have the required functionality.

module Messaging
  def message(text)
    puts "Provider.message: #{text}"
  end 
end

class Parent
  include Messaging
  ...

      

EDIT: I think you want to use anchor. It allows you to transfer the current area (context) to another area.



def print_local binding
  puts 'local is ' + binding.eval('local')
end

def foo
  local = 'value'
  print_local binding
end

foo 
=> local is value

      

In this case, print_local wants to print the variable foo local

. But it doesn't have access to it because it local

only exists in the scope of foo (or context).

So, you can go to scope foo like binding

.

See binding .

+1


source


I think B Seven said correctly. The most reasonable to establish a common functionality Module

, and include

this module in class. However, if you really want something like your own extend_from_instance

, you can use Ruby Object # extend to dynamically extend a module on a class instance (although I think this is a bad idea). Create the code you want:

module ExecutionContext
  def message(text)
    puts "ExecutionContext.message: #{text}"
  end 
  def answer?
    puts "ExecutionContext.answer called"
    true
  end
end

class Controller
  def do_run(context_module, runnable)
    runnable.extend(context_module)
    runnable.run
  end
end

class Runnable
  def run
    if answer?
      message "Runnable block executing!"
    end
  end
end

runnable = Runnable.new
Controller.new.do_run(ExecutionContext, runnable)

      



Again, this is a bad idea and will probably come back to bite you eventually.

0


source







All Articles