私がRubyクラスについて知っていることから、モジュールをクラスに含めると...ただし、Userの既存のインスタンスをさかのぼって変更することはありません。
それどころか、include / extendsは、クラスとそのスーパークラスの間のポインタの問題であるため、既存のすべてのインスタンスにすぐに影響します。Rubyで継承はどのように機能するかを参照してください。また、内部のリンク。
module HasAnAvatar
def m
puts 'in HasAnAvatar#m'
end
end
class AvatarUploader; end
class User
end
user = User.new
print 'user.respond_to?(:m) ? '; puts user.respond_to?(:m) ? 'yes' : 'no'
print '1) user.respond_to?(:avatar) ? '; puts user.respond_to?(:avatar) ? 'yes' : 'no'
class User
include HasAnAvatar
end
print 'user.respond_to?(:m) ? '; puts user.respond_to?(:m) ? 'yes' : 'no'
print '2) user.respond_to?(:avatar) ? '; puts user.respond_to?(:avatar) ? 'yes' : 'no'
module HasAnAvatar
def self.included(base)
puts "#{self} included into #{base}"
# base.mount_uploader :avatar, AvatarUploader
base.send(:attr_reader, :avatar)
end
end
class User
include HasAnAvatar
end
print '3) user.respond_to?(:avatar) ? '; puts user.respond_to?(:avatar) ? 'yes' : 'no'
print 'user.avatar : '; p user.avatar
print 'user.avatar.class : '; p user.avatar.class
user.instance_variable_set(:@avatar, AvatarUploader.new)
print 'after set, user.avatar : '; p user.avatar
print 'user.avatar.class : '; p user.avatar.class
実行(Ruby 1.9.2):
$ ruby -w t.rb
user.respond_to?(:m) ? no
1) user.respond_to?(:avatar) ? no
user.respond_to?(:m) ? yes
2) user.respond_to?(:avatar) ? no
HasAnAvatar included into User
3) user.respond_to?(:avatar) ? yes
user.avatar : nil
user.avatar.class : NilClass
after set, user.avatar : #<AvatarUploader:0x007fcc2b047cf8>
user.avatar.class : AvatarUploader
そのため、含まれているメソッドは、既存のすべてのインスタンスですぐに使用できるようになります。
なぜuser.avatar
nilと答えるのですか?インスタンス変数は...単一のインスタンスに属しているためです。Rubyのシンボルが変数の一種と見なされないのはなぜですか?を参照してください。
この場合、古いユーザーにはアバターが割り当てられていません。
しかし、なぜあなたは得るのですかuser2.avatar.class #=> AvatarUploader
。舞台裏では、base.mount_uploader :avatar, AvatarUploader
:avatarが対応するインスタンス変数のアクセサーではない、またはこの変数を新しいインスタンスに設定し始める初期化メソッドを定義するようなことをしていると思います。
2番目の例の解決策は次のとおりです。
module Pacifiable
def self.extended(host)
puts "#{host} extended by #{self}"
def host.pacified_with(mechanism)
@@method_name = "pacified_with_#{mechanism}?"
puts "about to define '#{@@method_name}' into #{self} of class #{self.class }"
if self.class == Class
then # define an instance method in a class
define_method(@@method_name) { true }
else # define a singleton method for an object
class << self
define_method(@@method_name) { true }
end
end
end
end
end
class JellyFish
define_method(:is_squishy?) { true }
end
class Lobster
extend Pacifiable
pacified_with :polar_bear
define_method(:is_squishy?) { false }
end
a_lobster = Lobster.new
print 'a_lobster.pacified_with_polar_bear? '; p a_lobster.pacified_with_polar_bear?
print 'a_lobster.is_squishy? '; p a_lobster.is_squishy?
jelly = JellyFish.new
### Add functionality to instance
#
## what I want:
#
jelly.extend(Pacifiable)
jelly.pacified_with(:polar_bear)
print 'jelly.pacified_with_polar_bear? '; p jelly.pacified_with_polar_bear? #=> true
実行:
Lobster extended by Pacifiable
about to define 'pacified_with_polar_bear?' into Lobster of class Class
a_lobster.pacified_with_polar_bear? true
a_lobster.is_squishy? false
#<JellyFish:0x007fcc2b047640> extended by Pacifiable
about to define 'pacified_with_polar_bear?' into #<JellyFish:0x007fcc2b047640> of class JellyFish
jelly.pacified_with_polar_bear? true
についてjelly.class.pacified_with(:polar_bear)
:間違いはclass
、クラスに答える、を呼び出すことでしたJellyFish
; 必要なのは、インスタンスオブジェクトjellyのシングルトンクラスです。オブジェクトのシングルトンクラスでメソッドが定義されると、それをオブジェクトに直接送信できます。クラスのインスタンスであるクラスにも同じことが当てはまります。クラスのシングルトンクラスでメソッドが定義されると、それをクラスに直接送信できます。それらをクラスメソッドと呼びます。実際には、クラスのシングルトンクラスのインスタンスメソッドです。Ouf!
最後のOR:説明したように、クラスを拡張すると、既存のすべてのインスタンスに対して有効になります。したがって、個々のインスタンスを拡張する必要があります。
class JellyFromTheBigBlueSea
def find
puts 'in JellyFromTheBigBlueSea#find'
jelly = JellyFish.new
jelly.extend(Pacifiable)
jelly.pacified_with :polar_bear
jelly
end
end
class JellyFromAnIsolatedCove
def find
puts 'in JellyFromAnIsolatedCove#find'
JellyFish.new
end
end
normal_jelly = JellyFromTheBigBlueSea.new.find
ignorant_jelly = JellyFromAnIsolatedCove.new.find
## what I want:
#
print 'normal_jelly.pacified_with_polar_bear? '; p normal_jelly.pacified_with_polar_bear?
print 'ignorant_jelly.pacified_with_polar_bear?' ; p ignorant_jelly.pacified_with_polar_bear?
実行:
in JellyFromTheBigBlueSea#find
#<JellyFish:0x007fb5d9045060> extended by Pacifiable
about to define 'pacified_with_polar_bear?' into #<JellyFish:0x007fb5d9045060> of class JellyFish
in JellyFromAnIsolatedCove#find
normal_jelly.pacified_with_polar_bear? true
ignorant_jelly.pacified_with_polar_bear?t.rb:109:in `<main>': undefined method `pacified_with_polar_bear?' for #<JellyFish:0x007fb5d9044d18> (NoMethodError)