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