web-dev-qa-db-fra.com

ruby / Rails: Comment déterminer si le module est inclus?

En développant ma question ici ( Ruby/Rails: extension ou inclusion d'autres modules ), en utilisant ma solution existante, quelle est la meilleure façon de déterminer si mon module est inclus?

Ce que j'ai fait pour l'instant, c'est que j'ai défini des méthodes d'instance sur chaque module, donc lorsqu'elles sont incluses, une méthode sera disponible, puis j'ai simplement ajouté un capteur (method_missing()) au module parent afin que je puisse détecter si elles ne sont pas inclus. Mon code de solution ressemble à:

module Features
  FEATURES = [Running, Walking]

  # include Features::Running
  FEATURES.each do |feature|
    include feature
  end

  module ClassMethods
    # include Features::Running::ClassMethods
    FEATURES.each do |feature|
      include feature::ClassMethods
    end
  end

  module InstanceMethods
    def method_missing(meth)
      # Catch feature checks that are not included in models to return false
      if meth[-1] == '?' && meth.to_s =~ /can_(\w+)\z?/
        false
      else
        # You *must* call super if you don't handle the method,
        # otherwise you'll mess up Ruby's method lookup
        super
      end
    end
  end

  def self.included(base)
    base.send :extend, ClassMethods
    base.send :include, InstanceMethods
  end
end

# lib/features/running.rb
module Features::Running
  module ClassMethods
    def can_run
      ...

      # Define a method to have model know a way they have that feature
      define_method(:can_run?) { true }
    end
  end
end

# lib/features/walking.rb
module Features::Walking
  module ClassMethods
    def can_walk
      ...

      # Define a method to have model know a way they have that feature
      define_method(:can_walk?) { true }
    end
  end
end

Donc dans mes modèles j'ai:

# Sample models
class Man < ActiveRecord::Base
  # Include features modules
  include Features

  # Define what man can do
  can_walk
  can_run
end

class Car < ActiveRecord::Base
  # Include features modules
  include Features

  # Define what man can do
  can_run
end

Et puis je peux

Man.new.can_walk?
# => true
Car.new.can_run?
# => true
Car.new.can_walk? # method_missing catches this
# => false

Ai-je bien écrit cela? Ou existe-t-il une meilleure façon?

27
index

Si je comprends bien votre question, vous pouvez le faire:

Man.included_modules.include?(Features)?

Par exemple:

module M
end

class C
  include M
end

C.included_modules.include?(M)
  #=> true

comme

C.included_modules
  #=> [M, Kernel]

D'autres moyens:

comme @Markan l'a mentionné:

C.include? M
  #=> true

ou:

C.ancestors.include?(M)
  #=> true

ou juste:

C < M
  #=> true 
47
Cary Swoveland