Suche…


Einführung

Metaprogrammierung kann auf zwei Arten beschrieben werden:

"Computerprogramme, die andere Programme (oder sich selbst) als ihre Daten schreiben oder bearbeiten oder zur Kompilierzeit einen Teil der Arbeit erledigen, der sonst zur Laufzeit erledigt würde"

Einfacher ausgedrückt: Metaprogrammierung schreibt Code, der zur Laufzeit Code schreibt, um Ihnen das Leben zu erleichtern .

"Mit" mit Instanzbewertung implementieren

In vielen Sprachen gibt es eine with Anweisung, mit der Programmierer den Empfänger von Methodenaufrufen auslassen können.

with kann in Ruby mit instance_eval leicht emuliert werden:

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

Die with Methode kann verwendet werden, um Methoden nahtlos an Objekten auszuführen:

hash = Hash.new

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

Methoden dynamisch definieren

Mit Ruby können Sie die Programmstruktur während der Ausführung ändern. Eine Möglichkeit besteht darin, Methoden dynamisch mit der Methode method_missing .

Nehmen wir an, wir wollen mit der Syntax 777.is_greater_than_123? testen können, ob eine Zahl größer als eine andere Zahl ist 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

Eine wichtige Sache, die Sie bei der Verwendung von method_missing beachten sollten, damit auch respond_to? überschrieben respond_to? Methode:

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

Wenn Sie dies 600.is_greater_than_123 , führt dies zu einer inkonsistenten Situation, wenn Sie erfolgreich 600.is_greater_than_123 aufrufen können. 600.is_greater_than_123 , aber 600.respond_to(:is_greater_than_123) gibt false zurück.

Methoden für Instanzen definieren

In Ruby können Sie vorhandenen Instanzen einer beliebigen Klasse Methoden hinzufügen. Auf diese Weise können Sie einer Klasse Verhalten hinzufügen und eine Instanz hinzufügen, ohne das Verhalten der übrigen Instanzen dieser Klasse zu ändern.

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}

send () -Methode

send() wird verwendet, um eine Nachricht an ein object . send() ist eine Instanzmethode der Object Klasse. Das erste Argument in send() ist die Nachricht, die Sie an das Objekt senden, dh den Namen einer Methode. Es kann sich um einen string oder ein symbol aber Symbole werden bevorzugt. Dann Argumente, die in method übergeben werden müssen, das sind die restlichen Argumente 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.

Hier ist das anschaulichere Beispiel

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

Hinweis: send() selbst wird nicht mehr empfohlen. Verwenden Sie __send__() , mit dem private Methoden aufgerufen werden können, oder (empfohlen) public_send()



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow