module Persistent💎::JRubyWorkaround
Constants
- BROKEN_ENCODING
- BROKEN_ENCODING_JRUBY_1_7
Public Class Methods
# File lib/persistent_dmnd/jruby_workaround.rb, line 42 def self.included(klass) # Make methods on this module also available inside classes (e.g. not just in instances) klass.extend(self) end
Public Instance Methods
Workaround JRuby encoding bug See github.com/jruby/jruby/issues/4878 and gitlab.com/ivoanjo/persistent-dmnd/issues/5
The trick here is that on JRuby, methods with emojis in the name are defined, but the resulting name is mangled so instead of for instance to_💎 the result is to_?x00. (Or #💎ify will become #?ifyx00.) This behavior is consistent between def and calling a method, so def will register a method to_?x00, and a normal method call will do the same mangling and thus look for a method WITH the mangled name.
But there are still other places in the code that rely on the correct name, such as alias and public_send/send, so we additionally use this module to define the correct name as an alias for the broken name.
Thus, it all works on JRuby, albeit in a very roundabout way!
FOR JRUBY 1.7: On JRuby 1.7 it seems that the mangling is different, and the emoji just gets replaced with ?, so for instance to_💎 becomes to_?. But then, to make things interesting, on symbols created without quotes, it gets mangled with the BROKEN_ENCODING_JRUBY_1_7
, e.g :to_💎 becomes :to_BROKEN_ENCODING_JRUBY_1_7 (but :“to_💎” is still correct). To support both of these, we add an extra alias on JRuby, so that everything else seems to work even if it is actually using the name with the mangled encoding.
# File lib/persistent_dmnd/jruby_workaround.rb, line 81 def maybe_fix_broken_encoding(name, target = nil) name_string = name.to_s if JRUBY_VERSION.start_with?('1.7.') unless name_string.match(/\?.+/) || ['a?', 'h?', 's?', 'each?'].include?(name_string) || ['_?', '_a?', '_h?', '_s?'].any? { |suffix| name_string.end_with?(suffix) } return end else return unless name_string.end_with?(BROKEN_ENCODING) end fixed_name = name_string.sub('?', '💎').delete(BROKEN_ENCODING).to_sym fixed_name_jruby_1_7 = name_string.sub('?', BROKEN_ENCODING_JRUBY_1_7).to_sym if target target.instance_eval { alias_method(fixed_name, name) } target.instance_eval { alias_method(fixed_name_jruby_1_7, name) } if JRUBY_VERSION.start_with?('1.7.') else alias_method(fixed_name, name) alias_method(fixed_name_jruby_1_7, name) if JRUBY_VERSION.start_with?('1.7.') end end
# File lib/persistent_dmnd/jruby_workaround.rb, line 47 def method_added(name) super maybe_fix_broken_encoding(name) end
# File lib/persistent_dmnd/jruby_workaround.rb, line 52 def singleton_method_added(name) super maybe_fix_broken_encoding(name, self.singleton_class) end