portaldacalheta.pt
  • Principal
  • Mode De Vie
  • Rise Of Remote
  • Processus Financiers
  • Gestion De Projet
La Technologie

La métaprogrammation Ruby est encore plus cool qu'il n'y paraît



Vous entendez souvent que la métaprogrammation est quelque chose que seuls les ninjas Ruby utilisent, et que ce n'est tout simplement pas pour les mortels. Mais la vérité est que la métaprogrammation n’a rien d’effrayant. Cet article de blog servira à remettre en question ce type de réflexion et à rapprocher la métaprogrammation du développeur Ruby moyen afin qu'il puisse également profiter de ses avantages.

travailler avec des dates en javascript
Métaprogrammation Ruby: code d'écriture de code Tweet

Il convient de noter que la métaprogrammation peut signifier beaucoup et qu'elle peut souvent être très mal utilisée et aller à l'extrême en matière d'utilisation.Je vais donc essayer de donner des exemples du monde réel que tout le monde pourrait utiliser dans la programmation quotidienne.



Métaprogrammation

Métaprogrammation est une technique par laquelle vous pouvez écrire du code qui écrit code par lui-même dynamiquement au moment de l'exécution. Cela signifie que vous pouvez définir des méthodes et des classes pendant l'exécution. Fou, non? En un mot, en utilisant la métaprogrammation, vous pouvez rouvrir et modifier des classes, attraper des méthodes qui n'existent pas et les créer à la volée, créer du code qui est SEC en évitant les répétitions, et plus encore.



Les bases

Avant de plonger dans une métaprogrammation sérieuse, nous devons explorer les bases. Et la meilleure façon de le faire est par l'exemple. Commençons par un et comprenons la métaprogrammation Ruby étape par étape. Vous pouvez probablement deviner ce que fait ce code:



class Developer def self.backend 'I am backend developer' end def frontend 'I am frontend developer' end end

Nous avons défini une classe avec deux méthodes. La première méthode de cette classe est une méthode de classe et la seconde est une méthode d'instance. Ce sont des choses basiques dans Ruby, mais il se passe beaucoup plus derrière ce code que nous devons comprendre avant de continuer. Il est à noter que la classe Developer lui-même est en fait un objet. Dans Ruby, tout est un objet, y compris les classes. Depuis Developer est une instance, c'est une instance de la classe Class. Voici à quoi ressemble le modèle objet Ruby:

Modèle d



p Developer.class # Class p Class.superclass # Module p Module.superclass # Object p Object.superclass # BasicObject

Une chose importante à comprendre ici est la signification de self. Le frontend method est une méthode régulière disponible sur les instances de la classe Developer, mais pourquoi backend méthode une méthode de classe? Chaque morceau de code exécuté dans Ruby est exécuté contre un soi . Lorsque l'interpréteur Ruby exécute un code, il garde toujours la trace de la valeur self pour une ligne donnée. self fait toujours référence à un objet, mais cet objet peut changer en fonction du code exécuté. Par exemple, à l'intérieur d'une définition de classe, le self fait référence à la classe elle-même qui est une instance de la classe Class.

class Developer p self end # Developer

À l'intérieur des méthodes d'instance, self fait référence à une instance de la classe.



class Developer def frontend self end end p Developer.new.frontend # #

À l'intérieur des méthodes de classe, self fait référence à la classe elle-même d'une manière (qui sera discutée plus en détail plus loin dans cet article):

class Developer def self.backend self end end p Developer.backend # Developer

C'est bien, mais qu'est-ce qu'une méthode de classe après tout? Avant de répondre à cette question, nous devons mentionner l'existence de quelque chose appelé métaclasse, également connu sous le nom de classe singleton et classe propre. Méthode de classe frontend que nous avons défini précédemment n'est rien d'autre qu'une méthode d'instance définie dans la métaclasse pour l'objet Developer! Une métaclasse est essentiellement une classe que Ruby crée et insère dans la hiérarchie d'héritage pour contenir les méthodes de classe, n'interférant donc pas avec les instances créées à partir de la classe.



Métaclasses

Chaque objet de Ruby a le sien métaclasse . Il est en quelque sorte invisible pour un développeur, mais il est là et vous pouvez l'utiliser très facilement. Depuis notre classe Developer est essentiellement un objet, il a sa propre métaclasse. À titre d’exemple, créons un objet d’une classe String et manipulez sa métaclasse:

example = 'I'm a string object' def example.something self.upcase end p example.something # I'M A STRING OBJECT

Ce que nous avons fait ici, c'est que nous avons ajouté une méthode singleton something à un objet. La différence entre les méthodes de classe et les méthodes singleton est que les méthodes de classe sont disponibles pour toutes les instances d'un objet de classe tandis que les méthodes singleton ne sont disponibles que pour cette seule instance. Les méthodes de classe sont largement utilisées alors que les méthodes singleton ne le sont pas tellement, mais les deux types de méthodes sont ajoutés à une métaclasse de cet objet.



L'exemple précédent pourrait être réécrit comme ceci:

example = 'I'm a string object' class << example def something self.upcase end end

La syntaxe est différente mais elle fait effectivement la même chose. Revenons maintenant à l'exemple précédent où nous avons créé Developer class et explorez d'autres syntaxes pour définir une méthode de classe:



class Developer def self.backend 'I am backend developer' end end

C'est une définition de base que presque tout le monde utilise.

def Developer.backend 'I am backend developer' end

C'est la même chose, nous définissons le backend méthode de classe pour Developer. Nous n'avons pas utilisé self mais définir une méthode comme celle-ci en fait effectivement une méthode de classe.

class Developer class << self def backend 'I am backend developer' end end end

Encore une fois, nous définissons une méthode de classe, mais en utilisant une syntaxe similaire à celle que nous avons utilisée pour définir une méthode singleton pour un String objet. Vous remarquerez peut-être que nous avons utilisé self ici qui fait référence à un Developer objet lui-même. Nous avons d'abord ouvert Developer classe, faisant de soi égal à Developer classe. Ensuite, nous faisons class << self, rendant self égal à la métaclasse de Developer. Ensuite, nous définissons une méthode backend sur la métaclasse de Developer.

class << Developer def backend 'I am backend developer' end end

En définissant un bloc comme celui-ci, nous définissons self à la métaclasse de Developer pour la durée du bloc. En conséquence, le backend est ajoutée à la métaclasse de Developer, plutôt qu'à la classe elle-même.

Voyons comment cette métaclasse se comporte dans l'arborescence d'héritage:

Métaclasse dans l

Comme vous l'avez vu dans les exemples précédents, il n'y a aucune preuve réelle que la métaclasse existe même. Mais nous pouvons utiliser un petit hack qui peut nous montrer l'existence de cette classe invisible:

class Object def metaclass_example class << self self end end end

Si nous définissons une méthode d'instance dans Object classe (oui, nous pouvons rouvrir n'importe quelle classe à tout moment, c'est encore une autre beauté de la métaprogrammation), nous aurons un self se référant au Object objet à l'intérieur. On peut alors utiliser class << self syntaxe pour changer le courant soi pour pointer vers la métaclasse de l'objet courant. Puisque l'objet courant est Object classe elle-même, ce serait la métaclasse de l'instance. La méthode renvoie self qui est à ce stade une métaclasse elle-même. Ainsi, en appelant cette méthode d'instance sur n'importe quel objet, nous pouvons obtenir une métaclasse de cet objet. Définissons notre Developer classe à nouveau et commencez à explorer un peu:

class Developer def frontend p 'inside instance method, self is: ' + self.to_s end class << self def backend p 'inside class method, self is: ' + self.to_s end end end developer = Developer.new developer.frontend # 'inside instance method, self is: #' Developer.backend # 'inside class method, self is: Developer' p 'inside metaclass, self is: ' + developer.metaclass_example.to_s # 'inside metaclass, self is: #'

Et pour le crescendo, voyons la preuve que frontend est une méthode d'instance d'une classe et backend est une méthode d'instance d'une métaclasse:

quelle langue utilise windows
p developer.class.instance_methods false # [:frontend] p developer.class.metaclass_example.instance_methods false # [:backend]

Cependant, pour obtenir la métaclasse, vous n’avez pas besoin de rouvrir Object et ajoutez ce hack. Vous pouvez utiliser singleton_class que Ruby fournit. C'est la même chose que metaclass_example nous avons ajouté mais avec ce hack, vous pouvez réellement voir comment Ruby fonctionne sous le capot:

p developer.class.singleton_class.instance_methods false # [:backend]

Définition de méthodes à l'aide de «class_eval» et «instance_eval»

Il existe une autre façon de créer une méthode de classe, à savoir en utilisant instance_eval :

class Developer end Developer.instance_eval do p 'instance_eval - self is: ' + self.to_s def backend p 'inside a method self is: ' + self.to_s end end # 'instance_eval - self is: Developer' Developer.backend # 'inside a method self is: Developer'

Cet interpréteur de code Ruby évalue dans le contexte d'une instance, qui est dans ce cas un Developer objet. Et lorsque vous définissez une méthode sur un objet, vous créez une méthode de classe ou une méthode singleton. Dans ce cas, il s'agit d'une méthode de classe - pour être exact, les méthodes de classe sont des méthodes singleton mais des méthodes singleton d'une classe, tandis que les autres sont des méthodes singleton d'un objet.

D'autre part, class_eval évalue le code dans le contexte d'une classe au lieu d'une instance. Il rouvre pratiquement la classe. Voici comment class_eval peut être utilisé pour créer une méthode d'instance:

Developer.class_eval do p 'class_eval - self is: ' + self.to_s def frontend p 'inside a method self is: ' + self.to_s end end # 'class_eval - self is: Developer' p developer = Developer.new # # developer.frontend # 'inside a method self is: #'

Pour résumer, lorsque vous appelez class_eval méthode, vous changez self pour faire référence à la classe d'origine et lorsque vous appelez instance_eval, self modifications pour faire référence à la métaclasse de la classe d'origine.

Définition des méthodes manquantes à la volée

Un autre morceau de puzzle de métaprogrammation est method_missing . Lorsque vous appelez une méthode sur un objet, Ruby entre d'abord dans la classe et parcourt ses méthodes d'instance. S'il n'y trouve pas la méthode, il poursuit sa recherche dans la chaîne des ancêtres. Si Ruby ne trouve toujours pas la méthode, il appelle une autre méthode nommée method_missing qui est une méthode d'instance de Kernel que chaque objet hérite. Puisque nous sommes sûrs que Ruby va éventuellement appeler cette méthode pour les méthodes manquantes, nous pouvons l'utiliser pour implémenter quelques astuces.

define_method est une méthode définie dans Module classe que vous pouvez utiliser pour créer des méthodes de manière dynamique. Pour utiliser define_method, vous l'appelez avec le nom de la nouvelle méthode et un bloc où les paramètres du bloc deviennent les paramètres de la nouvelle méthode. Quelle est la différence entre l'utilisation de def pour créer une méthode et define_method? Il n'y a pas beaucoup de différence sauf que vous pouvez utiliser define_method en combinaison avec method_missing pour écrire le code DRY. Pour être exact, vous pouvez utiliser define_method au lieu de def pour manipuler les étendues lors de la définition d'une classe, mais c'est une toute autre histoire. Prenons un exemple simple:

class Developer define_method :frontend do |*my_arg| my_arg.inject(1, :*) end class < 100 p Developer.backend # undefined method 'backend' for Developer:Class (NoMethodError) Developer.create_backend p Developer.backend # 'Born from the ashes!'

Ceci montre comment define_method a été utilisé pour créer une méthode d'instance sans utiliser de def. Cependant, nous pouvons en faire beaucoup plus. Jetons un coup d'œil à cet extrait de code:

class Developer def coding_frontend p 'writing frontend' end def coding_backend p 'writing backend' end end developer = Developer.new developer.coding_frontend # 'writing frontend' developer.coding_backend # 'writing backend'

Ce code n'est pas DRY, mais utilise define_method nous pouvons le faire SEC:

class Developer ['frontend', 'backend'].each do |method| define_method 'coding_#{method}' do p 'writing ' + method.to_s end end end developer = Developer.new developer.coding_frontend # 'writing frontend' developer.coding_backend # 'writing backend'

C’est beaucoup mieux, mais toujours pas parfait. Pourquoi? Si nous voulons ajouter une nouvelle méthode coding_debug par exemple, nous devons mettre ceci 'debug' dans le tableau. Mais en utilisant method_missing nous pouvons résoudre ce problème:

class Developer def method_missing method, *args, &block return super method, *args, &block unless method.to_s =~ /^coding_w+/ self.class.send(:define_method, method) do p 'writing ' + method.to_s.gsub(/^coding_/, '').to_s end self.send method, *args, &block end end developer = Developer.new developer.coding_frontend developer.coding_backend developer.coding_debug

Ce morceau de code est un peu compliqué, alors décomposons-le. L'appel d'une méthode qui n'existe pas déclenchera method_missing. Ici, nous voulons créer une nouvelle méthode uniquement lorsque le nom de la méthode commence par 'coding_'. Sinon, nous appelons simplement super pour faire le travail de rapport d'une méthode qui manque réellement. Et nous utilisons simplement define_method pour créer cette nouvelle méthode. C'est tout! Avec ce morceau de code, nous pouvons créer littéralement des milliers de nouvelles méthodes commençant par 'coding_', et c'est ce qui rend notre code DRY. Depuis define_method se trouve être privé de Module, nous devons utiliser send pour l'invoquer.

numéros de carte de crédit de travail avec de l'argent 2017

Emballer

Ce n'est que la pointe de l'iceberg. Devenir un Ruby Jedi , c'est le point de départ. Une fois que vous maîtrisez ces éléments de base de la métaprogrammation et que vous en comprenez vraiment l'essence, vous pouvez passer à quelque chose de plus complexe, par exemple créer le vôtre Langue spécifique au domaine (DSL). DSL est un sujet en soi, mais ces concepts de base sont une condition préalable à la compréhension des sujets avancés. Certaines des pierres précieuses les plus utilisées Rails ont été construits de cette façon et vous avez probablement utilisé son DSL sans même le savoir, comme RSpec et ActiveRecord.

J'espère que cet article peut vous aider à comprendre la métaprogrammation et peut-être même à créer votre propre DSL, que vous pouvez utiliser pour coder plus efficacement.

Quatre écueils de la précision de l'analyse des sentiments

Back-End

Quatre écueils de la précision de l'analyse des sentiments
Premiers pas avec TensorFlow: un didacticiel d'apprentissage automatique

Premiers pas avec TensorFlow: un didacticiel d'apprentissage automatique

La Technologie

Articles Populaires
Conception de page de destination: création de la page de destination ultime
Conception de page de destination: création de la page de destination ultime
Modèles de fiches de conditions - Clauses à surveiller lors de la négociation
Modèles de fiches de conditions - Clauses à surveiller lors de la négociation
Promesses JavaScript: un tutoriel avec des exemples
Promesses JavaScript: un tutoriel avec des exemples
Introduction à OpenGL: un didacticiel sur le rendu de texte 3D
Introduction à OpenGL: un didacticiel sur le rendu de texte 3D
C Corp contre S Corp, partenariat, entreprise individuelle et LLC: quelle est la meilleure entité commerciale?
C Corp contre S Corp, partenariat, entreprise individuelle et LLC: quelle est la meilleure entité commerciale?
 
Les marchés à millions de dollars sont-ils meilleurs que les marchés à milliards de dollars?
Les marchés à millions de dollars sont-ils meilleurs que les marchés à milliards de dollars?
Créer un curseur de page complète personnalisé avec CSS et JavaScript
Créer un curseur de page complète personnalisé avec CSS et JavaScript
La métaprogrammation Ruby est encore plus cool qu'il n'y paraît
La métaprogrammation Ruby est encore plus cool qu'il n'y paraît
Blockchain, IoT et l'avenir des transports: comprendre la devise du moteur
Blockchain, IoT et l'avenir des transports: comprendre la devise du moteur
Explorer les algorithmes d'apprentissage automatique supervisé
Explorer les algorithmes d'apprentissage automatique supervisé
Articles Populaires
  • jwt rejeté : échec de l'authentification de l'utilisateur
  • meilleure façon de travailler à distance
  • comment utiliser les modèles d'amorçage
  • qu'est-ce que powerpivot pour excel
  • c# visual studio mac
Catégories
  • Mode De Vie
  • Rise Of Remote
  • Processus Financiers
  • Gestion De Projet
  • © 2022 | Tous Les Droits Sont Réservés

    portaldacalheta.pt