ฉันรู้ใน Ruby ว่าฉันสามารถใช้respond_to?
เพื่อตรวจสอบว่าวัตถุมีวิธีการบางอย่าง
แต่ให้ชั้นเรียนฉันจะตรวจสอบว่าอินสแตนซ์มีวิธีการบางอย่างได้อย่างไร
นั่นคือสิ่งที่ชอบ
Foo.new.respond_to?(:bar)
แต่ฉันรู้สึกว่ามีวิธีที่ดีกว่าการสร้างอินสแตนซ์ใหม่
ฉันรู้ใน Ruby ว่าฉันสามารถใช้respond_to?
เพื่อตรวจสอบว่าวัตถุมีวิธีการบางอย่าง
แต่ให้ชั้นเรียนฉันจะตรวจสอบว่าอินสแตนซ์มีวิธีการบางอย่างได้อย่างไร
นั่นคือสิ่งที่ชอบ
Foo.new.respond_to?(:bar)
แต่ฉันรู้สึกว่ามีวิธีที่ดีกว่าการสร้างอินสแตนซ์ใหม่
คำตอบ:
ฉันไม่รู้ว่าทำไมทุกคนแนะนำว่าคุณควรใช้instance_methods
และทำงานinclude?
เมื่อmethod_defined?
ไหร่
class Test
def hello; end
end
Test.method_defined? :hello #=> true
บันทึก
ในกรณีที่คุณมาทับทิมจากภาษา OO อื่นหรือคุณคิดว่าmethod_defined
หมายถึงวิธีการเดียวที่คุณกำหนดไว้อย่างชัดเจนด้วย:
def my_method
end
แล้วอ่านสิ่งนี้:
ใน Ruby คุณสมบัติ (attribute) ในแบบจำลองของคุณนั้นเป็นวิธีการเช่นกัน ดังนั้นmethod_defined?
จะส่งคืนจริงสำหรับคุณสมบัติไม่ใช่เฉพาะเมธอด
ตัวอย่างเช่น:
กำหนดอินสแตนซ์ของคลาสที่มีแอตทริบิวต์ String first_name
:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
เนื่องจากfirst_name
เป็นทั้งแอตทริบิวต์และเมธอด (และสตริงประเภท String)
String.instance_methods(false).include? :freeze
ที่เป็นเท็จอาร์กิวเมนต์สามารถบอกได้ว่าไม่ว่าจะเป็นfreeze
วิธีการที่กำหนดไว้ในระดับ String หรือไม่ ในกรณีนี้มันจะคืนค่าเท็จเนื่องจากfreeze
เมธอดนั้นสืบทอดมาจากโมดูลเคอร์เนลด้วย String แต่String.method_defined? :freeze
จะคืนค่าจริงเสมอซึ่งไม่สามารถช่วยอะไรได้มากกับวัตถุประสงค์ดังกล่าว
method_defined?
ต้องใช้กับคลาส (เช่นArray
) แต่คุณพยายามใช้กับอินสแตนซ์ (เช่น[]
)
คุณสามารถใช้method_defined?
ดังนี้
String.method_defined? :upcase # => true
ง่ายกว่าพกพาและมีประสิทธิภาพมากกว่าinstance_methods.include?
คนอื่น ๆ ดูเหมือนว่าจะแนะนำ
เก็บไว้ในใจว่าคุณจะไม่ทราบว่าระดับตอบสนองแบบไดนามิกเพื่อบางสายด้วยmethod_missing
เช่นโดยการกําหนดrespond_to?
หรือตั้งแต่ทับทิม 1.9.2 respond_to_missing?
ด้วยการกำหนด
instance.class.method_defined? :upcase
อันที่จริงมันใช้ไม่ได้กับทั้ง Objects และ Classes
สิ่งนี้:
class TestClass
def methodName
end
end
ดังนั้นด้วยคำตอบที่ได้รับงานนี้:
TestClass.method_defined? :methodName # => TRUE
แต่นี่ไม่ได้ผล:
t = TestClass.new
t.method_defined? : methodName # => ERROR!
ดังนั้นฉันจึงใช้สิ่งนี้สำหรับทั้งคลาสและวัตถุ:
ชั้นเรียน:
TestClass.methods.include? 'methodName' # => TRUE
วัตถุที่:
t = TestClass.new
t.methods.include? 'methodName' # => TRUE
คำตอบของ " ให้ชั้นเรียนดูว่าอินสแตนซ์มีเมธอด (Ruby) " ดีกว่าหรือไม่ เห็นได้ชัดว่า Ruby มีตัวนี้อยู่และฉันก็พลาดไป คำตอบของฉันถูกทิ้งไว้สำหรับการอ้างอิงโดยไม่คำนึงถึง
เรียนทับทิมตอบสนองต่อวิธีการและinstance_methods
public_instance_methods
ใน Ruby 1.8 รายการแรกจะแสดงชื่อเมธอดอินสแตนซ์ทั้งหมดในอาร์เรย์ของสตริงและอันดับที่สอง จำกัด เป็นวิธีสาธารณะ พฤติกรรมที่สองคือสิ่งที่คุณต้องการมากที่สุดเนื่องจากrespond_to?
จำกัด ตัวเองเป็นวิธีสาธารณะโดยค่าเริ่มต้นเช่นกัน
Foo.public_instance_methods.include?('bar')
อย่างไรก็ตามใน Ruby 1.9 วิธีการเหล่านั้นจะคืนค่าอาร์เรย์ของสัญลักษณ์
Foo.public_instance_methods.include?(:bar)
หากคุณวางแผนที่จะทำเช่นนี้บ่อยครั้งคุณอาจต้องการขยายModule
เพื่อรวมวิธีการทางลัด (อาจดูเหมือนแปลกที่จะกำหนดสิ่งนี้ให้Module
แทนClass
แต่เนื่องจากเป็นที่ที่instance_methods
วิธีการอาศัยอยู่จึงเป็นสิ่งที่ดีที่สุดเพื่อให้สอดคล้องกับรูปแบบนั้น)
class Module
def instance_respond_to?(method_name)
public_instance_methods.include?(method_name)
end
end
หากคุณต้องการสนับสนุนทั้ง Ruby 1.8 และ Ruby 1.9 นั่นจะเป็นสถานที่ที่สะดวกในการเพิ่มตรรกะเพื่อค้นหาทั้งสตริงและสัญลักษณ์เช่นกัน
method_defined?
ดีกว่า :)
ลอง Foo.instance_methods.include? :bar
ไม่แน่ใจว่านี่เป็นวิธีที่ดีที่สุดหรือไม่ แต่คุณสามารถทำสิ่งนี้ได้ตลอดเวลา:
Foo.instance_methods.include? 'bar'
ฉันคิดว่ามีบางอย่างผิดปกติmethod_defined?
ใน Rails มันอาจจะไม่สอดคล้องกันหรือบางอย่างดังนั้นถ้าคุณใช้ Rails มันจะดีกว่าถ้าใช้อะไรattribute_method?(attribute)
มันอาจจะไม่สอดคล้องหรืออะไรดังนั้นหากคุณใช้ทางรถไฟดีกว่าที่จะใช้อะไรบางอย่างจาก
" การทดสอบ method_defined? บนคลาส ActiveRecord ไม่ทำงานจนกว่าจะเริ่มอินสแตนซ์ " เป็นคำถามเกี่ยวกับความไม่สอดคล้องกัน
หากคุณกำลังตรวจสอบเพื่อดูว่าวัตถุสามารถตอบสนองต่อวิธีการต่างๆได้หรือไม่คุณสามารถทำสิ่งต่อไปนี้
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
methods & something.methods
จะเข้าร่วมในสองอาร์เรย์ทั่วไป / องค์ประกอบการจับคู่ของพวกเขา บางสิ่งบางอย่างวิธีรวมถึงวิธีการทั้งหมดที่คุณกำลังตรวจสอบมันจะเป็นวิธีการที่เท่าเทียมกัน ตัวอย่างเช่น:
[1,2] & [1,2,3,4,5]
==> [1,2]
ดังนั้น
[1,2] & [1,2,3,4,5] == [1,2]
==> true
ในสถานการณ์เช่นนี้คุณต้องการใช้สัญลักษณ์เพราะเมื่อคุณเรียก. วิธีมันจะส่งกลับอาร์เรย์ของสัญลักษณ์และถ้าคุณใช้["my", "methods"]
มันจะส่งกลับเท็จ
klass.instance_methods.include :method_name
หรือ"method_name"
ฉันคิดว่าขึ้นอยู่กับรุ่น Ruby
class Foo
def self.fclass_method
end
def finstance_method
end
end
foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method]
foo_obj.class.instance_methods(false)
=> [:fclass_method]
หวังว่านี่จะช่วยคุณได้!
ในกรณีของฉันทำงานกับทับทิม 2.5.3 ประโยคต่อไปนี้ทำงานได้อย่างสมบูรณ์แบบ:
value = "hello world"
value.methods.include? :upcase
มันจะคืนค่าบูลีนจริงหรือเท็จ
ในขณะที่respond_to?
จะคืนค่าเป็นจริงสำหรับวิธีสาธารณะเท่านั้นการตรวจหา "การกำหนดวิธีการ" ในชั้นเรียนอาจเกี่ยวข้องกับวิธีการส่วนตัว
บน Ruby v2.0 + การตรวจสอบทั้งชุดสาธารณะและส่วนตัวสามารถทำได้ด้วย
Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)