from - Ruby: Aufruf der Klassenmethode von der Instanz




ruby invoke class method from instance (6)

Wie rufst du in Ruby eine Klassenmethode von einer Instanz dieser Klasse an? Sag ich habe

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

Die Zeile Truck.default_make ruft den Standard ab. Aber gibt es eine Möglichkeit, dies zu sagen, ohne Truck zu erwähnen? Es scheint so als müsste es sein.


Ähnlich Ihrer Frage könnten Sie Folgendes verwenden:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end

Anstatt auf den self.class.whatever der Klasse zu verweisen, können Sie innerhalb einer Instanzmethode einfach 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

Ausgänge:

Class method: Foo
Instance method: Foo

Du machst es richtig. Klassenmethoden (ähnlich wie 'statische' Methoden in C ++ oder Java) sind nicht Teil der Instanz, daher müssen sie direkt referenziert werden.

In diesem Beispiel wäre es besser, "default_make" zu einer normalen Methode zu machen:

#!/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()

Klassenmethoden sind nützlicher für Funktionen vom Dienstprogrammtyp, die die Klasse verwenden. Beispielsweise:

#!/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

Einer noch:

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

Hier ist ein Ansatz, wie Sie eine _class Methode implementieren _class , die in dieser Situation als self.class funktioniert. Hinweis: Benutze das nicht im Produktionscode, dies ist aus Gründen des Interesses :)

Von: Können Sie Code im Kontext eines Aufrufers in Ruby einlesen? und auch 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

Vielleicht ist die richtige Antwort, einen Patch für Ruby einzureichen :)


Wenn Sie Zugriff auf die Delegate-Methode haben, können Sie Folgendes tun:

[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"

Alternativ und wahrscheinlich sauberer, wenn Sie mehr als eine oder zwei Methoden haben, die Sie an Klasse und Instanz delegieren möchten:

[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"

Ein Wort der Warnung:

Ordnen Sie nicht einfach alle Elemente, die den Status nicht ändern, zufällig an Klasse und Instanz an, da Sie damit beginnen, Konflikte mit seltsamen Namen zu lösen. Tun Sie dies sparsam und erst nachdem Sie nichts anderes überprüft haben, wird es gequetscht.





class-method