简体   繁体   中英

ruby include vs extend

I am trying to abstract some of the logic required for cropping images into a module so that its not messing up my models. The code is based on http://railscasts.com/episodes/182-cropping-images

module CroppableImage
  def croppable_image(*image_names)
    image_names.each do |image_name|

      define_method "#{image_name}_sizes" do
        { :cropped => read_attribute("#{image_name}_size").to_s, :large => "800x800>" }
      end

      define_method "#{image_name}_geometry" do |style|
        style ||= :original
        @geometry ||= {}
        @geometry[style] ||= Paperclip::Geometry.from_file(eval "#{image_name}.path(style)")
      end

      define_method "#{image_name}_aspect_ratio" do
        width, height = read_attribute("#{image_name}_size").split("x")
        width.to_f / height.to_f
      end

      private

        define_method "reprocess_#{image_name}" do
          eval "#{image_name}.reprocess!"
        end

    end
  end

end

To include this into my model it seems that I have to use extend. I thought extend was for including class methods. I am from a java background - I thought using extend basically created static method on the class.

class Website < ActiveRecord::Base
  extend CroppableImage
  croppable_image :logo, :footer_image

-- this works

It seems then that what I am really wanting is to create instance methods.

class Website < ActiveRecord::Base
  include CroppableImage
  croppable_image :logo, :footer_image

-- This throws the error "undefined method `croppable_image' for #"

Can anyone please explain whats going on and if I should be using include or extend in this case. Thanks guys

extend M internally is similar to class << self; include M; end class << self; include M; end class << self; include M; end - extend includes module into singleton class of an object (and makes instance methods of the module to be a singleton methods of a class you extend).

In your case you call croppable_image in the context of a class definition and thus croppable_image should be an instance method of a Class class or a singleton method of Website class.

This is why you should extend Website class with a module CroppableImage by using extend CroppableImage - it adds instance method croppable_image as a singleton method of Website class.

you can use both logic together. Ruby has callbacks for extend and include Example of using included callback

module CroppableImage
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def bar
      puts 'class method'
    end
  end

  def foo
    puts 'instance method'
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM