简体   繁体   中英

Ruby: mixins, inheritance and constants name resolution

My program has following structure:

module M1
    class A
        def action
            C.new.foo
        end
    end

    class C
        def foo
            puts "M1::C foo"
        end
    end
end


module M2
    class A
        def action
            C.new.foo
        end
    end

    class C
        def foo
            puts "M2::C foo"
        end
    end
end

As both M1::A and M2::A share same code, I've been thinking of putting common code inside separate class (or module) and inherit from it (include it). Something like this:

class ABase
    def action
        C.new.foo
    end
end

module M1
    class A < ABase
    end

    class C
        def foo
            puts "M1::C foo"
        end
    end
end


module M2
    class A < ABase
    end

    class C
        def foo
            puts "M2::C foo"
        end
    end
end

However, when I tried, I've got into trouble with name resolution uninitialized constant ABase::C . What is the proper way to achieve code sharing in this case?

Due to the way constants are resolved based on definition scope and not in inherited scopes you'll need to bridge that with a method call:

class ABase
  def action
    # Within this scope only constants defined in `ABase` are resolved.
    # As ABase::C and ::C (root-level) don't exist, C can't be resolved.
    # However, a method `c` defined in a subclass will be.
    c.new.foo
  end
end

module M1
  class A < ABase
    def c
      C
    end
  end

  class C
    def foo
      puts "M1::C foo"
    end
  end
end

module M2
  class A < ABase
    # This resolves C as either M2::A::C, M2::ABase::C, M2::C or ::C,
    # whichever it finds first.
    def c
      C
    end
  end

  class C
    def foo
      puts "M2::C foo"
    end
  end
end

Then you get the expected results:

M1::A.new.action
# => M1::C foo
M2::A.new.action
# => M2::C foo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM