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. , .
. 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
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!