--Metaprogramming schreibt Code, der Code schreibt.
In der Programmierung und in Ruby ist Introspektion im Allgemeinen die Fähigkeit, Objekte, Klassen usw. zur Laufzeit zu sehen, um sie zu kennen.
vgl. Ruby Introspektion
Beispiel:
#Unten ist die Klassendefinition
class A
def a; end
end
module B
def b; end
end
class C < A
include B
def c; end
end
##Selbstbeobachtung
# Q.Was ist eine C-Instanzmethode?
# A. C.instance_methods # [:c, :b, :a, :to_json, :instance_of?...]
# Q.Was ist eine Instanzmethode, die nur C deklariert?
# A. C.instance_methods(false) # [:c]
# Q.Was sind die Vorfahren der Klasse C?
# A. C.ancestors # [C, B, A, Object,...]
# Q.C Superklasse?
# A. C.superclass # A
# the_m_word/orm.rb
class Entity
attr_reader :table, :ident
def initialize(table, ident)
@table = table
@ident = ident
Database.sql "INSERT INTO #{@table} (id) VALUES (#{@ident})"
end
def set(col, val)
Database.sql "UPDATE #{@table} SET #{col}='#{val}' WHERE id=#{@ident}"
end
def get(col)
Database.sql("SELECT #{col} FROM #{@table} WHERE id=#{@ident}")[0][0]
end
end
Auch wenn Sie die obige Klasse nicht schreiben Sie können Code schreiben, der zur Laufzeit Zugriffsmethoden definiert, indem Sie einfach ActiveRecord :: Base erben.
Die Hauptaufgabe von class
ist es, Sie in den Kontext der Klasse zu bringen.
Es ist eher ein Bereichsoperator als eine Klassendeklaration.
Sie können vorhandene Klassen, einschließlich Standardklassen, erneut öffnen und im laufenden Betrieb ändern.
Einfache Patches für Klassen, z. B. wenn Sie die ursprüngliche Methode mit demselben Namen überschreiben, werden als Affen-Patches bezeichnet.
--Klasse ist ein Objekt
#Vom Argument"false"Bedeutet "geerbte Methoden ignorieren"
Class.instance_methods(false) # => [:allocate, :new, :superclass]
Class.superclass # => Module
Alle großgeschriebenen Referenzen, einschließlich Klassen- und Modulnamen, sind Konstanten.
Sie können auch den Wert der Konstante ändern.
Sie können auch den Wert der String-Klasse ändern, um Ruby zu brechen.
Ähnlichkeit zwischen Ruby-Konstanten und Dateien
Alle Konstanten im Programm sind wie ein Dateisystem in einem Baum angeordnet.
Module und Klassen sind Verzeichnisse und Konstanten sind Dateien.
--Instanzmethode Modul # Konstanten
# => [: C,: Y]
Module.constants
Module.nesting
# => [M :: C :: M2, M :: C, M]
new
--Verwenden Sie den Klassennamen, um auf die Klasse zu verweisen.load
require
MyClass
class
=> Class
superclass
=> Object
Object
class
=> Class
Class
class
=> Class
superclass
=> Module
Module
superclass
=> Object
MySubClass.ancestors # => [MySubclass, MyClass, Object, Kernel, BasicObject]
module M1
def my_method
'My#my_method()'
end
end
class C
include M1
end
class D < C; end
D.ancestors # => [D, C, M, Object, Kernel, BasicObject]
--Ruby-Code wird innerhalb von ** aktuelles Objekt selbst ** ausgeführt.
--State, wenn die Methode nicht aufgerufen wird oder wenn alle aufgerufenen Methoden zurückgegeben werden
self # => main
self.class # => Object
class MyClass
self # => MyClass
end
Sie können keine privaten Methoden mit einem expliziten Empfänger aufrufen
Die private Methode muss für den impliziten Empfänger self sein.
Nur Sie können eine Methode mit privat aufrufen.
Beispiel 1 --Objekt x kann die private Methode des Objekts y derselben Klasse nicht aufrufen.
Weil Sie den Empfänger explizit angeben müssen, um die Methoden anderer Objekte unabhängig von der Klasse aufzurufen.
Beispiel 2
Sie können private Methoden aufrufen, die von Oberklassen geerbt wurden.
Da sich die geerbte Methode an Ihrer Stelle befindet, müssen Sie den Empfänger beim Aufruf nicht explizit angeben.
Refinements
module StringExtensions
refine String do
def reverse
"esrever"
end
end
end
module StringStuff
using StringExtensions
"my_string".reverse # => "esrever"
end
"my_string".reverse # => "gnirts_ym"
--Refinierungen sind nur an zwei Stellen aktiviert.
-Ein Objekt besteht aus mehreren Instanzvariablen und Verknüpfungen zu Klassen.
-Die Methoden des Objekts befinden sich in der Klasse des Objekts (aus Sicht der Klasse wird sie als Instanzmethode bezeichnet).
-Eine Klasse ist ein Objekt der Klassenklasse. Klassenkameraden sind nur Konstanten.
-Klasse ist eine Unterklasse von Module. Ein Modul ist im Grunde eine Sammlung von Methoden. Darüber hinaus können Klassen mit neu instanziiert oder hierarchisch mit Superklasse erstellt werden.
-Die Konstanten sind wie ein Dateisystem in einem Baum angeordnet. Module und Klassen werden als Verzeichnisse bezeichnet, und reguläre Konstanten sind wie Dateien.
-Jede Klasse hat eine Vererbungskette, die sich auf BasicObject erstreckt.
-Wenn Sie die Methode aufrufen, geht Ruby einen Schritt nach rechts in Richtung der Klasse des Empfängers und dann die Vererbungskette hinauf. Es wird fortgesetzt, bis Sie eine Methode entdecken oder die Vererbungskette beenden.
-Wenn Sie ein Modul in eine Klasse aufnehmen, wird das Modul direkt über der Vererbungskette für diese Klasse eingefügt. Durch das Vorabschreiben eines Moduls wird es direkt unter der Vererbungskette für diese Klasse eingefügt.
-Beim Aufruf der Methode wird der Empfänger selbst.
-Wenn Sie ein Modul (oder eine Klasse) definieren, wird dieses Modul selbst.
-Instanzvariablen werden immer als Selbstinstanzvariablen betrachtet.
-Wenn Sie eine Methode aufrufen, ohne einen Empfänger explizit anzugeben, wird sie als Selbstmethode betrachtet.
-Verfeinerungen sind wie das Patchen von Klassencode und das Überschreiben der normalen Methodensuche. Verfeinerungen sind jedoch nur in einem begrenzten Bereich von dem Punkt gültig, an dem die Verwendung aufgerufen wird, bis zu dem Punkt, an dem die Definition der Datei oder des Moduls endet.
"Das Aufrufen einer Methode bedeutet das Senden einer Nachricht an das Objekt."
Verwenden Sie die Punktnotation oder "Object # send", um die Methode aufzurufen.
obj = MyClass.new
obj.my_method(3) # => 6
obj.send(:my_method, 3) # => 6
--Mit Verwendung von "Senden" wird der Name der Methode, die Sie aufrufen möchten, zu einem normalen Argument, und Sie können entscheiden, welche Methode aufgerufen werden soll, wenn der Code ausgeführt wird.
def refresh(options={})
defaults = {}
attributes = [ :input, :output, :commands, :print, :quiet,
:exception_handler, :hooks, :custom_completions,
:prompt, :memory_size, :extra_sticky_locals ]
attributes.each do |attribute|
defaults[attribute] = Pry.send attribute
end
# ...
defaults.merge!(options).each do |key, value|
# memory_size=Der Accessor des Attributs wie wird aufgerufen.
send("#{key}=", value) if respond_to?("#{key}=")
end
true
end
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def mouse
component :mouse
end
def cpu
component :cpu
end
def keyboard
component :keyboard
end
def component(name)
info = @data_source.send "get_#{name}_info", @id
price = @data_source.send "get_#{name}_price", @id
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
end
Module#define_method
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
end
obj = MyClass.new
obj.my_method(2) # => 6
--Code-Beispiel mit definierter define_method
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def self.define_component(name)
define_method(name) do
info = @data_source.send "get_#{name}_info", @id
price = @data_source.send "get_#{name}_price", @id
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
end
define_component :mouse
define_component :cpu
define_component :keyboard
end
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
# Array#Wenn Sie einen Block an grep übergeben, wird der Block für alle Elemente ausgewertet, die dem regulären Ausdruck entsprechen.
#Die Zeichenfolge, die den Klammern des regulären Ausdrucks entspricht, ist eine globale Variable$Gespeichert in 1.
#Beispiel: data_Quelle ist bekommen_cpu_info und bekommen_mouse_Wenn Sie zwei Informationsmethoden haben
# Computer.define_Sie rufen die Komponente zweimal auf (übergeben Sie die Zeichenfolgen "CPU" bzw. "Maus").
data_source.methods.grep(/^get_(.*)_info$/) { Computer.define_component $1 }
end
def self.define_component(name)
define_method(name) do
# ...
end
end
end
method_missing
method_missing
auf, um den Verlust zu akzeptieren.
--method_missing
ist die "private" Instanzmethode von "BasicObject", die von allen Objekten geerbt wird.nick.send :method_missing, :my_method
# => NoMethodError: undefined method `my_method` for #<Lawyer:0x007f801b0f4978>
class Lawyer
def method_missing(method, *args)
puts "Namens:#{method}(#{args.join(', ')})"
puts "(Ich habe auch den Block passiert)" if block_given?
end
end
bob = Lawyer.new
bob.talk_simple('a', 'b') do
#Block
end
# =>Genannt: reden_simple(a, b)
#(Ich habe auch den Block passiert)
BasiObject # method_missing
lautet NoMethodError.--Diese Nachricht wird von method_missing verarbeitet und sieht aus wie ein normaler Aufruf an den Aufrufer, aber die entsprechende Methode wird auf der Empfängerseite nicht gefunden.
module Hashie
class Mash < Hashie::Hash
def method_missing(method_name, *args, &blk)
#Wenn der Name der aufgerufenen Methode ein Hash-Schlüssel ist[]Rufen Sie die Methode auf und geben Sie den entsprechenden Wert zurück.
return self.[](method_name,&blk)ifkey?(method_name)
#Das Ende des Methodennamens lautet "="Wenn,"=Entfernen Sie das "", um den Namen des Attributs abzurufen, und behalten Sie dann seinen Wert bei.
#Wenn beides nicht übereinstimmt, Methode_fehlt gibt den Standardwert zurück.
match = method_name.to_s.match(/(.*?)([?=!]?)$/)
case match[2]
when "="
self[match[1]] = args.first
else
default(method_name, *args, &blk)
end
end
end
end
Ein umschlossenes Objekt, das Methodenaufrufe auf method_missing
konzentriert, die Ghost-Methode ergänzt und auf ein anderes Objekt überträgt.
Beispiel für Ghee (eine Bibliothek mit einfachem Zugriff auf die HTTP-API von GitHub)
class Ghee
class ResourceProxy
# ...
def method_missing(message, *args, &block)
# my_gist.Hashie, ein Methodenaufruf wie url::Mash#method_Übergabe an Vermisste.
subject.send(message, *args, &block)
end
def subject
#Empfangen Sie das GitHub-Objekt in JSON und Hasie::In Mash konvertieren.
@subject ||= connection.get(path_prefix){|req| req.params.merge!params }.body
end
end
end
--Gee hält den Code mit diesem zweistufigen Design einfach.
Beim Lesen von Daten gibt es eine Ghost-Methode, sodass keine Methode definiert werden muss.
Definieren Sie Methoden nur, wenn Sie bestimmten Code wie "Stern" benötigen.
Ein weiterer Vorteil dieser dynamischen Methoden besteht darin, dass sie automatisch auf Änderungen in der GitHub-API reagieren können.
Auch wenn GitHub ein neues Feld hinzufügt, ist es auch eine Ghost-Methode, sodass Ghee den Aufruf unterstützen kann, ohne den Quellcode zu ändern.
Refactoring von Computerklassen mit method_missing
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
# BasicObject#method_Überschreiben fehlt
def method_missing(name)
super if !@data_source.respond_to?("get_#{name}_info")
info = @data_source.send("get_#{name}_info", @id)
price = @data_source.send("get_#{name}_price", @id)
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
#Antworten Sie, um festzustellen, ob es eine Geistermethode gibt_to_missing?Wird richtig überschrieben.
def respond_to_missing?(method, include_private = false)
@data_source.respond_to?("get_#{method}_info") || super
end
end
Module#const_missing
--Beispiel, wenn Task aufgrund eines Upgrades in Rake :: Task umbenannt wird
class Module
def const_missing(const_name)
case const_name
when :Task
#Warnen Sie vor der Verwendung veralteter Klassennamen.
Rake.application.const_warning(const_name)
Rake::Task
when :FileTask
Rake.application.const_warning(const_name)
Rake::FileTask
when :FileCreationTask
# ...
end
end
end
class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize
3.times do
number = rand(10) + 1
puts "#{number}..."
end
"#{person} got a #{number}"
end
end
--BasicObject, das die Wurzel der Klassenhierarchie von Ruby ist, verfügt nur über die minimal erforderlichen Methoden. Um schnell eine leere Tafel in Ruby zu definieren, sollte BasicObject vererbt werden.
-Die Ghost-Methode ist ein grundlegender Ratschlag (immer super anrufen, immer antworten_to_missing?Neudefinitionen), wodurch die meisten Probleme vermieden werden, aber dennoch komplexe Fehler verursacht werden.
-Da die Ghost-Methode keine echte Methode ist, verhält sie sich anders als die eigentliche Methode.
-In einigen Situationen können nur Ghost-Methoden verwendet werden, z. B. wenn eine große Anzahl von Methodenaufrufen vorliegt oder wenn die aufzurufende Methode nur zur Laufzeit bekannt ist.
-"Verwenden Sie nach Möglichkeit dynamische Methoden und Ghost-Methoden, wenn Sie nicht helfen können."
--Block ist Mitglied einer großen Familie von "aufrufbaren Objekten". --Brocks Familie hat eine andere Abstammung als objektorientiert und folgt dem Fluss von "funktionalen Programmiersprachen" wie LISP.
--Blöcke können nur beim Aufruf einer Methode definiert werden.
def my_method
#Die Bindungen in der Methode sind für den Block nicht sichtbar.
x = "Goodbye"
yield("cruel")
end
x = "Hello"
#Wickeln Sie eine lokale Bindung wie x ein und übergeben Sie den Block an die Methode.
my_method = {|y| "#{x}, #{y} world"} # => "Hello, cruel world"
#Auf globale Variablen kann von jedem Bereich aus zugegriffen werden.
def a_scope
$var = "some value"
end
def another_scope
$var
end
a_scope
another_scope # => "some value"
#Instanzvariablen der obersten Ebene sind Instanzvariablen des Hauptobjekts auf der obersten Ebene.
#Sie können es von jedem Ort aus aufrufen, an dem die Hauptleitung selbst wird.
#Wenn das andere Objekt selbst wird, verlässt die Instanzvariable der obersten Ebene den Gültigkeitsbereich.
@var = "Variablen der obersten Ebene@var"
def my_method
@var
end
my_method # => "Variablen der obersten Ebene@var"
class MyClass
def my_method
@var = "Variablen der obersten Ebene@Nicht var!"
end
end
my_var = "Erfolg"
MyClass = Class.new do # class MyClass
puts "In der Klassendefinition#{my_var}!"
define_method :my_method do # def my_method
"Auch in der Methodendefinition#{my_var}!"
end
end
def define_methods
shared = 0
Kernel.send :define_method, :counter do
shared
end
Kernel.send :define_method, :inc do |x|
shared += x
end
end
define_methods
counter # => 0
inc(4)
counter # => 4
-Es gibt viele Einschränkungen für den Umfang von Ruby.
-Bereiche werden durch Bereichsfenster wie Klasse, Modul und Def getrennt.
-Wenn Sie über das Zielfernrohr springen und sich in die Knechtschaft schleichen möchten, können Sie den Block (näher) verwenden.
-Durch Definieren eines Blocks können Sie die Einschränkungen in Ihrer aktuellen Umgebung umbrechen und übertragen.
-Ersetzen Sie das Scope-Gate durch einen Methodenaufruf, wickeln Sie die aktuelle Bindung in einen Abschluss ein und übergeben Sie diesen Abschluss an die Methode.
-Klasse ist Klasse.neu, Modul ist Modul.neu und def sind Modul.define_Kann durch Methode ersetzt werden.
-Dies ist ein flaches Zielfernrohr, die grundlegende Magie des Verschlusses.
-Wenn Sie mehrere Methoden in demselben flachen Bereich definieren und sie mit dem Bereichsfenster schützen, können Sie die Bindung freigeben.
-Dies wird als gemeinsamer Bereich bezeichnet.
instance_eval
--BasicObject # instance_eval
** wertet den Block im Kontext des Objekts aus **.
-
instance_eval
übergebene Block wird als Kontextsucher bezeichnet.class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
# instance_Der an eval übergebene Block wird ausgewertet, nachdem der Empfänger sich selbst gemacht hat
#Die private Methode des Empfängers und@Sie können auch auf Instanzvariablen wie v zugreifen.
obj.instance_eval do
self # => #<MyClass:0x3340dc @v=1>
@v # => 1
end
class C
def initialize
@x = 1
end
end
# instance_eval
class D
def twisted_method
@y = 2
# instance_Wenn eval sich selbst zum Empfänger wechselt
#Die Instanzvariable caller (D) fällt aus dem Block.
C.new.instance_eval { "@x: #{@x}, @y: #{@y}" }
end
end
D.new.twisted_method # => "@x: 1, @y: "
# instance_exec
class D
def twisted_method
@y = 2
#C-Instanzvariablen und D-Instanzvariablen können sich im selben Bereich befinden.
C.new.instance_exec(@y) {|y| "#{@x}, @y: #{y}" }
end
end
D.mew.twisted_method # => "@x: 1, @y: 2"
--Padrino-Testbeispiel
describe "PadrinoLogger" do
context 'for logger functionality' do
context "static asset logging" do
...
should 'allow turning on static assets logging' do
Padrino.logger.instance_eval { @log_static = true }
# ...
get "/images/something.png "
assert_equal "Foo", body
assert_match /GET/, Padrino.logger.log.string
Padrino.logger.instance_eval { @log_static = false }
end
end
end
end
--Erstellen Sie ein Objekt, um den Block auszuwerten. Eine Umgebung zum Auswerten von Blöcken.
inc = Proc.new {|x| x + 1 }
inc.call(2) # => 3
dec = lambda {|x| x - 1 }
# dec = ->(x) { x - 1 }
dec.class # => Proc
dec.call(2) # => 1
Ein Block ist wie ein anonymes Argument, das an eine Methode übergeben wird.
Wenn der Ertrag nicht ausreicht. --Wenn Sie einen Block an eine andere Methode übergeben möchten --Wenn Sie einen Block in Proc konvertieren möchten
** Weisen Sie Blöcken Bindungen zu (geben Sie einen "Namen" an, um auf den Block zu zeigen) &
**
Platzieren Sie das Ende der Methodenargumentsequenz und markieren Sie den Namen mit "&".
Hinzufügen von & bedeutet, dass Sie den an die Methode übergebenen Block empfangen und in Proc konvertieren möchten.
Beispiel für die Konvertierung eines Blocks in Proc
def math(a, b)
yield(a, b)
end
# &Mit der Qualifizierung wird der an die Methode übergebene Block in Proc konvertiert!
def do_math(a, b, &operation)
math(a, b, &operation)
end
do_math(2, 3) {|x, y| x * y } # => 6
def my_method(&the_proc)
the_proc
end
p = my_method {|name| "Hello, #{name}!" }
p.class # => "Proc"
p.call("Bill") # => "Hello, Bill!"
&
**def my_method(greeting)
"#{greeting}, #{yield}"
end
my_proc = proc { "Bill" }
my_method("Hello", &my_proc)
-Proc-Umwandlung durch & wird "Proc-Zwang" genannt (Zwang: Zwang, Zwang usw.).
lambda
--Proc mit Lambda gemacht unterscheidet sich von anderen Proc.
Ein mit Lambda erstelltes Proc-Objekt heißt Lambda. ――Der andere heißt einfach Proc.
Sie können mithilfe der Proc # lambda? -Methode überprüfen, ob Proc Lambda ist.
Der Unterschied zwischen Proc und Lambda
#Für Lambda kehrt return einfach von Lambda zurück.
def double(callable_object)
callable_object.call * 2
end
1 = lambda { return 10 }
double(1) # => 20
#Kehren Sie für Proc aus dem Bereich zurück, in dem Proc definiert ist.
def another_double
p = Proc.new { return 10 }
result = p.call
return result * 2 #Ich werde nicht so weit kommen!
end
another_double # => 10
def double(callable_object)
callable_object.call * 2
end
p = Proc.new { return 10 }
double(p) # => LocalJumpError
p = Proc.new { 10 }
double(p) # => 20
p = Proc.new
p.call(1, 2, 3) # => [1, 2]
p.call(1) # => [1, nil]
```
Proc vs lambda
- Im Allgemeinen soll Lambda intuitiver sein als Proc, weil es eher einer Methode ähnelt.
--Auch die Anzahl der Begriffe ist streng, und wenn Sie return aufrufen, endet sie einfach.
- Viele Rubyisten wählen zuerst Lambda, es sei denn, Sie benötigen Proc-Funktionalität.
### Methodenobjekt
- Die Methode wird auch zu einem aufrufbaren Objekt wie Lambda.
```rb
class MyClass
def initialize(value)
@x = value
end
def my_method
@x
end
end
object = MyClass.new(1)
m = object.method :my_method #Sie können die Methode selbst als Methodenobjekt abrufen
m.call # => 1 # Object#Das durch die Methode erhaltene Objekt wird als Methode verwendet#Kann per Aufruf ausgeführt werden
```
--`Method` kann mit` Method # to_proc` in` Proc` konvertiert werden, und Blöcke können mit` define_method` in Methoden konvertiert werden.
--lambda wird im definierten Bereich (näher) ausgewertet, Methode wird jedoch im Bereich des Objekts ausgewertet, zu dem es gehört.
UnboundMethod
- So etwas wie eine Methode, die von der ursprünglichen Klasse oder dem ursprünglichen Modul getrennt ist.
```rb
module MyModule
def my_method
42
end
end
unbound = MyModule.instance_method(:my_method)
unbound.class # => UnboundMethod
```
### Zusammenfassung der aufrufbaren Objekte
```
-Block (nicht "Objekt", sondern "aufrufbar"): Wird im definierten Bereich ausgewertet
-Proc: Ein Objekt der Proc-Klasse. Wie ein Block wird er in einem definierten Bereich ausgewertet.
-Lambda: Dies ist ebenfalls ein Proc-Klassenobjekt, unterscheidet sich jedoch geringfügig von einem normalen Proc. Wie Blöcke und Prozesse ist es ein Abschluss und wird in einem definierten Bereich bewertet.
-Methode: An das Objekt binden und im Bereich des Objekts auswerten. Sie können es auch aus dem Bereich des Objekts entfernen und an ein anderes Objekt binden.
-Geben Sie für Methoden und Lambdas Rückgaben vom aufrufbaren Objekt zurück.
-Andererseits kehren Proc und Block aus dem ursprünglichen Kontext des aufrufbaren Objekts zurück.
-Die Methode ist streng in Bezug auf den Unterschied in der Anzahl der Begriffe zum Zeitpunkt des Anrufs, und das Lambda ist auch fast streng.
-Proc und Block sind tolerant.
-Der obige Unterschied ist`Proc.new` 、 `Method#to_proc` 、 `&Qualifikation`Und so weiter
Sie können von einem aufrufbaren Objekt in ein anderes konvertieren.
```
## Domain-spezifische Sprache
- Beispiel 1
```rb
def event(description)
puts "ALERT: #{description}" if yield
end
loda 'events.rb'
# events.rb
event 'Ereignisse, die immer auftreten' do
true
end
event 'Ereignisse, die niemals auftreten' do
false
end
# => ALERT:Ereignisse, die immer auftreten
```
- Beispiel 2
```rb
def setup(&block)
@setups << block
end
def event(description, &block)
@events << {:description => description, :condition => block }
end
@setups = []
@events = []
load 'events.rb'
@events.each do |event|
@setups.each do |setup|
setup.call
end
puts "ALERT: #{event[:description}" if event[:condition].call
end
```
### Löschen Sie globale Variablen
--Beispiel 2 überarbeitet
```rb
lambda {
#Setups und Ereignisse sind lokale Variablen von Lambad, daher sind sie von außen nicht sichtbar
setups = []
events = []
Kernel.send :define_method, :setup do |&block|
setups << block
end
Kernel.send :define_method, :event do |description, &block|
events << {:description => description, :condition => block}
end
Kernel.send :define_method, :each_setup do |&block|
setups.each do |setup|
block.call event
end
end
Kernel.send :define_method, :each_event do |&block|
events.each do |event|
block.call event
end
end
}.call
each_event do |event|
each_setup do |setup|
setup.call
end
puts "ALERT: #{event[:description]}" if event[:condition].call
end
#Alternativ können Sie einen Reinraum im Kontext des Objekts verwenden, um zu verhindern, dass Ereignisse Instanzvariablen gemeinsam nutzen.
each_event do |event|
env = Object.new
each_setup do |setup|
env.instance_eval &setup
end
puts "ALERT: #{event[:description]}" if env.instance_eval &(event[:condition])
end
```
## Kapitel 4 Zusammenfassung
```
-Scopegate und wie Ruby Bereiche verwaltet.
-So fügen Sie flache und gemeinsam genutzte Bereiche hinzu, um Bindungen über Bereiche hinweg sichtbar zu machen.
-Im Bereich des Objekts (Instanz_Bewertung und Instanz_Ausführen von Code (mit exec) oder Ausführen von Code in einem Reinraum.
-So konvertieren Sie Blöcke und Objekte (Proc) ineinander.
-So konvertieren Sie Methoden und Objekte (Method und UnboundMethod) ineinander.
-Arten von aufrufbaren Objekten (Blöcke, Procs, Lambda) und ihre Unterschiede. Unterschied zur normalen Methode.
-So schreiben Sie Ihr eigenes kleines DSL.
```