Module: Fortitude::MethodOverriding

Defined in:
lib/fortitude/support/method_overriding.rb

Class Method Summary collapse

Class Method Details

.override_methods(target_module, override_methods_module, feature_name, method_names) ⇒ Object

This is Fortitude’s way of maintaining compatibility both with Ruby < 2.0 (no support for Module#prepend) and Ruby 2.0 and later (alias_method_chain is deprecated). Here’s how it works:

  • For a method 'foo' that you want to override using a 'feature name' of bar, you define a method called 'foo_uniwith_bar' – but not in the target module or class (containing the method to be overridden); rather, it must be in a separate Module, and, importantly, not one that you have already Module#include'd into the target module or class. This method has the same signature as the original, except that it also takes, as a first parameter, a #call'able object (typically a Proc or lambda) that represents the original, un-overridden method. You use this, instead of calling 'foo_without_bar' or 'super', in order to invoke the original method.

  • You then call Fortitude::MethodOverriding.override_methods. target_module is the module containing the method you want to override, override_methods_module is the module containing your overriding method ('foo_uniwith_bar'), feature_name is the name of the feature you're using ('bar'), and method_names is an Array of Symbols, each of which is the name of a method you want to override (e.g., 'foo').

This class then performs the appropriate logic to use 'alias_method_chain' or Module#prepend appropriately.

One exception: using Module#prepend seems to cause Fortitude all kinds of problems with JRuby 9.1.5.0 (as of this writing, the latest version of JRuby). In particular, you get things like a java.lang.BootstrapMethodError at “require at org/jruby/RubyKernel.java:956”, and various java.lang.StackOverflowErrors that seem to make no sense at all – and if you use alias_method_chain instead, everything seems to work perfectly. As a result, we currently fall back to using alias_method_chain on JRuby. (You only get deprecation warnings with this when running with Rails 5, which is not yet supported by JRuby anyway, at least as of this writing.)


27
28
29
30
31
32
33
# File 'lib/fortitude/support/method_overriding.rb', line 27

def override_methods(target_module, override_methods_module, feature_name, method_names)
  if RUBY_VERSION =~ /^2\./ && (! ((RUBY_ENGINE || '').to_s.downcase.strip == 'jruby'))
    override_methods_using_prepend(target_module, override_methods_module, feature_name, method_names)
  else
    override_methods_using_alias_method_chain(target_module, override_methods_module, feature_name, method_names)
  end
end