Ruby: l'Appel d'une méthode de la classe de l'instance

dans Ruby, comment appelez-vous une méthode de classe à partir d'une des instances de cette classe? Dites que j'ai

class Truck
  def self.default_make
    # Class method.
    "mac"
  end

  def initialize
    # Instance method.
    Truck.default_make  # gets the default via the class's method.
    # But: I wish to avoid mentioning Truck. Seems I'm repeating myself.
  end
end

la ligne Truck.default_make récupère la valeur par défaut. Mais y a-t-il un moyen de le dire sans mentionner Truck ? Il semble comme il devrait être.

295
demandé sur Andrew Grimm 2010-03-27 04:48:01

9 réponses

plutôt que de se référer au nom littéral de la classe, à l'intérieur d'une méthode d'instance vous pouvez simplement appeler self.class.whatever .

class Foo
    def self.some_class_method
        puts self
    end

    def some_instance_method
        self.class.some_class_method
    end
end

print "Class method: "
Foo.some_class_method

print "Instance method: "
Foo.new.some_instance_method

sorties:

Class method: Foo
Instance method: Foo
492
répondu Mark Rushakoff 2010-03-27 02:33:57

utiliser self.class.blah N'est pas la même chose que ClassName.blah lorsqu'il s'agit de l'héritage.

class Truck
  def self.default_make
    "mac"
  end

  def make1
    self.class.default_make
  end

  def make2
    Truck.default_make
  end
end


class BigTruck < Truck
  def self.default_make
    "bigmac"
  end
end

ruby-1.9.3-p0 :021 > b=BigTruck.new
 => #<BigTruck:0x0000000307f348> 
ruby-1.9.3-p0 :022 > b.make1
 => "bigmac" 
ruby-1.9.3-p0 :023 > b.make2
 => "mac" 
164
répondu Mark B 2015-02-05 17:44:02
self.class.default_make
6
répondu yfeldblum 2010-03-27 03:28:13

pour accéder à une méthode de classe à l'intérieur d'une méthode d'instance, faites ce qui suit:

self.class.default_make

Voici une solution alternative à votre problème:

class Truck

  attr_accessor :make, :year

  def self.default_make
    "Toyota"
  end

  def make
    @make || self.class.default_make
  end

  def initialize(make=nil, year=nil)
    self.year, self.make = year, make
  end
end

maintenant utilisons notre classe:

t = Truck.new("Honda", 2000)
t.make
# => "Honda"
t.year
# => "2000"

t = Truck.new
t.make
# => "Toyota"
t.year
# => nil
6
répondu Harish Shetty 2017-11-16 02:56:17

vous le faites de la bonne façon. Les méthodes de classe (similaires aux méthodes 'statiques' en C++ ou Java) ne font pas partie de l'instance, elles doivent donc être référencées directement.

sur cette note, dans votre exemple, vous seriez mieux servi en faisant 'default_make' une méthode régulière:

#!/usr/bin/ruby

class Truck
    def default_make
        # Class method.
        "mac"
    end

    def initialize
        # Instance method.
        puts default_make  # gets the default via the class's method.
    end
end

myTruck = Truck.new()
Les méthodes de classe

sont plus utiles pour les fonctions de type utilitaire qui utilisent la classe. Par exemple:

#!/usr/bin/ruby

class Truck
    attr_accessor :make

    def default_make
        # Class method.
        "mac"
    end

    def self.buildTrucks(make, count)
        truckArray = []

        (1..count).each do
            truckArray << Truck.new(make)
        end

        return truckArray
    end

    def initialize(make = nil)
        if( make == nil )
            @make = default_make()
        else
            @make = make
        end
    end
end

myTrucks = Truck.buildTrucks("Yotota", 4)

myTrucks.each do |truck|
    puts truck.make
end
5
répondu Maha 2010-03-27 02:16:24

si vous avez accès à la méthode des délégués, vous pouvez le faire:

[20] pry(main)> class Foo
[20] pry(main)*   def self.bar
[20] pry(main)*     "foo bar"
[20] pry(main)*   end  
[20] pry(main)*   delegate :bar, to: 'self.class'
[20] pry(main)* end  
=> [:bar]
[21] pry(main)> Foo.new.bar
=> "foo bar"
[22] pry(main)> Foo.bar
=> "foo bar"

alternativement, et probablement plus propre si vous avez plus d'une méthode ou deux que vous voulez déléguer à Classe & instance:

[1] pry(main)> class Foo
[1] pry(main)*   module AvailableToClassAndInstance
[1] pry(main)*     def bar
[1] pry(main)*       "foo bar"
[1] pry(main)*     end  
[1] pry(main)*   end  
[1] pry(main)*   include AvailableToClassAndInstance
[1] pry(main)*   extend AvailableToClassAndInstance
[1] pry(main)* end  
=> Foo
[2] pry(main)> Foo.new.bar
=> "foo bar"
[3] pry(main)> Foo.bar
=> "foo bar"

Un mot de prudence:

N'est pas seulement au hasard delegate tout ce qui n'a pas changer l'état de classe et d'instance parce que vous allez commencer à courir dans d'étranges nom choc des questions. Faites ceci avec parcimonie et après avoir vérifié, rien d'autre n'est écrasé.

5
répondu bbozo 2013-10-17 19:30:41

un de plus:

class Truck
  def self.default_make
    "mac"
  end

  attr_reader :make

  private define_method :default_make, &method(:default_make)

  def initialize(make = default_make)
    @make = make
  end
end

puts Truck.new.make # => mac
2
répondu Alexey 2014-06-17 20:33:58

Voici une approche sur la façon dont vous pourriez mettre en œuvre une méthode _class qui fonctionne comme self.class pour cette situation. Note: ne l'utilisez pas dans le code de production, c'est pour les intérêts:)

De: Pouvez-vous eval du code dans le contexte de l'appelant en Ruby? et aussi http://rubychallenger.blogspot.com.au/2011/07/caller-binding.html

# Rabid monkey-patch for Object
require 'continuation' if RUBY_VERSION >= '1.9.0'
class Object
  def __; eval 'self.class', caller_binding; end
  alias :_class :__
  def caller_binding
    cc = nil; count = 0
    set_trace_func lambda { |event, file, lineno, id, binding, klass|
      if count == 2
        set_trace_func nil
        cc.call binding
      elsif event == "return"
        count += 1
      end
    }
    return callcc { |cont| cc = cont }
  end
end

# Now we have awesome
def Tiger
  def roar
    # self.class.roar
    __.roar
    # or, even
    _class.roar
  end
  def self.roar
    # TODO: tigerness
  end
end

peut - être que la bonne réponse est de soumettre un patch pour Ruby :)

1
répondu captainpete 2017-05-23 12:26:42

similaire à votre question, vous pouvez utiliser:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
-6
répondu Daniel 2014-07-11 11:54:06