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