มี alias_method สำหรับวิธีการเรียนหรือไม่?


10

พิจารณาคลาสต่อไปนี้:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
end

นี่ไม่มีปัญหาและคุณสามารถโทรFoo.new.a_new_inst_methodโดยไม่มีปัญหา

ฉันต้องการความสามารถในการมีคลาสวิธีการFoo.add_widget(*items)และนามแฝงเพื่อให้ฉันสามารถทำสิ่งที่ชอบ:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

โดยพื้นฐานแล้วมันมี "ruby style" ที่ชอบ1.minuteและ2.minutesดังนั้นฉันต้องการนามแฝงFoo.add_widgetดังนั้นการเรียกFoo.add_widgetsใช้วิธีการเดียวกันแน่นอน ฉันรู้ว่าฉันสามารถห่อมันได้ แต่ฉันรู้สึกว่าฉันควรจะทำสิ่งนี้ด้วยวิธีที่สะอาดกว่า

พิจารณาความพยายามของฉันที่ลองทำสิ่งนี้:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
  alias_method :a_new_class_method, :a_class_method
end

อย่างไรก็ตามฉันได้รับข้อผิดพลาดต่อไปนี้:

NameError (undefined method `a_class_method' for class `Foo')

และดูเหมือนว่านี่จะไม่ทำงานสำหรับวิธีการเรียน ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


9

alias_methodนามแฝงวิธีการอินสแตนซ์ของผู้รับ วิธีการเรียนเป็นจริงวิธีการอินสแตนซ์ที่กำหนดไว้ในชั้นเดียวของชั้นเรียน

class MyClass
  def self.a
    "Hello World!"
  end
end

method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)

method_1 == method_2
#=> true

เพื่อนามแฝงวิธีการอินสแตนซ์ที่กำหนดไว้ในชั้นเดียวคุณสามารถเปิดขึ้นโดยใช้class << objectไวยากรณ์

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

หรือคุณสามารถอ้างอิงได้โดยตรงโดยใช้singleton_classวิธีการ

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

หากคุณยังอยู่ในบริบทของคลาสselfจะอ้างอิงถึงคลาส ดังนั้นข้างต้นสามารถเขียนเป็น:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end

หรือ

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end

หรือการรวมกันของทั้งสอง


5

คุณสามารถห่อวิธีการเรียนและการalias_methodโทรของพวกเขาลงในโมดูลที่แยกต่างหากและรวมโมดูลนั้นเข้าในชั้นเรียนของคุณผ่านextend:

class Foo
  def an_inst_method
    'instance method'
  end
  alias_method :a_new_inst_method, :an_inst_method

  module ClassMethods
    def a_class_method
      'class method'
    end
    alias_method :a_new_class_method, :a_class_method
  end

  extend ClassMethods
end

เฮ้! ฉันลืมเกี่ยวกับการextend ClassMethodsแก้ปัญหา +1
aarona

4

สิ่งสำคัญที่ต้องเข้าใจคือไม่มีวิธีการเรียนใน Ruby

วิธีการเรียนเป็นเพียงวิธีการเดี่ยว ไม่มีอะไรพิเศษเกี่ยวกับวิธีการเรียน ทุกวัตถุสามารถมีวิธีการเดี่ยว เราเพิ่งเรียกพวกเขาว่า "วิธีการเรียน" เมื่อวัตถุเป็นClassเพราะ "วิธีการเดี่ยวของตัวอย่างClass " ยาวเกินไปและเทอะทะ

รอ! ฉันพูดว่า "วิธีการเดี่ยว"?

อีกสิ่งที่สำคัญที่ต้องเข้าใจคือไม่มีวิธีเช่นเดียวกับใน Ruby

วิธีการแบบซิงเกิลเป็นเพียงวิธีแบบเก่าที่น่าเบื่อแบบธรรมดาของคลาสซิงเกิล ไม่มีอะไรพิเศษเกี่ยวกับวิธีการแบบซิงเกิล พวกมันเป็นเพียงแค่วิธีการเช่นเดียวกับวิธีอื่น ๆ

ในความเป็นจริง Ruby มีวิธีการอินสแตนซ์เท่านั้น ไม่มีฟังก์ชั่นไม่มีตัวสร้างไม่มีวิธีการคงที่ไม่มีวิธีการเรียนไม่มีฟังก์ชั่นโมดูลไม่มีวิธีการเดี่ยว

คำถามไม่ใช่ "นี่เป็นวิธีการเรียนหรือไม่นี่เป็นวิธีการแบบซิงเกิล" แต่เป็น "วิธีการที่โมดูลนี้กำหนดไว้ใช่หรือไม่"

"วิธี Singleton" เป็นวิธีการอินสแตนซ์ที่กำหนดไว้ในคลาส singleton ไวยากรณ์สำหรับการเข้าถึงคลาส singleton fooคือ

class << foo
end

นอกจากนี้ยังมีวิธีการObject#singleton_classที่ส่งกลับชั้นเดียวของวัตถุ

เหตุใดฉันจึงใช้ความพยายามอย่างจริงจังเกี่ยวกับความจริงที่ว่าทุกวิธีเป็นวิธีการแบบอินสแตนซ์และวิธีการเรียนแบบนั้นไม่มีอยู่จริง? เพราะมันหมายความว่าแบบจำลองวัตถุของรูบี้นั้นง่ายกว่าที่คิด! ท้ายที่สุดในคำถามของคุณคุณได้แสดงให้เห็นแล้วว่าคุณรู้วิธีการตั้งชื่อแทนวิธีการอินสแตนซ์ แต่คุณบอกว่าคุณไม่ทราบวิธีใช้นามแฝงวิธีการเรียน แต่นั่นเป็นสิ่งที่ผิด! คุณไม่ทราบวิธีการวิธีการเรียนนามแฝงเพราะพวกเขามีวิธีการเช่นเพียง หากคุณได้รับการสอนข้อเท็จจริงนี้อย่างถูกต้องคุณจะไม่ต้องถามคำถามนี้เลย!

เมื่อคุณเข้าใจว่าทุกวิธีเป็นวิธีการแบบอินสแตนซ์และสิ่งที่เราเรียกว่า "วิธีการแบบซิงเกิล" เป็นเพียงวิธีการแบบอินสแตนซ์ของคลาสซิงเกิลการแก้ปัญหาจะกลายเป็นชัดเจน:

singleton_class.alias_method :a_new_class_method, :a_class_method

หมายเหตุ: เมื่อฉันเขียนข้างต้นว่า "ไม่มีสิ่งเช่น X" สิ่งที่ฉันหมายถึงคือ "ไม่มีสิ่งเช่น X ในภาษา Ruby " แต่นั่นไม่ได้หมายความว่าแนวคิดเหล่านี้ไม่ได้มีอยู่ในชุมชนทับทิม

เรามักพูดถึง "วิธีการแบบซิงเกิล" และ "วิธีการแบบชั้นเรียน" เพียงเพราะมันง่ายกว่าการพูดถึง "วิธีแบบอินสแตนซ์ของคลาสแบบซิงเกิล" หรือ "วิธีแบบอินสแตนซ์ของคลาสแบบเดี่ยวของวัตถุที่เกิดขึ้นเป็นตัวอย่างของClassชั้นเรียน " มีวิธีการชอบมีObject#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_methodและModule#module_functionในห้องสมุดหลักทับทิม แต่สิ่งสำคัญคือต้องจำไว้เสมอว่าสิ่งเหล่านั้นไม่ใช่แนวคิดทางภาษา เหล่านี้คือแนวคิดชุมชนที่มีอยู่ในหัวของเราและในชื่อของวิธีการห้องสมุดบางอย่าง


2

ตกลงดูเหมือนว่าฉันจะทำอะไรเช่นนี้และมันจะทำงาน:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    alias_method :a_new_class_method, :a_class_method
  end
end

Foo.a_class_method # => "class method" 
Foo.a_new_class_method # => "class method"

หากใครมีข้อมูลที่เป็นประโยชน์เกี่ยวกับภาษา Ruby ที่นี่และต้องการที่จะส่งคำตอบที่ครอบคลุมฉันจะให้ +1


1
เมื่อคุณทำclass << selfตามalias_method :a_new_class_method, :a_class_methodคุณจริงโทรบนชั้นเดี่ยวของalias_method Fooอีกวิธีในการเขียนนี้คือ: singleton_class.alias_method :a_new_class_method, :a_class_methodในบริบทของชั้นเรียน
3limin4t0r

คุณต้องการอะไรอีกจากคำตอบ ฉันหมายความว่านี่น่าจะเป็นทางออกที่สะอาดที่สุด
Dave Newton

@ 3limin4t0r ถ้าคุณตอบคำถามนั้นฉันจะ +1 มัน ขอบคุณสำหรับข้อมูลพิเศษนี้
aarona

@ เดฟนิวตันคุณพูดถูก แต่เพราะฉันยังมีปรัชญาที่ว่าถ้าใครสามารถให้ข้อมูลที่มีความหมายกับปัญหาแม้ว่ามันจะแก้ปัญหาทางอ้อมฉันก็คิดว่าควรได้รับรางวัลเช่นกัน
aarona

2

alias_methodทำงานบนอินสแตนซ์ดังนั้นคุณจะต้องไปหนึ่งระดับลึกและทำงานบนClassอินสแตนซ์หรือระดับ metaclass Ruby มีรูปแบบวัตถุที่สามารถทำลายสมองได้ แต่มันให้พลังมากมาย:

class Foo
  def an_inst_method
    'instance method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    def a_class_method
      'class method'
    end

    alias_method :a_new_class_method, :a_class_method
  end
end

ฉันทำงานกับทับทิมในบริบททางรถไฟมาประมาณหนึ่งทศวรรษ แต่เพิ่งจะเริ่มทำการดำน้ำลึกลงในโมเดลวัตถุ มีสิ่งดีๆมากมายให้เลือก!
aarona
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.