Sam
Sam

Reputation: 5250

Meta Programming - dynamic method

I have 2 versions of Computer class here. I'm seeing that Computer2 is much better than Computer1. Both Computer classes yield the same result. How the Computer2 class varies from Computer1 class?

class DataSource
  def cpu_info(computer_id)
    "#{computer_id}'s CPU"
  end

  def cpu_price(computer_id)
    12
  end

  def mouse_info(computer_id)
    "#{computer_id}'s mouse"
  end

  def mouse_price(computer_id)
    27
  end

  def monitor_info(computer_id)
    "#{computer_id}'s monitor"
  end

  def monitor_price(computer_id)
    33
  end
end

# Step 1
class Computer1
  def initialize(computer_id, data_source)
    @id = computer_id
    @ds = data_source
  end

  def cpu
    get_info :cpu
  end

  def mouse
    get_info :mouse
  end

  def monitor
    get_info :monitor
  end

  def get_info(component)
    component_info = @ds.send("#{component}_info", @id)
    component_price = @ds.send("#{component}_price", @id)
    data = "The work station #{component_info} is about #{component_price}$"
    return data;
  end
end

computer = Computer1.new(1, DataSource.new)
computer.cpu #The work station 1's CPU is about 12$

# Step 2 - Further simplified
class Computer2
  def initialize(computer_id, data_source)
    @id = computer_id
    @ds = data_source
  end

  def self.get_info(component)
    define_method(component) do
      component_info = @ds.send("#{component}_info", @id)
      component_price = @ds.send("#{component}_price", @id)
      data = "The work station #{component_info} is about #{component_price}$"
      return data;
    end
  end

  get_info :mouse
  get_info :cpu
  get_info :monitor
end

computer = Computer2.new(1, DataSource.new)
computer.cpu #The work station 1's CPU is about 12$

My question is how the following is possible as there is no instance cpu method in Computer2 class

computer = Computer2.new(1, DataSource.new)
computer.cpu

Upvotes: 0

Views: 60

Answers (2)

Dimitrius Lachi
Dimitrius Lachi

Reputation: 1287

In the Computer2 class, you call the method :get_info:

get_info :mouse
get_info :cpu
get_info :monitor

This methods, call the ruby function :define_method (https://apidock.com/ruby/Module/define_method), this method creates a named function for you instance in this case, and after call get_info(:cpu) you have the .cpu method to call, with the giving block:

component_info = @ds.send("#{component}_info", @id)
component_price = @ds.send("#{component}_price", @id)
data = "The work station #{component_info} is about #{component_price}$"
return data;

Upvotes: 1

ray
ray

Reputation: 5552

When your class Computer2 is loaded, self calls get_info class method with argument :cpu which is later used to define instance method cpu for your Computer2 instance.

Read define_method

Upvotes: 1

Related Questions