Module: JrubyScala::CoreExt::Module::Traits

Included in:
Module
Defined in:
lib/jruby_scala/core_ext/module/traits.rb

Overview

Enables the inclusion of Scala traits into Ruby modules.

TODO: Currently, JRuby throws an exception when attempting to load many of the top-level traits: List, Iterator, Equiv, Ordered, etc. Oddly enough, scala.FunctionN works fine. We need to investigate why this happens.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



15
16
17
18
19
20
# File 'lib/jruby_scala/core_ext/module/traits.rb', line 15

def self.included(base)
  base.module_eval do
    alias_method :include_without_scala_trait_support, :include
    alias_method :include, :include_with_scala_trait_support
  end
end

Instance Method Details

#include_with_scala_trait_support(*modules) ⇒ Object

Mixes the given modules into the current module, including Scala Traits.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/jruby_scala/core_ext/module/traits.rb', line 24

def include_with_scala_trait_support(*modules)
  modules.each do |m|
    if m.respond_to?(:java_class) and m.java_class.interface?
      loader = m.java_class.class_loader
      unless loader.nil?
        mixin_methods_from_trait(loader.load_class(m.java_class.to_s), loader)
        unless self < JrubyScala::CoreExt::OperatorTranslations
          include_without_scala_trait_support(JrubyScala::CoreExt::OperatorTranslations)
        end
      end
    end

    if defined?(@@trait_methods)
      define_method(:scala_reflective_trait_methods) {@@trait_methods}
    end

    include_without_scala_trait_support(m)
  end
end

#mixin_methods_from_trait(trait_class, loader, done = Set.new) ⇒ Object

Mixes the methods from a Scala trait into the module.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/jruby_scala/core_ext/module/traits.rb', line 50

def mixin_methods_from_trait(trait_class, loader, done = Set.new)
  return if done.include?(trait_class)
  done << trait_class

  begin
    klass = loader.load_class("#{trait_class.name}$class")
  rescue java.lang.ClassNotFoundException
    # Unable to load the <TraitName>$class, probably because this is
    # a standard Java interface, not a Scala trait, so just return.
    return
  end

  # TODO: Should this happen before attempting to load the special
  # <TraitName>$class?
  trait_class.interfaces.each do |iface| 
    mixin_methods_from_trait(iface, loader, done)
  end

  klass.declared_methods.each do |meth|
    mods = meth.modifiers
    
    if java.lang.reflect.Modifier.static?(mods) and java.lang.reflect.Modifier.public?(mods)
      @@trait_methods ||= []

      unless meth.name.include?('$')
        module_eval "          def \#{meth.name}(*args, &block)\n            args.insert(0, self)\n            args << block unless block.nil?\n            args.map! {|a| defined?(a.java_object) ? a.java_object : a}\n            scala_reflective_trait_methods[\#{@@trait_methods.size}].invoke(nil, args.to_java)\n          end\n        CODE\n\n        @@trait_methods << meth\n      else\n        # Method name contains special characters, so use a fallback\n        # implementation with define_method.\n        #\n        # Caveat: This impl can't deal with methods with function\n        # arguments (blocks)\n        define_method(meth.name) do |*args|\n          args.insert(0, self)\n          meth.invoke(nil, args.to_java)\n        end\n      end\n    end\n  end\nend\n"