Ricerca…


introduzione

La metaprogrammazione può essere descritta in due modi:

"Programmi per computer che scrivono o manipolano altri programmi (o se stessi) come dati, o che fanno parte del lavoro in fase di compilazione che altrimenti verrebbero eseguiti in fase di esecuzione".

Più semplicemente: Metaprogramming sta scrivendo un codice che scrive codice durante il runtime per semplificarti la vita .

Implementare "con" usando la valutazione dell'istanza

Molte lingue sono dotate di with dichiarazione che consente ai programmatori di omettere il ricevitore di chiamate di metodo.

with può essere facilmente emulato in Ruby usando instance_eval :

def with(object, &block)
  object.instance_eval &block
end

Il metodo with può essere utilizzato per eseguire senza problemi metodi sugli oggetti:

hash = Hash.new

with hash do
  store :key, :value
  has_key? :key       # => true
  values              # => [:value]
end

Definizione dei metodi in modo dinamico

Con Ruby puoi modificare la struttura del programma in tempo di esecuzione. Un modo per farlo è definire i metodi in modo dinamico usando il metodo method_missing .

Diciamo che vogliamo essere in grado di verificare se un numero è maggiore di un altro numero con la sintassi 777.is_greater_than_123? .

# open Numeric class
class Numeric
  # override `method_missing`
  def method_missing(method_name,*args)
    # test if the method_name matches the syntax we want
    if method_name.to_s.match /^is_greater_than_(\d+)\?$/
      # capture the number in the method_name
      the_other_number = $1.to_i
      # return whether the number is greater than the other number or not
      self > the_other_number
    else
      # if the method_name doesn't match what we want, let the previous definition of `method_missing` handle it
      super
    end
  end
end

Una cosa importante da ricordare quando si usa method_missing anche quello di sovrascrivere respond_to? metodo:

class Numeric
   def respond_to?(method_name, include_all = false) 
     method_name.to_s.match(/^is_greater_than_(\d+)\?$/) || super
   end
end

Dimenticare di farlo porta a una situazione incoerente, quando è possibile chiamare correttamente 600.is_greater_than_123 , ma 600.respond_to(:is_greater_than_123) restituisce false.

Definizione dei metodi su istanze

In ruby ​​puoi aggiungere metodi a istanze esistenti di qualsiasi classe. Ciò consente di aggiungere un comportamento e un'istanza di una classe senza modificare il comportamento del resto delle istanze di quella classe.

class Example
  def method1(foo)
    puts foo
  end
end

#defines method2 on object exp
exp = Example.new
exp.define_method(:method2) {puts "Method2"}

#with method parameters
exp.define_method(:method3) {|name| puts name}

metodo send ()

send() è usato per passare il messaggio object . send() è un metodo di istanza della classe Object . Il primo argomento di send() è il messaggio che stai inviando all'oggetto, cioè il nome di un metodo. Potrebbe essere una string o un symbol ma i simboli sono preferiti. Quindi gli argomenti che devono passare nel metodo, quelli saranno gli argomenti rimanenti in send() .

class Hello
  def hello(*args)
    puts 'Hello ' + args.join(' ')
  end
end
h = Hello.new
h.send :hello, 'gentle', 'readers'   #=> "Hello gentle readers"
# h.send(:hello, 'gentle', 'readers') #=> Here :hello is method and rest are the arguments to method.

Ecco l'esempio più descrittivo

class Account
  attr_accessor :name, :email, :notes, :address

  def assign_values(values)
    values.each_key do |k, v|
      # How send method would look a like
      # self.name = value[k]
      self.send("#{k}=", values[k])
    end
  end
end

user_info = {
  name: 'Matt',
  email: '[email protected]',
  address: '132 random st.',
  notes: "annoying customer"
}

account = Account.new
If attributes gets increase then we would messup the code
#--------- Bad way --------------
account.name = user_info[:name]
account.address = user_info[:address]
account.email = user_info[:email]
account.notes = user_info[:notes]

# --------- Meta Programing way --------------
account.assign_values(user_info) # With single line we can assign n number of attributes

puts account.inspect

Nota: send() stesso non è più raccomandato. Usa __send__() che ha il potere di chiamare metodi privati ​​o (consigliato) public_send()



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow