Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

엉망으로 만들지 않고 원숭이 패치하는 3가지 방법

원숭이 패치. Ruby를 처음 사용하면 놀랍습니다. 핵심 클래스에 바로 메서드를 추가할 수 있습니다! Time.now.advance(days: -1)를 호출할 필요가 없습니다. , 1.day.ago를 작성할 수 있습니다. ! 이것은 Ruby가 읽고 쓰는 것을 즐겁게 만듭니다. 까지...

패치가 Hash를 변경했기 때문에 이상한 버그가 발생했습니다. .

어떤 코드가 실제로 실행되었는지 혼란스러워서 중단되면 디버그할 수 없습니다.

그리고 마침내 모든 문제가 6개월 전에 Enumerable에 원숭이 패치를 적용했을 때 발생했다는 것을 알게 됩니다. 한 줄의 코드를 다섯 글자로 줄이려면.

그러나 대안은 무엇입니까? 전혀 편리하지 않습니까? GroupableArray.new([1, 2, 3, 4]).in_groups_of(2)와 같은 코드 ? blank?를 기다리고 있습니까? 좋은 사용자 입력 처리가 허용되기 전에 핵심 Ruby로 만들려면?

원숭이 패치를 완전히 포기하고 싶지는 않습니다. 하지만 하지 않는 원숭이 패치를 어떻게 작성할 수 있습니까? 다음에 그들을 볼 때 무능하다고 자책하고 싶습니까?

모듈에 넣기

클래스를 원숭이 패치할 때 클래스를 다시 열고 패치를 밀어넣지 마십시오.

class DateTime
  def weekday?
    !sunday? && !saturday?
  end
end

왜 안되나요?

  • 두 라이브러리가 같은 방법으로 원숭이 패치를 적용하면 구분할 수 없습니다.

    첫 번째 원숭이 패치는 덮어쓰여지고 영원히 사라집니다.

  • 오류가 있으면 DateTime 내에 오류가 발생한 것처럼 보입니다. .

    기술적으로 사실이지만 그다지 도움이 되지는 않습니다.

  • 원숭이 패치를 끄기가 더 어렵습니다.

    전체 패치를 주석 처리하거나 원숭이 패치 파일 없이 코드를 실행하려는 경우 원숭이 패치 파일 요구를 건너뛰어야 합니다.

  • 예를 들어 require 'date'를 잊어버린 경우 이 원숭이 패치를 실행하기 전에 실수로 재정의하게 됩니다. DateTime 패치하는 대신

대신, 원숭이 패치를 모듈에 넣으십시오:

module CoreExtensions
  module DateTime
    module BusinessDays
      def weekday?
        !sunday? && !saturday?
      end
    end
  end
end

이런 식으로 관련 원숭이 패치를 함께 구성할 수 있습니다. 오류가 발생하면 문제 코드가 어디에서 왔는지 정확히 알 수 있습니다. 그리고 한 번에 한 그룹씩 포함할 수 있습니다.

# Actually monkey-patch DateTime
DateTime.include CoreExtensions::DateTime::BusinessDays

더 이상 패치를 원하지 않으면 해당 줄을 주석 처리하십시오.

함께 유지

핵심 클래스를 원숭이 패치할 때 핵심 Ruby API에 추가합니다. 핵심 패치가 있는 모든 앱은 약간씩 다릅니다. 따라서 새 코드베이스로 이동할 때 이러한 변경 사항을 빠르게 배울 수 있는 방법이 있어야 합니다. 원숭이 패치가 어디에 살고 있는지 알아야 합니다.

저는 주로 Rails의 원숭이 패치 규칙을 따릅니다. 패치는 lib/core_extensions/class_name/group.rb로 이동합니다. . 그래서 이번 패치:

module CoreExtensions
  module DateTime
    module BusinessDays
      def weekday?
        !sunday? && !saturday?
      end
    end
  end
end

lib/core_extensions/date_time/business_days.rb로 이동합니다. .

새로운 개발자는 lib/core_extensions에서 Ruby 파일을 탐색할 수 있습니다. Ruby에 추가한 내용을 알아보세요. 그리고 그들은 실제로 사용할 것입니다. 방해만 되는 방법 대신에 당신이 작성한 편리한 새로운 방법.

최소한의 경우를 생각해 보세요

Enumerable인지 모르겠습니다. sum이 없습니다. 방법. 너무 자주 [1, 2, 3].sum을 작성할 수 있기를 바랍니다. 또는 ["a", "b", "c"].sum 또는 [Article.new, Article.new, Article.new].sum ... 아.

원숭이 패치 수업을 할 때 일반적으로 쉽게 만들고 싶은 한 가지에 대해 생각합니다. 숫자의 합을 계산하고 싶지만 배열이 다른 것을 저장할 수 있다는 사실을 잊어버리세요.

지금은 이해가 됩니다. 당신은 해시 묶음의 평균을 계산하지 마십시오. 하지만 가끔 호출할 때 그냥 실패하는 메서드를 객체에 첨부하면 나중에 혼란스러울 것입니다.

몇 가지 방법으로 이 문제를 해결할 수 있습니다. 최고에서 최악으로:

  • 예기치 않은 입력을 합리적으로 처리합니다.

    패치가 문자열과 함께 작동하는 경우 잘 작동합니다. to_s를 호출하면 거의 모든 것에서 합리적인 것을 얻을 수 있습니다. 그것에 먼저. 그리고 Confident Ruby는 다양한 종류의 입력을 처리하는 수많은 방법을 알려줄 것입니다.

  • 오류를 보다 명확하게 처리합니다.

    이것은 ArgumentError를 던지는 것만큼 쉬울 수 있습니다. 예상하지 못한 입력을 볼 때 좋은 메시지와 함께. 임의의 NoMethodError를 이해하는 다른 사람에게 의존하지 마십시오. s.

  • 댓글에서 기대하는 입력 유형을 문서화합니다.

    다른 두 옵션을 사용할 수 있다면 더 좋습니다. 그러나 패치 내에서 엣지 케이스를 확인할 수 없다면 최소한 문서화하십시오. 그렇게 하면 발신자가 문제의 원인이 패치라는 것을 알게 되면 귀하가 무엇을 하려고 했는지 알 수 있습니다.

내가 가장 좋아하는 원숭이 패치

마지막으로 제가 가장 좋아하는 원숭이 패치를 여러분께 남기고 싶습니다:Hash#string_merge :

lib/core_extensions/hash/merging.rb
module CoreExtensions
  module Hash
    module Merging
      def string_merge(other_hash, separator = " ")
        merge(other_hash) {|key, old, new| old.to_s + separator + new.to_s}
      end
    end
  end
end

{}.string_merge({:class => "btn"}) # => {:class=>"btn"}

h = {:class => "btn"} # => {:class=>"btn"}
h.string_merge({:class => "btn-primary"}) # => {:class=>"btn btn-primary"}

CSS 클래스를 HTML 요소에 첨부하도록 합니다. 그래서 훨씬 좋습니다.

감각적인 원숭이 패치

원숭이 패치 핵심 클래스가 모두 나쁜 것은 아닙니다. 잘하면 코드가 Ruby처럼 느껴집니다. 하지만 Ruby의 날카로운 모서리와 마찬가지로 사용 시 각별한 주의가 필요합니다.

패치를 함께 유지하고, 모듈로 그룹화하고, 예상치 못한 것을 처리하면 원숭이 패치가 최대한 안전할 것입니다.

최고의 원숭이 패치는 무엇인가요? 당신이 가지고 있는 쓴 (또는 본) 적이 있습니까? 댓글을 남겨서 알려주세요!