Ruby on Rails 로케일 파일에서 YAML 부울 값 처리 이해하기

Localization in Ruby on Rails: Yes/No, On/Off

작성자
HackerNews
발행일
2025년 10월 15일

핵심 요약

  • 1 Ruby on Rails는 `psych` 젬을 통해 YAML 로케일 파일을 로드하며, 이 과정에서 'yes', 'no', 'on', 'off'와 같은 문자열이 Ruby의 `TrueClass` 또는 `FalseClass`로 자동 변환됩니다.
  • 2 이러한 자동 변환은 `psych`가 YAML 1.1 사양을 따르기 때문에 발생하며, YAML 1.1은 해당 문자열들을 표준 부울 리터럴로 정의합니다.
  • 3 흥미롭게도 `psych`는 YAML 1.1에서 부울로 정의된 'Y', 'y', 'N', 'n' 문자열은 부울로 변환하지 않고 리터럴 문자열로 유지하며, 이는 과거 `syck` 파서의 동작과 유사합니다.

도입

Ruby on Rails 애플리케이션에서 로케일(locale) 관리는 `i18n` 젬을 통해 이루어지며, 이 젬은 YAML 파일을 파싱하기 위해 `psych` 젬(또는 `yaml` 별칭)을 활용합니다. 이 과정에서 개발자들이 예상치 못한 데이터 타입 변환이 발생할 수 있습니다. 특히 `en.yml`과 같은 로케일 파일에 'yes', 'no', 'on', 'off'와 같은 문자열 값이 포함될 경우, Ruby로 로드될 때 `TrueClass` 또는 `FalseClass`로 자동 변환되는 현상이 관찰됩니다. 본 문서는 이러한 현상의 원인과 `psych` 젬의 YAML 파싱 방식에 대해 심층적으로 분석합니다.

Rails 로케일 파일의 부울 변환 현상

Rails 콘솔에서 I18n.locale = :en 설정 후 I18n.backend.send(:translations)[:en][:terms]를 호출하면, YAML 파일에 yes: Yes, no: No, switch_on: On, switch_off: Off와 같이 정의된 값들이 Ruby에서 TrueClassFalseClass로 변환되는 것을 확인할 수 있습니다. 이는 단순히 문자열로 예상했던 값들이 내부적으로 부울 값으로 처리되어 예상치 못한 동작을 유발할 수 있음을 의미합니다.

psych 젬의 YAML 파싱 규칙

psych 젬은 YAML 1.1 사양을 구현하고 있으며, 이 사양에 따라 특정 문자열을 부울 값으로 해석합니다. 다음은 psych의 테스트를 통해 확인된 부울 변환 예시입니다.

true로 변환되는 값

  • Psych.safe_load("--- YES") -> true

  • Psych.safe_load("--- Yes") -> true

  • Psych.safe_load("--- yes") -> true

  • Psych.safe_load("--- TRUE") -> true

  • Psych.safe_load("--- True") -> true

  • Psych.safe_load("--- true") -> true

  • Psych.safe_load("--- ON") -> true

  • Psych.safe_load("--- on") -> true

  • Psych.safe_load("--- On") -> true

false로 변환되는 값

  • Psych.safe_load("--- NO") -> false

  • Psych.safe_load("--- No") -> false

  • Psych.safe_load("--- no") -> false

  • Psych.safe_load("--- FALSE") -> false

  • Psych.safe_load("--- False") -> false

  • Psych.safe_load("--- false") -> false

  • Psych.safe_load("--- OFF") -> false

  • Psych.safe_load("--- Off") -> false

  • Psych.safe_load("--- off") -> false

이러한 현상은 YAML 1.1 사양에서 ‘yes’, ‘no’, ‘on’, ‘off’ (대소문자 구분 없음)를 부울 리터럴로 정의하고 있기 때문입니다. psych는 이 사양을 충실히 따르고 있습니다.

‘Y’, ‘y’, ‘N’, ‘n’의 예외 처리

YAML 1.1 사양은 ‘Y’, ‘y’, ‘N’, ‘n’ 또한 부울 값으로 정의할 수 있음을 시사하지만, psych는 이들을 부울로 변환하지 않고 리터럴 문자열로 취급합니다.

  • Psych.safe_load("--- Y") -> "Y"

  • Psych.safe_load("--- y") -> "y"

  • Psych.safe_load("--- N") -> "N"

  • Psych.safe_load("--- n") -> "n"

이는 psych 젬의 테스트 스위트에서도 명확히 문서화되어 있습니다. 이러한 동작은 과거 Ruby 1.9부터 사용되던 C로 작성된 YAML 파서인 syck의 영향으로 보입니다. syck는 YAML 1.0 사양을 따랐으며, ‘y’, ‘Y’, ‘n’, ‘N’을 리터럴 문자열로 처리하도록 구현되어 있었습니다. 비록 YAML 1.0 사양에서 부울 정의에 대한 정확한 명세는 찾기 어렵지만, syck가 이러한 방식을 채택하면서 Ruby의 YAML 파서들이 일관된 동작을 유지하게 된 것으로 추정됩니다.

결론

Ruby on Rails에서 로케일 파일을 로드할 때 `psych` 젬의 YAML 파싱 방식에 대한 이해는 매우 중요합니다. 'yes', 'no', 'on', 'off'와 같은 일반적인 문자열이 YAML 1.1 사양에 따라 자동으로 부울 값으로 변환되는 것은 의도치 않은 버그를 유발할 수 있습니다. 반면 'Y', 'y', 'N', 'n'은 부울로 변환되지 않고 문자열로 유지되는 점도 인지해야 합니다. 개발자는 이러한 `psych`의 동작을 명확히 이해하고, 로케일 파일 작성 시 데이터 타입 변환을 고려하여 문자열을 명시적으로 따옴표로 묶는 등 적절한 YAML 문법을 사용하여 예상치 못한 타입 변환을 방지해야 합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!