2017-09-17 25 views
3

添付ファイルのツールキットであるshrine gemのソースコードを理解しようとしています。あなたはそのようなレールにあなたのモデルにアップローダーを定義することができます。クラスから継承するモジュール

class Picture < ApplicationRecord 
    include ImageUploader::Attachment.new(:image) 
end 

Attachmentのためのクラス定義は、このlink.

これはそれがすべてあるで見つけることができます:

class Attachment < Module 
    @shrine_class = ::Shrine 
end 

私の仮定これにより、インクルードのクラスをインスタンス化することができるので、mixinと同様に、メソッドをインクルードした場所で利用できるようになります。 Moduleはルビークラスですか?これはどのくらい正確に機能しますか?

編集:明確にするために

ImageUploaderはそうのように私のアプリに定義されています。

class ImageUploader < Shrine 
    plugin :remove_attachment 
end 

のでImageUploader::Attachment.new(:image)Attachmentクラスが神社に定義されていることを利用しています。

答えて

2

Moduleは確かにRubyのクラスです。クラスModuleのインスタンスはRubyモジュールです。例示するために、モジュールを定義するこれら二つの方法は等価である:ModuleのインスタンスはRubyのモジュールである

module MyModule 
    # ... 
end 

# is equivalent to 

MyModule = Module.new do 
    # ... 
end 

場合、それはModuleの任意サブクラスのインスタンスはShrine::Attachment含め、またRubyのモジュールであることを意味します。これは理にかなっています。includeはモジュールしか使用できないため、Shrine::Attachmentのインスタンスはモジュールでなければなりません。そのため神社のplugin system design

、この:

class Attachment < Module 
    @shrine_class = ::Shrine 
end 

Shrine::Attachmentの全体の実装ではありません。実際の実装はShrine::Plugins::Base::AttachmentMethodsモジュールで定義され、Shrine::Attachmentに含まれています。

Shrine::Attachment.newの実装を見ると、指定された属性名に基づいてメソッド自体を動的に定義することがわかります。たとえば、Shrine::Attachment.new(:image)は、以下のメソッドが定義されたモジュールを生成します。#image_attacher#image=#image、および#image_url。これらのメソッドは、Shrine::Attachmentインスタンスを含むモデルに追加されます。


なぜ私はちょうど、代わりにModuleの全体のサブクラスを作成するModule.new(のようなRefile does)を経由して新しいモジュールを作成する方法を持っていませんでしたか?よく、2つの主な理由:

#<Module:0x007f8183d27ab0>をモデルの祖先リストで見るのではなく、その定義を指す実際のShrine::Attachmentインスタンスが表示されるため、これはより良いイントロスペクションです。あなたはまだmanually override #to_s and #inspectかもしれませんが、これが良いです。

第2に、Shrine::Attachmentがクラスになっているため、他のShrineプラグインでもより多くの動作を拡張できます。だから、remote_urlプラグインが#<attachment>_remote_urlアクセサを追加し、data_uriプラグイン等

+1

宝石をありがとう、私はあなたが使用するコーディングスタイルが本当に好きです。 ImageUploader :: Attachment.new(:image)をインスタンス化するときに、 'AttachmentMethods'の中の' initialize'メソッドがどのように呼び出されるのか、私が不安なのは唯一のことです。 – trueinViso

+1

ファイルの末尾に 'Shrine :: plugins Shrine :: Plugins :: Base'が呼び出されます。これは' Shrine :: Plugins :: Base :: AttachmentMethods'を 'Shrine :: Attachment'に含めます(' Shrine :: Plugins :: Base :: ClassMethods#plugin')ので、 'Shrine :: Plugins :: Base :: AttachmentMethods#initialize'とそのモジュールの他のメソッドはすべて' Shrine :: Attachment'に追加されます'Shrine :: Attachment#initialize'が定義されています。 –

+1

私はJeremy Evansにプラグインシステムの実装全体を借りていますが、それは実質的にRodaの宝石のコピー貼りです:https://github.com/jeremyevans/roda –

1

Modulesは、メソッド、クラス、および定数をグループ化する方法です。ここconstrollerファイル内のクラス

アプリ/サービス/ purchase_service.rb

module PurchaseService 

    class PurchaseRequest 
    def initialize 
     # init value 
    end 

    def request_item 
     # action 
    end 
    end 

    class PurchaseOrder 
    def initialize 
     # init value 
    end 

    def order_item 
     # action 
    end 
    end 
end 

をグループ化する最初のサンプルでは、​​モジュール名を使用してクラスを呼び出すことができ、ある::従う

@purchase_svc = PurchaseService::PurchaseRequest.new 
@purchase_svc.request_item 
@purchase_svc = PurchaseService::PurchaseOrder.new 
@purchase_svc.order_item 
としてClass_name.new
は、

しかし、自然にクラスを構成しないものをまとめてグループ化したいときは、です。例えば、貨物用オブジェクトがスタック機能を持っている必要がある場合は、今ここで をグループ化するための第2の例であるが、クラス形式で

module_collection.rb、(一つのファイルは、2つのモジュールは、スタック、キュー有する)ない

module Stacklike 
    def stack 
    @stack ||= [] 
    end 

    def add_to_stack(obj) 
    @stack.push(obj) 
    end 

    def take_from_stack 
    @stack.pop 
    end 
end 

module Queuelike 
    # 
end 

私はモジュールを組み込みます。

cargo.rb、

require './module_collection.rb' 
    include Stacklike 
    # as cargo needs stack 
    class 
    def initialize 
     stack 
     # this will call stack method inside module_collection.rb 
    end 
    end 
1

注意を#<attachment>_data_uriアクセサを追加します。この答えを準備し、数時間を要しました。その間、ジャンコムはうまく答えています。

RailsやShrineの人は、Rubyでできることの知識を、Rubyの本を読んで想像できるレベルをはるかに超えています。私は十数語を読んでいます。時間の

99%が含ま

include SomeModule 

SomeModulerequire 'some_module'と現在のソースファイルに組み込まれる別個のファイルsome_module.rbで定義されている形態です。

この

include ImageUploader::Attachment.new(:image) 

は多くの理由のために注意が必要です。時間の

===内部クラス===

98%、クラスは主DEFメソッドが含まれて外部オブジェクト、一部が含まれており、クラスのインスタンス変数のピンチです。 Rubyのコードは数多く書かれていませんが、特別な状況では内部クラスには一度だけ書かれています。外部からは、またはShrine::Plugins::Base::AttacherMethodsなど、完全な アクセスパスを指定することによってのみ使用できます。

私は1つが

ImageUploader::Attachment 

===モジュールを書くことができるように、サブクラスが内部クラスを「継承」することを知りませんでした。new ===

十分なRubyドキュメントを読むと、クラスとモジュールの違いがモジュールをインスタンス化できないということが1,000倍わかります。モジュールは、クラス内のコードまたは(主に)mixinメソッドの周囲に名前空間を作成するためにのみ使用されます(より正確には、SomeModuleはメソッドの検索パスがクラスからSomeModuleに、次にスーパークラスになるように匿名スーパークラスを作成します明示的に定義されていない))。

こうして私は、拷問の下で、モジュールのための新しい方法がないと宣誓したでしょう。なぜなら、必要性がないからです。しかし、匿名モジュールを返すものがあります。

まあ、ここではモジュールではなくクラスImageUploader::Attachmentをインスタンス化し、さらにModule.newはクラスModuleをインスタンス化します。

===発現モジュールを返す必要があり、一定ではなく式を使用しない含む1%のための発現===

を含みます。そして、AttachmentがModuleから継承する理由についてのあなたの答えがあります。そのような相続財産は、不平をつきます。次のコードを実行すると動作します。

t.rb:28:in `include': wrong argument type Shrine::Attachment_O (expected Module) (TypeError) 
    from t.rb:28:in `<class:Picture>' 
    from t.rb:27:in `<main>' 

ファイルt.rb:

class Shrine 
    class Attachment_O 
     def initialize(parm=nil) 
      puts "creating an instance of #{self.class.name}" 
     end 
    end 

    class Attachment_M < Module 
     def initialize(parm=nil) 
      puts "creating an instance of #{self.class.name}" 
     end 
    end 
end 

print 'Attachment_O ancestors '; p Shrine::Attachment_O.ancestors 
print 'Attachment_M ancestors '; p Shrine::Attachment_M.ancestors 

class ImageUploader < Shrine 
end 

imupO = ImageUploader::Attachment_O.new 
imupM = ImageUploader::Attachment_M.new 

print 'imupO is a Module ? '; p imupO.is_a?(Module) 
print 'imupM is a Module ? '; p imupM.is_a?(Module) 

class Picture 
# include ImageUploader::Attachment_O.new(:image) 
    include ImageUploader::Attachment_M.new(:image) 
end 

実行:

$ ruby -w t.rb 
Attachment_O ancestors [Shrine::Attachment_O, Object, Kernel, BasicObject] 
Attachment_M ancestors [Shrine::Attachment_M, Module, Object, Kernel, BasicObject] 
creating an instance of Shrine::Attachment_O 
creating an instance of Shrine::Attachment_M 
imupO is a Module ? false 
imupM is a Module ? true 
creating an instance of Shrine::Attachment_M 

あなたはクラスの画像で

# include ImageUploader::Attachment_O.new(:image) 

のコメントを解除した場合でも、誤りがあります

これはそれがすべてである:それは空であるため、一見すると

は、添付ファイルの定義は、好奇心と思われます。私は詳細にshrine.rbを勉強していないが、私はこれを見てきました:

# Load a new plugin into the current class ... 
def plugin(plugin, *args, &block) 
... 
    self::Attachment.include(plugin::AttachmentMethods) if defined?(plugin::AttachmentMethods) 

明らかにアタッチメントを後でモジュールを含めることによって方法が移入され、より正確に、includeは添付ファイルへの匿名のスーパークラスを作成し、このメソッドはAttachmentMethodsを指しており、メソッド検索メカニズムは含まれているモジュールのメソッドを見つけます。 How does Inheritance work in Ruby? も参照してください。

+0

説明ありがとうございます!それで、私はモジュールのための新しい方法がないという拷問の下で誓ったでしょう。必要がないからです。しかし、匿名のモジュールを返すものがある。それは面白い笑だった。 – trueinViso

関連する問題