Π Ruby Π²ΡΡ β ΠΎΠ±ΡΠ΅ΠΊΡ, Π° ΠΊΠ°ΠΆΠ΄ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ ΠΎΠ±Π»Π°Π΄Π°Π΅Ρ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ΠΌ, ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅ΠΌΡΠΌ Π΅Π³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Π°ΠΌΠΈ. ΠΠΎ ΠΊΠ°ΠΊ ΡΠ·Π½Π°ΡΡ, ΠΊΠ°ΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄ΠΎΡΡΡΠΏΠ½Ρ ΠΎΠ±ΡΠ΅ΠΊΡΡ, ΠΊΠ°ΠΊ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ Π΅Π³ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΠΈ Π΄Π°ΠΆΠ΅ ΠΏΠΎΠ΄ΠΌΠ΅Π½ΠΈΡΡ ΠΈΡ ? Π Π°Π·Π±Π΅ΡΡΠΌ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ ΠΈΠ½ΡΡΠΎΡΠΏΠ΅ΠΊΡΠΈΠΈ Ruby Π½Π° ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΡ ΠΏΡΠΈΠΌΠ΅ΡΠ°Ρ ΠΈΠ· ΠΆΠΈΠ·Π½ΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°.
π§ Π’Π΅ΠΎΡΠΈΡ: Π·Π°ΡΠ΅ΠΌ Π½ΡΠΆΠ½Π° ΠΈΠ½ΡΡΠΎΡΠΏΠ΅ΠΊΡΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ²?
ΠΠ½ΡΡΠΎΡΠΏΠ΅ΠΊΡΠΈΡ (ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΡ) β ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ ΠΈΡΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΡ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΡ ΡΡΡΡΠΊΡΡΡΡ Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ. Π Ruby ΡΡΠΎ ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎ Π²Π°ΠΆΠ½ΠΎ, ΠΏΠΎΡΠΎΠΌΡ ΡΡΠΎ:
- ΠΠ±ΡΠ΅ΠΊΡΡ ΠΌΠΎΠ³ΡΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ ΠΏΠΎΠ»ΡΡΠ°ΡΡ Π½ΠΎΠ²ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ
- ΠΠ»Π°ΡΡΡ ΠΌΠΎΠ³ΡΡ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΡΡ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ βΠ½Π° Π»Π΅ΡΡβ
- ΠΠ΅ΡΠΎΠ΄Ρ ΠΌΠΎΠ³ΡΡ Π±ΡΡΡ ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΌΠΈ, Π·Π°ΡΠΈΡΡΠ½Π½ΡΠΌΠΈ ΠΈΠ»ΠΈ ΠΏΡΠ±Π»ΠΈΡΠ½ΡΠΌΠΈ
Π Π°Π·Π±Π΅ΡΡΠΌ ΠΊΠ»ΡΡΠ΅Π²ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΌΠ΅ΡΠΎΠ΄Π°ΠΌΠΈ.
1οΈβ£ method β ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΌΠ΅ΡΠΎΠ΄ ΠΊΠ°ΠΊ ΠΎΠ±ΡΠ΅ΠΊΡ
user = User.find(1)
save_method = user.method(:save)
# => #<Method: User#save()>
save_method.call # Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΠΎ user.save
ΠΠΈΠ·Π½Π΅Π½Π½ΡΠΉ ΠΏΡΠΈΠΌΠ΅Ρ:
ΠΡ ΠΏΠΈΡΠ΅ΡΠ΅ ΡΠ½ΠΈΠ²Π΅ΡΡΠ°Π»ΡΠ½ΡΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΡΠΎΠ±ΡΡΠΈΠΉ, Π³Π΄Π΅ Π½ΡΠΆΠ½ΠΎ Π²ΡΠ·ΡΠ²Π°ΡΡ ΡΠ°Π·Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ Π²Ρ
ΠΎΠ΄ΡΡΠΈΡ
Π΄Π°Π½Π½ΡΡ
:
def handle_event(object, event_name)
if object.respond_to?(event_name)
object.method(event_name).call
else
# ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΡΡΡΡΡΠ²ΠΈΡ ΠΌΠ΅ΡΠΎΠ΄Π°
end
end
ΠΠ½ΡΠΈΠΏΠ°ΡΡΠ΅ΡΠ½:
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ method Π±Π΅Π· ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ respond_to? β ΡΡΠΎ Π²Π΅ΡΠ½ΡΠΉ ΡΠΏΠΎΡΠΎΠ± ΠΏΠΎΠ»ΡΡΠΈΡΡ NameError.
2οΈβ£ respond_to? β ΠΏΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ Π½Π°Π»ΠΈΡΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Π°
"ΡΡΡΠΎΠΊΠ°".respond_to?(:upcase) # => true
42.respond_to?(:split) # => false
ΠΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΊΠ΅ΠΉΡ:
ΠΡΠΈ ΡΠ°Π±ΠΎΡΠ΅ Ρ API ΠΎΡΠ²Π΅Ρ ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠΈΡ
ΠΎΠ΄ΠΈΡΡ Π² ΡΠ°Π·Π½ΡΡ
ΡΠΎΡΠΌΠ°ΡΠ°Ρ
:
def parse_response(response)
if response.respond_to?(:to_h)
response.to_h
elsif response.respond_to?(:to_json)
JSON.parse(response.to_json)
else
raise "Unsupported response format"
end
end
ΠΠ°ΠΆΠ½ΠΎ:
respond_to? Π½Π΅ Π²ΠΈΠ΄ΠΈΡ ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ. ΠΡΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Π²ΡΠΎΡΠΎΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ:
user.respond_to?(:admin?, true) # ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΡΠΎΠΆΠ΅
3οΈβ£ respond_to_missing? β ΠΌΠ°Π³ΠΈΡ method_missing
ΠΠΎΠ³Π΄Π° Π²ΡΠ·ΡΠ²Π°Π΅ΡΡΡ Π½Π΅ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠΉ ΠΌΠ΅ΡΠΎΠ΄, Ruby ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ method_missing. ΠΠΎ Π΄Π»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ respond_to? Π½ΡΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ ΠΈ respond_to_missing?:
class DynamicAttributes
def method_missing(name, *args)
if name.to_s.start_with?('find_by_')
# ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠΈΡΠΊΠ°
else
super
end
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?('find_by_') || super
end
end
ΠΡΠΈΠΌΠ΅Ρ ΠΈΠ· ΠΆΠΈΠ·Π½ΠΈ:
ORM Π²ΡΠΎΠ΄Π΅ ActiveRecord ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΡΡΠΎ Π΄Π»Ρ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΡ
finderβΠΎΠ²:
User.respond_to?(:find_by_email) # => true, Ρ
ΠΎΡΡ ΠΌΠ΅ΡΠΎΠ΄ ΡΠ²Π½ΠΎ Π½Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ½
4οΈβ£ method_defined? β ΠΏΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π° ΡΡΠΎΠ²Π½Π΅ ΠΊΠ»Π°ΡΡΠ°
User.method_defined?(:save) # => true
User.method_defined?(:new) # => false (ΡΡΠΎ ΠΌΠ΅ΡΠΎΠ΄ ΠΊΠ»Π°ΡΡΠ°)
ΠΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅:
ΠΡΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π° ΠΈΠ»ΠΈ ΠΌΠΎΠ΄ΡΠ»Ρ, ΠΊΠΎΡΠΎΡΡΠΉ Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅Ρ ΠΌΠ΅ΡΠΎΠ΄Ρ ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ ΠΎΠ½ΠΈ Π΅ΡΡ Π½Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Ρ:
module SafeMonkeyPatch
def add_feature
unless method_defined?(:original_method)
alias_method :original_method, :method
# ... Π½Π°ΡΠ° ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ½Π½Π°Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ
end
end
end
ΠΡΡΠΎΡΠΎΠΆΠ½ΠΎ:
method_defined? Π½Π΅ ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΌΠΎΠ΄ΡΠ»Π΅ΠΉ, Π²ΠΊΠ»ΡΡΡΠ½Π½ΡΡ
Π² ΠΊΠ»Π°ΡΡ.
5οΈβ£ instance_methods β Π²ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΠ°
User.instance_methods(false) # ΡΠΎΠ»ΡΠΊΠΎ ΠΌΠ΅ΡΠΎΠ΄Ρ, ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ½Π½ΡΠ΅ Π² User
User.instance_methods(true) # Π²ΠΊΠ»ΡΡΠ°Ρ ΡΠ½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Π½Π½ΡΠ΅
Π Π΅Π°Π»ΡΠ½ΡΠΉ ΠΏΡΠΈΠΌΠ΅Ρ:
ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΠΈΠ»ΠΈ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°:
required_methods = [:save, :validate, :to_json]
missing = required_methods - User.instance_methods(false)
raise "Interface not implemented: #{missing}" unless missing.empty?
Π‘ΠΎΠ²Π΅Ρ:
ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ false ΠΊΠ°ΠΊ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ, ΡΡΠΎΠ±Ρ Π½Π΅ Π·Π°ΡΠΎΡΡΡΡ Π²ΡΠ²ΠΎΠ΄ ΡΠ½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Π½Π½ΡΠΌΠΈ ΠΌΠ΅ΡΠΎΠ΄Π°ΠΌΠΈ.
6οΈβ£ singleton_methods β ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
user = User.new
def user.custom_method; end
user.singleton_methods # => [:custom_method]
ΠΠ΅ΠΉΡ ΠΈΠ· ΠΏΡΠ°ΠΊΡΠΈΠΊΠΈ:
ΠΠ΅ΠΊΠΎΡΠ°ΡΠΎΡΡ ΠΈΠ»ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠ΅ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ:
def decorate_user(user, role)
if role == :admin
def user.admin?; true; end
end
user
end
admin = decorate_user(User.new, :admin)
admin.singleton_methods # => [:admin?]
ΠΠ½ΡΠΈΠΏΠ°ΡΡΠ΅ΡΠ½:
ΠΠ»ΠΎΡΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ ΡΠΈΠ½Π³Π»ΡΠΎΠ½-ΠΌΠ΅ΡΠΎΠ΄Π°ΠΌΠΈ ΡΡΠ»ΠΎΠΆΠ½ΡΠ΅Ρ ΠΎΡΠ»Π°Π΄ΠΊΡ ΠΈ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅.
π§ͺ Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ²
ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π°Π»ΠΈΡΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² Π² ΡΠ΅ΡΡΠ°Ρ :
describe User do
it "implements required interface" do
expect(User.instance_methods).to include(:save, :destroy)
end
it "responds to dynamic finders" do
expect(User.new).to respond_to(:find_by_email)
end
end
π€ Π§ΡΠΎ ΡΠΊΠ°Π·Π°ΡΡ Π½Π° ΡΠΎΠ±Π΅ΡΠ΅Π΄ΠΎΠ²Π°Π½ΠΈΠΈ
β ΠΠ°ΠΊ Π²Ρ ΠΏΡΠΎΠ²Π΅ΡΡΠ΅ΡΠ΅, ΡΡΠΎ ΠΎΠ±ΡΠ΅ΠΊΡ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅Ρ Π½ΡΠΆΠ½ΡΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ?
β Π Ruby Π΅ΡΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΡΠΎΠ²Π½Π΅ΠΉ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ: respond_to? Π΄Π»Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°, method_defined? Π΄Π»Ρ ΠΊΠ»Π°ΡΡΠ°, instance_methods Π΄Π»Ρ ΠΏΠΎΠ»Π½ΠΎΠ³ΠΎ ΡΠΏΠΈΡΠΊΠ°. ΠΠ°ΠΆΠ½ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°ΡΡ ΡΠ°Π·Π»ΠΈΡΠΈΡ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΈΡ
Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°.
π§Ύ ΠΡΠ²ΠΎΠ΄
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅
methodΠΊΠΎΠ³Π΄Π° Π½ΡΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠΌ ΠΊΠ°ΠΊ Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠΌ respond_to?β Π²Π°ΡΠ° ΠΏΠ΅ΡΠ²Π°Ρ Π»ΠΈΠ½ΠΈΡ Π·Π°ΡΠΈΡΡ ΠΎΡ NoMethodError- ΠΠ»Ρ method_missing Π²ΡΠ΅Π³Π΄Π° ΡΠ΅Π°Π»ΠΈΠ·ΡΠΉΡΠ΅
respond_to_missing? method_defined?ΠΈinstance_methodsΡΠ°Π±ΠΎΡΠ°ΡΡ Π½Π° ΡΡΠΎΠ²Π½Π΅ ΠΊΠ»Π°ΡΡΠΎΠ²singleton_methodsΠΏΠΎΠΊΠ°ΠΆΡΡ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΠ°
ΠΠ½ΡΡΠΎΡΠΏΠ΅ΠΊΡΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² β ΡΡΠΎ ΠΊΠ°ΠΊ ΡΠ΅Π½ΡΠ³Π΅Π½ Π΄Π»Ρ Π²Π°ΡΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ²: ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π·Π°Π³Π»ΡΠ½ΡΡΡ Π²Π½ΡΡΡΡ ΠΈ ΠΏΠΎΠ½ΡΡΡ ΠΈΡ ΡΡΡΡΠΊΡΡΡΡ, Π½Π΅ ΡΠ°Π·Π±ΠΈΡΠ°Ρ Π½Π° ΡΠ°ΡΡΠΈ.