Metaprogrammierung in einer realen Aufgabe

Hallo! In diesem Artikel möchte ich anhand eines Beispiels für ein wirklich häufiges Problem über die Metaprogrammierung sprechen.





Wenn jemand über Metaprogrammierung spricht, bekommt ein Codierer der alten Schule einen Wutanfall.





Und es gibt Gründe dafür, und bei einem großen Projekt mag es verrückt erscheinen, Metaprogrammierung zu verwenden, da der Code sehr schwer zu lesen ist. Und wenn sich ein externer Spezialist dem Projekt anschließt, wird er darüber hinaus nichts in diesem Metacode verstehen.





Aber es ist nicht so einfach wie sie sagen - es gibt keine schlechten Werkzeuge. In diesem Artikel werde ich versuchen, anhand eines realen Beispiels zu zeigen, wie Metaprogrammierung dazu beitragen kann, Ihren Code sauberer zu machen und routinemäßige Wiederholungen zu vermeiden. Und Sie werden sich über Metamagie freuen.





Hilfe von Wikipedia

Metaprogrammierung ist eine Art der Programmierung, die mit der Erstellung von Programmen verbunden ist, die aufgrund ihrer Arbeit andere Programme generieren (insbesondere in der Phase der Kompilierung ihres Quellcodes), oder von Programmen, die sich während der Ausführung selbst ändern (selbstmodifizierender Code). . Mit dem ersten können Sie Programme mit weniger Zeit und Aufwand für das Codieren abrufen, als wenn der Programmierer sie vollständig von Hand geschrieben hätte, mit dem zweiten können Sie die Eigenschaften des Codes (Größe und Leistung) verbessern.





Damit ist die Einführung abgeschlossen. Jetzt möchte ich zum praktischen Teil übergehen und Ihnen die Essenz des Problems erläutern

Weiter werden wir über die Ruby-Sprache und insbesondere das Rails-Framework sprechen. Ruby hat Reflexion und großartige Möglichkeiten für die Metaprogrammierung. Die meisten Edelsteine, Module und Frameworks werden mit leistungsstarken Reflexionswerkzeugen erstellt.





Foto von Joshua Fuller auf Unsplash





Wer auch immer etwas auf Rails geschrieben hat, ist höchstwahrscheinlich auf ein Juwel wie Rails Admin gestoßen. Wenn Sie nicht versucht haben, es in Ihren Projekten auf Rails zu verwenden, oder wenn Sie Analoga haben, empfehle ich dies dringend, da Sie dies fast sofort tun werden Holen Sie sich ein vollwertiges CMS für Ihr System.





Es gibt also eine unangenehme Funktion, das Problem mit der Zuordnung has_one.





has_one . 1. , .





Bild 1
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

      
      







. has_one , . .









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

      
      







Ich hoffe, ich konnte den praktischen Wert der Verwendung von Metaprogrammiertechniken zeigen. Natürlich entscheiden Sie, ob Sie es verwenden möchten oder nicht. Wenn Sie es zu oft und fehl am Platz verwenden, wird das Projekt zu einem absolut unlesbaren und schwer zu debuggenden Projekt. Bei korrekter Verwendung wird jedoch im Gegenteil die Codemenge reduziert, die Lesbarkeit verbessert und Routinearbeiten vermieden. Vielen Dank an alle, die es gelesen haben!








All Articles