socialgekon.com
  • Glavni
  • Urejanje
  • Nasveti za iOS
  • Inženirski Management
  • Orodja In Vaje
Tehnologija

Rubyjevo metaprogramiranje je še bolj kul, kot se sliši

Pogosto slišite, da je metaprogramiranje nekaj, kar uporabljajo le Ruby nindže in da preprosto ni za navadne smrtnike. Toda resnica je, da metaprogramiranje sploh ni nekaj strašljivega. Ta objava v spletnem dnevniku bo služila izzivu tovrstnega razmišljanja in približanju metaprogramiranja povprečnemu razvijalcu Rubyja, da bodo lahko tudi izkoristili njegove prednosti.

Ruby metaprogramiranje: koda za pisanje kode Tweet

Treba je opozoriti, da bi lahko metaprogramiranje veliko pomenilo in ga je pogosto mogoče zelo zlorabiti in iti do skrajnosti, ko gre za uporabo, zato bom poskusil navesti nekaj primerov iz resničnega sveta, ki bi jih lahko vsak uporabil pri vsakodnevnem programiranju.

Metaprogramiranje

Metaprogramiranje je tehnika, s katero lahko napišete kodo, ki piše koda sama dinamično med izvajanjem. To pomeni, da lahko med izvajanjem definirate metode in razrede. Noro, kajne? Na kratko, z metaprogramiranjem lahko znova odprete in spremenite razrede, ujamete metode, ki ne obstajajo, in jih sproti ustvarite, ustvarite kodo, ki je SUHO z izogibanjem ponovitvam in še več.



Osnove

Preden se poglobimo v resno metaprogramiranje, moramo raziskati osnove. In najboljši način za to je z zgledom. Začnimo z enim in razumemo Rubyjevo metaprogramiranje po korakih. Verjetno lahko ugibate, kaj počne ta koda:

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

Opredelili smo razred z dvema metodama. Prva metoda v tem razredu je metoda razreda, druga pa metoda primerka. To je osnovna stvar v Rubyju, vendar se za to kodo dogaja veliko več, kar moramo razumeti, preden nadaljujemo. Omeniti velja, da je razred Developer sam je dejansko objekt. V Rubyju je vse predmet, vključno z razredi. Ker Developer je primerek, je primerek razreda Class. Evo, kako izgleda objektni model Ruby:

Ruby objektni model

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

Pomembno je, da tukaj razumemo pomen self. The frontend metoda je običajna metoda, ki je na voljo v primerkih razreda Developer, zakaj pa je backend metoda razredna metoda? Vsak del kode, izveden v Rubyju, se izvrši proti določenemu sebe . Ko interpreter Ruby izvede katero koli kodo, vedno zabeleži vrednost self za katero koli določeno vrstico. self se vedno nanaša na nek objekt, vendar se lahko ta objekt spremeni na podlagi izvedene kode. Na primer, znotraj definicije razreda je self se nanaša na sam razred, ki je primerek razreda Class.

class Developer p self end # Developer

Metode znotraj primerka, self se nanaša na primerek razreda.

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

Znotraj metod razreda, self se na nek način nanaša na sam razred (o katerem bomo podrobneje govorili v nadaljevanju tega članka):

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

To je v redu, kaj pa je razredna metoda? Preden odgovorimo na to vprašanje, moramo omeniti obstoj nečesa, čemur pravimo metaklasa, znana tudi kot singleton razred in lastni razred. Razredna metoda frontend kar smo prej definirali, ni nič drugega kot metoda primerka, definirana v metaklasi za objekt Developer! Metaklas je v bistvu razred, ki ga Ruby ustvari in vstavi v hierarhijo dedovanja, da zadrži metode razreda, s čimer ne posega v primerke, ustvarjene iz razreda.

Metaklase

Vsak predmet v Rubyju ima svojega metaklasa . Razvijalcu je nekako neviden, vendar je tam in ga lahko zelo enostavno uporabite. Od našega razreda Developer je v bistvu objekt, ima svoj metaklas. Kot primer ustvarimo objekt razreda String in manipulira z njegovim metaklasom:

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

Kar smo storili tukaj, smo dodali singleton metodo something na predmet. Razlika med metodami razreda in metodami singleton je v tem, da so metode razreda na voljo vsem primerkom predmeta razreda, medtem ko so metode singletona na voljo samo temu posameznemu primerku. Metode razredov se pogosto uporabljajo, medtem ko se enojne metode ne uporabljajo toliko, vendar sta obe vrsti metod dodani v metarazred tega predmeta.

Prejšnji primer bi lahko na novo napisali tako:

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

Sintaksa je drugačna, vendar dejansko naredi isto. Zdaj se vrnimo na prejšnji primer, kjer smo ustvarili Developer razreda in raziščite nekatere druge sintakse, da definirate metodo razreda:

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

To je osnovna definicija, ki jo uporabljajo skoraj vsi.

def Developer.backend 'I am backend developer' end

To je ista stvar, mi definiramo backend metoda razreda za Developer. Nismo uporabili self toda z definiranjem takšne metode je to dejansko metoda razreda.

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

Spet definiramo metodo razreda, vendar uporabljamo sintakso, podobno tisti, ki smo jo uporabili za določitev enojne metode za String predmet. Morda boste opazili, da smo uporabili self tukaj se nanaša na Developer predmet sam. Najprej smo odprli Developer razreda, tako da je samo enak Developer razred. Nato naredimo class << self in postanemo enaki metaklasu Developer Nato določimo metodo backend na Developer metaklasi.

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

Z definiranjem takega bloka nastavimo self do metaklase Developer za čas trajanja bloka. Kot rezultat se backend metoda je dodana v metarazred Developer in ne v sam razred.

Poglejmo, kako se ta metaklas obnaša v drevesu dedovanja:

Metaklas v dednem drevesu

Kot ste videli v prejšnjih primerih, ni pravega dokaza, da metaklasa sploh obstaja. Lahko pa uporabimo majhen kramp, ki nam lahko pokaže obstoj tega nevidnega razreda:

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

Če določimo metodo primerka v Object razred (da, kateri koli razred lahko kadar koli znova odpremo, to je še ena lepota metaprogramiranja), imeli bomo self ki se nanaša na Object predmet v njem. Nato lahko uporabimo class << self sintaksa za spremembo trenutne sebe da kaže na metaklaso trenutnega predmeta. Ker je trenutni objekt Object samega razreda, bi bil to metaklasa primerka. Metoda vrne self ki je v tem trenutku sam metaklas. S klicem te metode primerka na katerem koli objektu lahko dobimo metaklas tega predmeta. Določimo naše Developer ponovno poučite in začnite malo raziskovati:

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: #'

In za krešendo poglejmo dokaz, da frontend je metoda primerka razreda in backend je metoda primerka metaklase:

p developer.class.instance_methods false # [:frontend] p developer.class.metaclass_example.instance_methods false # [:backend]

Čeprav za pridobitev metaklasa ni treba dejansko znova odpreti Object in dodajte ta kramp. Uporabite lahko singleton_class ki jih Ruby zagotavlja. Je enako kot metaclass_example dodali smo, toda s tem krampom lahko dejansko vidite, kako Ruby deluje pod pokrovom:

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

Določanje metod z uporabo “class_eval” in “instance_eval”

Obstaja še en način za ustvarjanje metode predavanja, in sicer z uporabo 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'

Ta del kode, ki ga interpreter Ruby oceni v kontekstu primerka, ki je v tem primeru Developer predmet. In ko definirate metodo za objekt, ustvarite bodisi metodo razreda ali eno metodo. V tem primeru gre za metodo razreda - natančneje, metode razreda so singleton metode, vendar singleton metode razreda, medtem ko so druge singleton metode predmeta.

Po drugi strani, class_eval ovrednoti kodo v kontekstu razreda namesto primerka. Praktično ponovno odpre razred. Evo, kako class_eval se lahko uporablja za ustvarjanje metode primerka:

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: #'

Če povzamem, ko pokličete class_eval , spremenite self za sklicevanje na prvotni razred in ko pokličete instance_eval, self spremembe, ki se nanašajo na metaklase prvotnega razreda.

Opredelitev manjkajočih metod na letenje

Še en del sestavljanke metaprogramiranja je method_missing . Ko pokličete metodo na predmetu, Ruby najprej preide v razred in pobrska po metodah primerka. Če metode tam ne najde, nadaljuje iskanje po verigi prednikov. Če Ruby metode še vedno ne najde, pokliče drugo metodo z imenom method_missing ki je metoda primera Kernel ki ga podeduje vsak predmet. Ker smo prepričani, da bo Ruby sčasoma poklical to metodo zaradi manjkajočih metod, jo lahko uporabimo za izvajanje nekaterih trikov.

define_method je metoda, definirana v Module razreda, ki ga lahko uporabite za dinamično ustvarjanje metod. Če želite uporabiti define_method, ga pokličete z imenom nove metode in blokom, kjer parametri bloka postanejo parametri nove metode. Kakšna je razlika med uporabo def ustvariti metodo in define_method? Ni velike razlike, razen če lahko uporabite define_method v kombinaciji z method_missing napisati SUHO kodo. Natančneje, lahko uporabite define_method namesto def manipulirati z obsegi pri opredeljevanju razreda, vendar je to povsem druga zgodba. Oglejmo si preprost primer:

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!'

To kaže, kako define_method je bil uporabljen za ustvarjanje metode primerka brez uporabe def. Vendar lahko z njimi naredimo še veliko več. Oglejmo si ta delček kode:

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'

Ta koda ni SUHA, ampak uporablja define_method lahko ga naredimo SUHEGA:

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'

To je veliko bolje, vendar še vedno ni popolno. Zakaj? Če želimo dodati novo metodo coding_debug na primer, moramo postaviti to 'debug' v matriko. Ampak z uporabo method_missing to lahko popravimo:

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

Ta del kode je nekoliko zapleten, zato ga razčlenimo. Poklic metode, ki ne obstaja, se bo sprožil method_missing Tu želimo ustvariti novo metodo šele, ko se ime metode začne z 'coding_'. V nasprotnem primeru pokličemo samo super, da poroča o metodi, ki dejansko manjka. In mi preprosto uporabljamo define_method ustvariti to novo metodo. To je to! S tem delom kode lahko ustvarimo dobesedno na tisoče novih metod, začenši z 'coding_', in to je tisto, zaradi česar je naša koda SUHA. Ker define_method se zgodi, da je zasebno za Module, moramo uporabiti send da ga prikličete.

Zavijanje

To je le vrh ledene gore. Postati a Ruby Jedi , to je izhodišče. Ko obvladate te gradnike metaprogramiranja in resnično razumete njegovo bistvo, lahko nadaljujete do nečesa bolj zapletenega, na primer ustvarite svojega Domain-specific Language (DSL). DSL je tema sama po sebi, vendar so ti osnovni koncepti predpogoj za razumevanje naprednih tem. Nekateri najpogosteje uporabljeni dragulji v Tirnice so bili zgrajeni na ta način in ste verjetno uporabili njegov DSL, ne da bi ga sploh vedeli, na primer RSpec in ActiveRecord.

Upamo, da boste s tem člankom prišli korak bližje k razumevanju metaprogramiranja in morda celo k izdelavi lastnega DSL-ja, ki ga lahko uporabite za učinkovitejše kodiranje.

Potreba po hitrosti: retrospektiva ApeeScape JavaScript Coding Challenge

Back-End

Potreba po hitrosti: retrospektiva ApeeScape JavaScript Coding Challenge
Najboljši čas za objavo na TikTok za rekordne oglede v letu 2021

Najboljši čas za objavo na TikTok za rekordne oglede v letu 2021

Objava

Priljubljene Objave
Pregled iPhone SE 2020: Se ga splača kupiti za fotografiranje?
Pregled iPhone SE 2020: Se ga splača kupiti za fotografiranje?
Kako narediti posnetek zaslona na iPhoneu: 5 načinov za zajem zaslona
Kako narediti posnetek zaslona na iPhoneu: 5 načinov za zajem zaslona
Kako urejati videoposnetke v iPhonu s fotografijami in iMovie
Kako urejati videoposnetke v iPhonu s fotografijami in iMovie
Kako nastaviti arhitekturo mikro storitev v Ruby: Vodnik po korakih
Kako nastaviti arhitekturo mikro storitev v Ruby: Vodnik po korakih
Cordova Frameworks: Ionic vs. Framework7
Cordova Frameworks: Ionic vs. Framework7
 
Kako snemati družinsko fotografijo doma samo z vašim iPhoneom
Kako snemati družinsko fotografijo doma samo z vašim iPhoneom
Stalni podatki na straneh, ki se ponovno naložijo: piškotki, IndexedDB in vse, kar je vmes
Stalni podatki na straneh, ki se ponovno naložijo: piškotki, IndexedDB in vse, kar je vmes
Razbijanje procesa oblikovalskega razmišljanja
Razbijanje procesa oblikovalskega razmišljanja
Vodnik za oddaljene delavce, kako ostati zdrav
Vodnik za oddaljene delavce, kako ostati zdrav
Kako implementirati popoln dizajn uporabniškega vmesnika za iOS
Kako implementirati popoln dizajn uporabniškega vmesnika za iOS
Kategorije
Podatkovne Vede In Zbirke PodatkovKpi In AnalitikaStreljanjeProces In OrodjaInženirski ManagementOdpravljanje težavDrugoŽivljenjski Cikel IzdelkaMobilno OblikovanjeIzdelki In Ekipe

© 2023 | Vse Pravice Pridržane

socialgekon.com