Ruby klases metožu pārdefinēšana

Saskāros ar situāciju, kad bija nepieciešams eksistējošu klases metodi pārdefinēt modulī kuru var iekļaut šī klase. Sākumā viss šķita vienkārši, bet tad mazliet papētot sapratu, ka nav nemaz tik ērti. Tāpēc gribu padalīties ar dažiem piemēriem, kuri var noderēt dažādās situācijās.

Piemērs Nr.1

Ja gadījumā ir situācija, kad ir nepieciešams kādai klasei pēc tās definēšanas pievienot kādu klases metodi (singleton), kas ir jau pašā klasē, tad viena pieeja būtu atvērt klasi un pievienot metodi vai arī ar class_eval to pārrakstīt.

class User
   def self.username
     "Username"
   end
 end
 User.class_eval do
   def self.username
     "AdminUser"
   end
 end

Viennozīmīgi varu pateikt, ka nestrādās include vai extend, gan atverot Eigenklasi, gan saucot uz pašu klasi, ja metode jau reiz ir nodefinēta klasē.
Šie piemēri nestrādā

 module Admin
   def username
     "AdminUser"
   end
 end
 class << User
   include Admin
 end
 User.extend(Admin)

Šie piemēri strādā, ja neeksistē vēl šāda klases metode.

Piemērs Nr.2

Vēl viens veids kā, tomēr panākt lai būtu iespējams iekļaut moduli ir ar alias.

class User
   def self.username
      "Username"
   end
 end
 module Admin
   def self.included(base)
     base.singleton_class.class_eval do
       include ClassMethods
       alias :username, :admin_username
     end
   end
   module ClassMethods
     def admin_username
       "Admin"
     end
   end
 end
 User.username   #=> Username
 User.send(:include,Admin)
 User.username   #=> Admin

Protams, ka šāda pieeja liek definēt metodes ar citiem nosaukumiem, tomēr, tas ir samērā ērts veids kā automatizēt moduļa metožu pārrakstīšananu.

 Admin::ClassMethods.instance_methods.each do |method|
   name=method.to_s.gsub("admin_","").to_sym
   eval%(alias #{name} #{method})
 end

Piemērs Nr.3

Viens veids kā panākt, lai objekts uzvestos kā klase, bet ar pārrakstītām klases metodēm, ir izveidot anonīmuklasi, kuras superklase ir, klase kuras metodes ir jāpārraksta.

class User
     def self.username
       "Username"
     end
     def is_user?
       true
     end
   end
   module Admin
     def self.username
       "Admin"
     end
   end
   User.username #=> Username
   klass=Class.new(User)
   klass.extend(Admin)
   klass.is_user? #=> true
   klass.username #=> Admin
Atbildēt

Jūsu e-pasta adrese netiks publicēta.