salut! Dans cet article, je veux parler de métaprogrammation en utilisant un exemple de problème réel commun.
Quand quelqu'un parle de métaprogrammation, un codeur de la vieille école devient furieux.
Et il y a des raisons à cela, et sur un gros projet, il peut sembler fou d'utiliser la métaprogrammation, car le code devient très difficile à lire. Et si un spécialiste de l'extérieur rejoint le projet, alors il ne comprendra encore plus rien à ce méta-code.
Mais ce n'est pas aussi simple qu'on le dit - il n'y a pas de mauvais outils. Dans cet article, je vais essayer de montrer avec un exemple concret comment la métaprogrammation peut aider à rendre votre code plus propre et à éliminer les répétitions de routine. Et vous fera vous réjouir de la méta-magie.
Aide de wikipedia
La métaprogrammation est un type de programmation associé à la création de programmes qui génèrent d'autres programmes du fait de leur travail (en particulier, au stade de la compilation de leur code source), ou des programmes qui se modifient en cours d'exécution (code auto-modifiable) . Le premier vous permet d'obtenir des programmes avec moins de temps et d'efforts de codage que si le programmeur les écrivait entièrement à la main, le second vous permet d'améliorer les propriétés du code (taille et performances).
Ceci conclut l'introduction. Maintenant, je veux passer à la partie pratique et vous parler de l'essence du problème
Plus loin, nous parlerons du langage ruby et du framework Rails en particulier. Ruby a de la réflexion et de grandes opportunités pour la métaprogrammation. La plupart des gemmes, modules et frameworks sont construits avec de puissants outils de réflexion.
Photo de Joshua Fuller sur Unsplash
Quiconque a écrit quelque chose sur Rails est probablement tombé sur un joyau tel que Rails Admin, si vous n'avez pas essayé de l'utiliser dans vos projets sur rails, ou si vous avez des analogues, je vous recommande fortement de le faire, car vous le ferez presque immédiatement. obtenez un CMS à part entière pour votre système.
Il y a donc une fonctionnalité désagréable , le problème de l'association has_one.
has_one . 1. , .
. has_one (draft) CMS.
class TechProcess < ApplicationRecord
include MdcSchema
has_many :executor_programs, inverse_of: :tech_process, foreign_key: :barcode_tech_process, primary_key: :barcode
validates :barcode, presence: true
validates :barcode, uniqueness: true
has_one :draft2tech_process, dependent: :destroy
has_one :draft, through: :draft2tech_process
has_many :tech_process2tech_operations
has_many :tech_operations, through: :tech_process2tech_operations
end
def draft_id
self.draft.try :id
end
def draft_id=(id)
self.draft = Draft.find_by_id(id)
end
, , , CMS.
, 15 has_one ? , DRY. . .
Meta
self.reflect_on_all_associations(:has_one).each do |has_one_association|
define_method("#{has_one_association.name}_id") do
self.send(has_one_association.name).try :id
end
define_method("#{has_one_association.name}_id=") do |id|
self.send("#{has_one_association.name}=",has_one_association.klass.find_by_id(id))
end
end
, has_one Rails Admin
. .
, . reflect_on_all_associations , "macro" :hasone has_one , , .
, has_one . , , define_method .
has_one rails admin.
"" , . - concern
require 'active_support/concern'
module HasOneHandler
extend ActiveSupport::Concern
included do
self.reflect_on_all_associations(:has_one).each do |has_one_association|
define_method("#{has_one_association.name}_id") do
self.send(has_one_association.name).try :id
end
define_method("#{has_one_association.name}_id=") do |id|
self.send("#{has_one_association.name}=",has_one_association.klass.find_by_id(id))
end
end
end
end
, . CMS has_one . , .
class TechProcess < ApplicationRecord
include MdcSchema
include HasOneHandler
has_many :executor_programs, inverse_of: :tech_process, foreign_key: :barcode_tech_process, primary_key: :barcode
validates :barcode, presence: true
validates :barcode, uniqueness: true
has_one :draft2tech_process, dependent: :destroy
has_one :draft, through: :draft2tech_process
has_many :tech_process2tech_operations
has_many :tech_operations, through: :tech_process2tech_operations
end
J'espère avoir pu montrer la valeur pratique de l'utilisation des techniques de métaprogrammation. Bien sûr, vous décidez de l'utiliser ou non. Si vous l'utilisez trop souvent et hors de propos, le projet deviendra absolument illisible et difficile à déboguer, mais s'il est utilisé correctement, au contraire, réduit la quantité de code, améliore la lisibilité et élimine le travail de routine. Merci à tous ceux qui l'ont lu!