--Metaprogramming écrit du code qui écrit du code.
En programmation et Ruby, l'introspection est généralement la possibilité de voir des objets, des classes, etc. à l'exécution pour les connaître.
Exemple:
#Ci-dessous la définition de la classe
class A
def a; end
end
module B
def b; end
end
class C < A
include B
def c; end
end
##Introspection
# Q.Qu'est-ce qu'une méthode d'instance C?
# A. C.instance_methods # [:c, :b, :a, :to_json, :instance_of?...]
# Q.Qu'est-ce qu'une méthode d'instance qui déclare uniquement C?
# A. C.instance_methods(false) # [:c]
# Q.Quels sont les ancêtres de la classe C?
# A. C.ancestors # [C, B, A, Object,...]
# Q.C super classe?
# 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
Même si vous n'écrivez pas la classe ci-dessus
Vous pouvez écrire du code qui définit les méthodes d'accès au moment de l'exécution en héritant simplement de ActiveRecord :: Base
.
ActiveRecord :: Base
et écrivez le code qui définit la méthode d'accesseur au moment de l'exécution (* écrivez le code qui écrit le code * )être capable de.La tâche principale de class
est de vous emmener dans le contexte de la classe.
Cela ressemble plus à un opérateur de portée qu'à une déclaration de classe.
Vous pouvez rouvrir les classes existantes, y compris les classes standard, et les modifier à la volée.
Les correctifs faciles aux classes, comme lorsque vous écrasez la méthode originale du même nom, sont appelés des correctifs de singe.
--Il n'y a pas de connexion entre les classes d'objets Ruby et les variables d'instance.
--Class est un objet --Une classe est un objet et la classe de la classe est la classe Class.
#De l'argument"false"Signifie "ignorer les méthodes héritées"
Class.instance_methods(false) # => [:allocate, :new, :superclass]
Class.superclass # => Module
--Similarité entre les constantes Ruby et les fichiers
--Séparez les chemins constants avec deux deux points. --Lorsque vous êtes à l'arrière de l'arborescence des constantes, vous pouvez spécifier une constante externe avec un chemin absolu en commençant par deux deux points indiquant la racine.
Module # constantes
--Retourne toutes les constantes dans la portée actuelle. # => [: C ,: Y]
Module.constants
--Retourne les constantes de niveau supérieur du programme en cours.Module.nesting
# => [M :: C :: M2, M :: C, M]
--Un objet (une instance de la classe Class) avec une liste de méthodes d'instance et un lien vers la superclasse.
nouveau
--Utilisez le nom de la classe pour faire référence à la classe.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]
--L'objet auquel appartient la méthode à appeler
--Exemple de chaîne d'héritage de classe --Classe → Super classe → Super classe ... (Continuer vers BasicObject)
--Lorsque vous incluez un module dans une classe (ou un autre module), Ruby insère le module dans la chaîne d'héritage. ――Il entre dans ** directement au-dessus ** de la classe incluse.
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]
--Lorsque la méthode est appelée, la mémorisation de la référence du récepteur vous rappellera qui est le récepteur lorsque la méthode est exécutée.
--État lorsque la méthode n'est pas appelée, ou lorsque toutes les méthodes appelées sont retournées
self # => main
self.class # => Object
--Dans la définition d'une classe ou d'un module (en dehors de la méthode), le rôle de self est la classe ou le module lui-même.
class MyClass
self # => MyClass
end
--Seulement, vous pouvez appeler une méthode avec private.
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"
-Un objet se compose de plusieurs variables d'instance et de liens vers des classes.
-Les méthodes de l'objet vivent dans la classe de l'objet (du point de vue de la classe, cela s'appelle une méthode d'instance).
-Une classe est un objet de la classe Class. Les camarades de classe ne sont que des constantes.
-La classe est une sous-classe de Module. Un module est essentiellement une collection de méthodes. De plus, les classes peuvent être instanciées avec new ou créées hiérarchiquement avec superclass.
-Les constantes sont disposées sur une arborescence comme un système de fichiers. Les modules et les classes sont des répertoires nommés, et les constantes régulières sont comme des fichiers.
-Chaque classe a une chaîne d'héritage qui s'étend à BasicObject.
-Lorsque vous appelez la méthode, Ruby fait un pas vers la droite vers la classe du récepteur, puis remonte la chaîne d'héritage. Il continue jusqu'à ce que vous découvriez une méthode ou que vous mettiez fin à la chaîne d'héritage.
-Lorsque vous incluez un module dans une classe, le module est inséré directement au-dessus de la chaîne d'héritage pour cette classe. La pré-écriture d'un module l'insère directement sous la chaîne d'héritage pour cette classe.
-Lors de l'appel de la méthode, le récepteur devient soi-même.
-Lors de la définition d'un module (ou d'une classe), ce module devient self.
-Les variables d'instance sont toujours considérées comme des variables d'auto-instance.
-Si vous appelez une méthode sans spécifier explicitement un récepteur, elle est considérée comme une méthode self.
-Les raffinements sont comme la correction du code de classe et le remplacement de la recherche de méthode normale. Cependant, les raffinements ne sont valables que dans une zone limitée à partir du point où l'utilisation est appelée jusqu'au point où la définition du fichier ou du module se termine.
--Utilisez la notation par points ou Object # send
pour appeler la méthode.
obj = MyClass.new
obj.my_method(3) # => 6
obj.send(:my_method, 3) # => 6
En utilisant send
, le nom de la méthode que vous voulez appeler devient un argument normal, et vous pouvez décider quelle méthode appeler lorsque le code est exécuté.
Exemple de Pry # refresh
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=L'accesseur de l'attribut tel que appelé.
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
--Une technique pour définir des méthodes lors de l'exécution.
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
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#Si vous passez un bloc à grep, le bloc sera évalué pour tous les éléments qui correspondent à l'expression régulière.
#La chaîne qui correspond aux parenthèses de l'expression régulière est une variable globale$Stocké dans 1.
#Exemple: data_la source est obtenir_cpu_info et obtenir_mouse_Si vous avez deux méthodes d'information
# Computer.define_Vous appellerez le composant deux fois (passez les chaînes "cpu" et "mouse" respectivement)
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
--Lors de la recherche d'une méthode, si la méthode n'est pas trouvée, appelez la méthode method_missing
pour accepter la perte.
--method_missing
est la méthode d'instance private
de BasicObject
héritée par tous les objets.
nick.send :method_missing, :my_method
# => NoMethodError: undefined method `my_method` for #<Lawyer:0x007f801b0f4978>
class Lawyer
def method_missing(method, *args)
puts "Appelé:#{method}(#{args.join(', ')})"
puts "(J'ai aussi passé le bloc)" if block_given?
end
end
bob = Lawyer.new
bob.talk_simple('a', 'b') do
#bloquer
end
# =>Appelé: parler_simple(a, b)
#(J'ai aussi passé le bloc)
BasiObject # method_missing
sera NoMethodError.--Ce message est traité par method_missing et ressemble à un appel normal à l'appelant, mais la méthode correspondante n'est pas trouvée du côté du récepteur.
module Hashie
class Mash < Hashie::Hash
def method_missing(method_name, *args, &blk)
#Si le nom de la méthode appelée est une clé de hachage[]Appelez la méthode et renvoyez la valeur correspondante.
return self.[](method_name,&blk)ifkey?(method_name)
#La fin du nom de la méthode est "="Si,"=Supprimez le "" pour récupérer le nom de l'attribut, puis conservez sa valeur.
#Si aucun des deux ne correspond, méthode_missing renvoie la valeur par défaut.
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
method_missing
, complète les méthodes fantômes et les transfère vers d'autres objets.--Exemple de Ghee (une bibliothèque avec un accès facile à l'API HTTP de GitHub)
class Ghee
class ResourceProxy
# ...
def method_missing(message, *args, &block)
# my_gist.Hashie, un appel de méthode comme url::Mash#method_Transférer aux disparus.
subject.send(message, *args, &block)
end
def subject
#Recevoir l'objet GitHub en JSON et Hasie::Convertissez en purée.
@subject ||= connection.get(path_prefix){|req| req.params.merge!params }.body
end
end
end
--Deux points de Ghee
--Gee garde le code simple avec cette conception en deux étapes.
--Il existe une méthode fantôme lors de la lecture des données, il n'est donc pas nécessaire de définir une méthode.
--Définissez les méthodes uniquement lorsque vous avez besoin d'un code spécifique comme star
.
Un autre avantage de ces méthodes dynamiques est qu'elles peuvent répondre automatiquement aux modifications de l'API GitHub.
Même si GitHub ajoute un nouveau champ, c'est aussi une méthode fantôme, donc Ghee peut prendre en charge l'appel sans modifier le code source.
Refactoring de classe d'ordinateur à l'aide de method_missing
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
# BasicObject#method_Remplacer manquant
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
#Répondez pour voir s'il existe une méthode fantôme_to_missing?Est correctement annulée.
def respond_to_missing?(method, include_private = false)
@data_source.respond_to?("get_#{method}_info") || super
end
end
Module#const_missing
Une méthode qui vous permet d'utiliser d'anciens camarades de classe sans nouvel espace de noms de camarade de classe.
Exemple lorsque Task est renommé Rake :: Task en raison d'une mise à niveau
class Module
def const_missing(const_name)
case const_name
when :Task
#Vous avertit de l'utilisation de noms de classe obsolètes.
Rake.application.const_warning(const_name)
Rake::Task
when :FileTask
Rake.application.const_warning(const_name)
Rake::FileTask
when :FileCreationTask
# ...
end
end
end
method_missing
et appelé number
dedans, la même chaîne d'événements Se produit encore et encore, provoquant éventuellement un débordement de pile.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, qui est la racine de la hiérarchie des classes de Ruby, n'a que le minimum de méthodes nécessaires, et afin de définir rapidement une ardoise vide dans Ruby, BasicObject doit être hérité.
-La méthode Ghost est un conseil de base (appelez toujours super, répondez toujours_to_missing?Redéfinit), ce qui évite la plupart des problèmes, mais provoque toujours des bogues complexes.
-Comme la méthode fantôme n'est pas une méthode réelle, elle se comporte différemment de la méthode réelle.
-Il existe certaines situations où seules des méthodes fantômes peuvent être utilisées, par exemple lorsqu'il y a un grand nombre d'appels de méthode ou lorsque la méthode à appeler n'est connue qu'au moment de l'exécution.
-"Utilisez des méthodes dynamiques si possible, utilisez des méthodes fantômes si vous ne pouvez pas aider"
--Block fait partie d'une grande famille d '"objets appelables".
Kernel # block_given?
Pour vérifier les blocs.--Définissez un bloc et obtenez la liaison à ce stade. --Lorsque vous transmettez un bloc à une méthode, emportez cette liaison avec vous.
def my_method
#Les liaisons de la méthode ne sont pas visibles pour le bloc.
x = "Goodbye"
yield("cruel")
end
x = "Hello"
#Enveloppez une liaison locale comme x, puis passez le bloc à la méthode.
my_method = {|y| "#{x}, #{y} world"} # => "Hello, cruel world"
#Les variables globales sont accessibles à partir de n'importe quelle portée.
def a_scope
$var = "some value"
end
def another_scope
$var
end
a_scope
another_scope # => "some value"
#Les variables d'instance de niveau supérieur sont des variables d'instance de l'objet principal au niveau supérieur.
#Vous pouvez l'appeler de partout où le principal devient soi.
#Si l'autre objet devient self, la variable d'instance de niveau supérieur sort de la portée.
@var = "Variables de niveau supérieur@var"
def my_method
@var
end
my_method # => "Variables de niveau supérieur@var"
class MyClass
def my_method
@var = "Variables de niveau supérieur@Pas var!"
end
end
--Il y a trois endroits où le programme change d'étendue et ouvre une nouvelle étendue, et le mot clé qui marque chacune est appelé la porte d'étendue.
--Comment passer des liaisons à travers les portes de portée afin que les variables des autres portées soient visibles. ―― Cette magie est également appelée ** portée lexicale imbriquée **.
my_var = "Succès"
MyClass = Class.new do # class MyClass
puts "Dans la définition de classe#{my_var}!"
define_method :my_method do # def my_method
"Également dans la définition de la méthode#{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
-Il existe de nombreuses contraintes sur la portée de Ruby.
-Les portées sont séparées par des portes de portée telles que class, module et def.
-Si vous voulez sauter par-dessus la porte de la lunette et vous faufiler dans le bondage, vous pouvez utiliser le bloc (plus proche).
-En définissant un bloc, vous pouvez encapsuler et transporter les contraintes dans votre environnement actuel.
-Remplacez la porte de portée par un appel de méthode, encapsulez la liaison actuelle dans une fermeture et transmettez cette fermeture à la méthode.
-la classe est la classe.nouveau, le module est un module.nouveau et def sont module.define_Peut être remplacé par method.
-C'est une lunette plate, la magie de base de la fermeture.
-Si vous définissez plusieurs méthodes dans la même étendue plate et que vous les protégez avec la porte d'étendue, vous pouvez partager la liaison.
-C'est ce qu'on appelle une portée partagée.
instance_eval
--BasicObject # instance_eval
** évalue le bloc dans le contexte de l'objet **.
-
instance_eval
est appelé un chercheur de contexte.class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
# instance_Le bloc passé à eval est évalué après avoir rendu le récepteur self, donc
#La méthode privée du récepteur et@Vous pouvez également accéder à des variables d'instance telles que v.
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_Quand eval se transforme en récepteur
#La variable d'instance de l'appelant (D) sort du bloc.
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
#Les variables d'instance C et les variables d'instance D peuvent être dans la même portée.
C.new.instance_exec(@y) {|y| "#{@x}, @y: #{y}" }
end
end
D.mew.twisted_method # => "@x: 1, @y: 2"
Si vous utilisez un chercheur de contexte (bloc passé à instance_eval), vous pouvez interrompre l'encapsulation, de sorte que les cas d'utilisation sont limités dans les cas suivants. --Si vous voulez voir le contenu de l'objet depuis irb --Pour tester
Exemple de test de Padrino
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
--Créez un objet juste pour évaluer le bloc. Un environnement pour évaluer les blocs.
--Objet appelable --Dans Ruby, méthode "enregistrer le code et l'appeler plus tard" --Dans Proc. C'est un bloc qui est devenu un objet.
Proc # call
.inc = Proc.new {|x| x + 1 }
inc.call(2) # => 3
--Deux méthodes de noyau pour convertir des blocs en Proc - lambda - proc
dec = lambda {|x| x - 1 }
# dec = ->(x) { x - 1 }
dec.class # => Proc
dec.call(2) # => 1
Un bloc est comme un argument anonyme passé à une méthode.
Cas où le rendement ne suffit pas. --Lorsque vous souhaitez passer un bloc à une autre méthode --Lorsque vous souhaitez convertir un bloc en Proc
** Assignez des liaisons aux blocs (donnez un "nom" pour pointer vers le bloc) &
**
Placez à la fin de la séquence d'arguments de la méthode et marquez le nom avec &
.
Ajouter &
signifie que vous souhaitez recevoir le bloc passé à la méthode et le convertir en Proc.
Exemple de conversion d'un bloc en Proc
def math(a, b)
yield(a, b)
end
# &Avec qualification, il prend le bloc passé à la méthode et le convertit en Proc!
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)
La conversion -Proc par & est appelée "coercition Proc" (coercition: coercition, coercition, etc.).
lambda
--La différence entre Proc et lambda
#Pour lambda, return renvoie simplement de lambda.
def double(callable_object)
callable_object.call * 2
end
1 = lambda { return 10 }
double(1) # => 20
#Pour Proc, retournez à partir de la portée dans laquelle Proc est défini.
def another_double
p = Proc.new { return 10 }
result = p.call
return result * 2 #Je ne viendrai pas si loin!
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
- D'une manière générale, on dit que lambda est plus intuitif que Proc car il ressemble plus à une méthode.
- De plus, le nombre de termes est strict et lorsque vous appelez return, il se termine simplement.
- De nombreux Rubyistes choisissent d'abord lambda, sauf si vous avez besoin de la fonctionnalité Proc.
### Objet de méthode
- La méthode devient également un objet appelable comme 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 #Vous pouvez obtenir la méthode elle-même en tant qu'objet Method
m.call # => 1 # Object#L'objet obtenu par méthode est utilisé comme méthode#Peut être exécuté en utilisant un appel
```
--`Method` peut être converti en` Proc` avec `Method # to_proc`, et les blocs peuvent être convertis en méthodes avec` define_method`.
--lambda est évalué dans la portée définie (plus proche), mais Method est évaluée dans la portée de l'objet auquel elle appartient.
UnboundMethod
- Quelque chose comme une méthode séparée de la classe ou du module d'origine.
```rb
module MyModule
def my_method
42
end
end
unbound = MyModule.instance_method(:my_method)
unbound.class # => UnboundMethod
```
### Récapitulatif des objets appelables
```
-Bloc (pas "objet" mais "appelable"): évalué dans la portée définie
-Proc: un objet de la classe Proc. Comme un bloc, il est évalué dans une portée définie.
-lambda: C'est aussi un objet de classe Proc, mais il est légèrement différent d'un Proc normal. Comme les blocs et les processus, il s'agit d'une clôture et est évalué dans une portée définie.
-Méthode: Liez à l'objet et évaluez dans la portée de l'objet. Vous pouvez également l'éloigner de la portée de l'objet et le lier à un autre objet.
-Pour les méthodes et les lambdas, retourne les retours de l'objet appelable.
-D'autre part, Proc et Block reviennent du contexte d'origine de l'objet appelable.
-La méthode est stricte en ce qui concerne la différence de nombre de termes au moment de l'appel, et le lambda est également presque strict.
-Proc et block sont tolérants.
-La différence ci-dessus est`Proc.new` 、 `Method#to_proc` 、 `&Qualification`Etc
Vous pouvez convertir d'un objet appelable à un autre.
```
## Langue spécifique au domaine
- Exemple 1
```rb
def event(description)
puts "ALERT: #{description}" if yield
end
loda 'events.rb'
# events.rb
event 'Des événements qui se produisent toujours' do
true
end
event 'Des événements qui ne se produisent jamais' do
false
end
# => ALERT:Des événements qui se produisent toujours
```
- Exemple 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
```
### Supprimer les variables globales
- Exemple 2 révisé
```rb
lambda {
#Les configurations et les événements sont des variables locales de lambad, donc ils ne sont pas visibles de l'extérieur
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
#Vous pouvez également utiliser une salle blanche dans le contexte de l'objet pour empêcher les événements de partager des variables d'instance.
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
```
## Résumé du chapitre 4
```
-Scopegate et comment Ruby gère les étendues.
-Comment ajouter des étendues plates et partagées pour rendre les liaisons visibles dans toutes les étendues.
-Dans la portée de l'objet (instance_évaluation et instance_Comment exécuter du code (en utilisant exec) ou comment exécuter du code dans une salle blanche.
-Comment convertir des blocs et des objets (Proc) les uns aux autres.
-Comment convertir des méthodes et des objets (Method et UnboundMethod) entre eux.
-Types d'objets appelables (blocs, procs, Lambda) et leurs différences. Différence avec la méthode normale.
-Comment écrire votre propre petit DSL.
```