Olá! Neste artigo, quero falar sobre metaprogramação usando um exemplo de um problema comum real.
Quando alguém fala sobre metaprogramação, um programador da velha escola tem um acesso de raiva.
E há razões para isso, e em um grande projeto pode parecer loucura usar metaprogramação, pois o código se torna muito difícil de ler. E se um especialista de fora se juntar ao projeto, ele ainda mais não entenderá nada neste meta-código.
Mas não é tão simples quanto dizem - não existem ferramentas ruins. Neste artigo, tentarei mostrar com um exemplo real de trabalho como a metaprogramação pode ajudar a tornar seu código mais limpo e eliminar as repetições de rotina. E vai fazer você se alegrar com a metamágica.
Ajuda da wikipedia
Metaprogramação é um tipo de programação associada à criação de programas que geram outros programas como resultado de seu trabalho (em particular, na fase de compilação de seu código-fonte), ou programas que se alteram durante a execução (código auto-modificador) . O primeiro permite obter programas com menos tempo e esforço de codificação do que se o programador os escrevesse inteiramente à mão, o segundo permite melhorar as propriedades do código (tamanho e desempenho).
Isso conclui a introdução. Agora eu quero passar para a parte prática e falar sobre a essência do problema
Além disso, falaremos sobre a linguagem ruby e o framework Rails em particular. Ruby tem reflexão e grandes oportunidades para metaprogramação. A maioria das joias, módulos e estruturas são construídas com ferramentas de reflexão poderosas.
Foto de Joshua Fuller no Unsplash
Quem escreveu algo no Rails provavelmente encontrou uma joia como o Rails Admin, se você não tentou usá-lo em seus projetos no Rails, ou se você tem análogos, eu recomendo fortemente fazer isso, já que quase pronto, você irá obtenha um CMS completo para o seu sistema.
Portanto, há um recurso desagradável , o problema com a associação 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
Espero ter conseguido mostrar o valor prático do uso de técnicas de metaprogramação. Claro, você decide se vai usar ou não. Se você usar com muita frequência e fora do lugar, o projeto se tornará absolutamente ilegível e difícil de depurar, mas se usado corretamente, ao contrário, reduz a quantidade de código, melhora a legibilidade e elimina o trabalho rotineiro. Obrigado a todos que leram!