Ruby 객체에 대한 호출 방법의 이점
10529 단어 rubyprogramming
공동 작업을 용이하게 하기 위해 Ruby의 개체 모델 활용
일상적인 Ruby 코딩에서 사용하는 일반적인 패턴 중 하나는 모듈 또는 레벨
call
메서드를 정의하는 것입니다. 저는 이러한call
방법을 서로 다른 관심사 사이의 선명한 인터페이스로 설정하고 싶습니다.호출에 응답하는 개체를 사용한 종속성 주입
다음 예제에서는
deliver!
메서드가 있는 "패키지"클래스를 구성했습니다. 한 번 보자:module Handler
def self.call(package:)
# Complicated logic
end
end
module Notifier
def self.call(package:)
# Complicated logic
end
end
class Package
def initialize(origin:, destination:, notifier: Notifier, handler: Handler)
@origin = origin
@destination = destination
@handler = handler
@notifier = notifier
end
attr_reader :origin, :destination, :handler, :notifier
def deliver!(with_notification: true)
notifier.call(package: self) if with_notification
handler.call(package: self)
end
end
deliver!
메서드를 테스트하려면 몇 가지 시나리오를 고려해야 합니다.그리고
Notifier.call
와 Handler.call
모두 테스트에서 실행하는 데 비용이 많이 든다고 가정해 보겠습니다. 스터빙이나 조롱 없이 다음 테스트를 작성할 수 있습니다.def test_assert_not_sending_notification
# By having the notifier `raise`, we'll know if it was called.
notifier = ->(package:) { raise }
handler = ->(package:) { :handled }
package = Package.new(
origin: :here,
destination: :there,
notifier: notifier,
handler: handle
)
assert(package.deliver!(with_notification: false) == :handled)
end
협업 개체의 메서드를 Lambda로 사용하는 종속성 주입
이제 내려갈 수 있는 몇 가지 흥미로운 경로가 있습니다. 첫째,
.call
메서드 명명 규칙이 정말 마음에 들지 않으면 어떻게 할까요?module PlanetExpress
def self.deliver(package:)
# Navigates multiple hurdles to renew delivery licenses
end
end
PlanetExpress.deliver
라는 별칭을 만들 수 있지만 약간의 Ruby 마법을 사용할 수도 있습니다.Package.new(
origin: :here,
destination: :there,
handler: PlanetExpress.method(:deliver)
)
Object.method
메소드는 call
에 응답하는 메소드 객체를 반환합니다. 이를 통해 call
기반 인터페이스의 유연성을 계속 즐기면서 PlanetExpress 모듈을 수정하지 않아도 됩니다.ActiveRecord와의 인터페이스에 대해 생각할 때 이것은 아마도 훨씬 더 관련이 있습니다. 기록을 찾아서 처리하고 싶은 경우가 있나요? 어쩌면 그 기록을 만드는 데 비용이 많이 들 수도 있습니다. 그것을 단락시키자.
class User < ActiveRecord::Base
end
# An async worker that must receive an ID, not the full object.
class CongratulatorWorker
def initialize(user_id:, user_finder: User.method(:find))
@user = user_finder.call(user_id)
end
def send_congratulations!
# All kinds of weird things with lots of conditionals
end
end
위와 같이 이제 테스트에서 다음을 설정할 수 있습니다.
def test_send_congratulations!
user = User.new(email: "[email protected]")
finder = ->(user_id) { user }
worker = CongratulatorWorker.new(user_id: "1", user_finder: finder)
worker.send_congratulations!
end
위의 시나리오에서 User 클래스에 선언된
User.call
메서드를 보면 머리가 긁힐 것입니다. 그러나 CongratulatorWorker
에서 나는 무슨 일이 일어나고 있는지 추론할 기회를 좀 더 가질 것입니다.메서드 개체를 블록으로 사용
이 예제는 다른 방향으로 진행되지만
call
메서드를 갖는 규칙의 유용성을 강조합니다.module ShoutOut
def self.say_it(name)
puts "#{name} is here"
end
end
["huey", "duey", "louie"].each(&ShoutOut.method(:say_it))
나는
call
에 ShoutOut
를 정의하고 그것을 블록으로 사용할 수 있기를 바랐습니다(예: .each(&ShoutOut)
). 그러나 그것은 효과가 없었습니다.결론
이러한 정도의 역동성은 제가 Ruby에 대해 좋아하는 한 가지 측면입니다. 그리고 그것은 Ruby에만 국한된 것이 아닙니다. 나는 Emacs-Lisp에서 이것을 한다.
Ruby를 배우는 초기에 나는 Ruby에 대해 알려주는 몇 가지 문장을 우연히 발견했습니다.
그리고 객체에 대한 메서드도 그 자체로 객체입니다. 좋은 점은 이러한 물체에 모양과 형태가 있다는 것입니다. 메서드를 "분리"하고 전달하는 것을 볼 수 있습니다.
Reference
이 문제에 관하여(Ruby 객체에 대한 호출 방법의 이점), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/devteam/benefits-of-having-a-call-method-for-your-ruby-object-30dk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)