Add existing classes into a module

前端 未结 5 2099
无人及你
无人及你 2020-12-17 02:37

I have some existing ruby classes in a app/classes folder:

class A
   ...
end

class B
   ...
end

I\'d like to group those classes in a mod

相关标签:
5条回答
  • 2020-12-17 02:42

    If you do want to put them in a module I don't see the point of first including them in the global namespace and then aliasing them inside the module. I think what you want to do (although I doubt it is a good thing to do) is something like this:

    file classes/g1.rb

    class A1
      def self.a
        "a1"
      end
    end
    
    class B1
      def self.b
        "b1"
      end
    end
    

    file classes/g2.rb

    class A2
      def self.a
        "a2"
      end
    end
    
    class B2
      def self.b
        "b2"
      end
    end
    

    file imp.rb

    module MyModule
      ["g1.rb", "g2.rb"].each do |file|
        self.class_eval open("classes/#{file}"){ |f| f.read }
      end
    end
    
    puts defined? MyModule
    puts defined? A1
    puts defined? MyModule::A1
    
    puts MyModule::A1.a
    puts MyModule::B2.b
    

    outputs

    constant
    nil
    constant
    a1
    b2
    

    I can think of a few disadvantages of this approach (harder to debug for one thing, and probably a bit slower to load although I am only guessing).

    Why don't you just do something like this:

    Dir["classes/*.rb"].each do |file|
      contents = open(file) { |f| f.read }
      open(file, "w") do |f| 
        f.puts "module MyModule\n"
        contents.each { |line| f.write "  #{line}" }
        f.puts "\nend"
      end
    end
    

    That'll fix your classes to be in your module since in ruby you can reopen a module at any time. Then just include them like you do normally.

    0 讨论(0)
  • 2020-12-17 02:43

    @Squeegy's answer already tells you what to do, but I think it is equally important to understand why that works. And it's actually pretty simple: classes in Ruby are nothing special. They are just objects like any other object that get assigned to variables just like any other variable. More precisely: they are instances of the Class class and they usually get assigned to constants (i.e. variables whose name starts with an uppercase letter).

    So, just like you can alias any other object to multiple variables:

    a = ''
    b = a
    a << 'Hello'
    c = b
    b << ', World!'
    puts c # => Hello, World!
    

    You can also alias classes to multiple variables:

    class Foo; end
    bar = Foo
    p bar.new # => #<Foo:0x1d9f220>
    

    If you want to move the classes into the namespace instead of just aliasing them, you also need to set the original variables to some other object like nil, in addition to @Squeegy's answer:

    ::A = nil
    ::B = nil
    
    0 讨论(0)
  • 2020-12-17 02:47
    module Foo
      A = ::A
      B = ::B
    end
    
    Foo::A.new.bar
    

    Note that the :: prefix on a constant starts searchign the global namespace first. Like a leading / on a pathname. This allows you differentiate the global class A from the modularized constant Foo::A.

    0 讨论(0)
  • 2020-12-17 02:49

    Yes, in your module create the class and have it inherit from your outside classes. For example,

    class A
    ...
    end
    
    module MyModule
     class NewA < A
     end
    end
    

    The class MyModule::NewA will have all the attributes and methods of class A.
    Then again, modules in ruby are never locked, so there is nothing stopping you just writing the class definition straight into the module.

    0 讨论(0)
  • 2020-12-17 03:06

    Use the const_missing hook. If the constant can't be found in the current module, try to resolve in the global namespace:

    class A; end
    class B; end
    
    module M
        def self.const_missing(c)
            Object.const_get(c)
        end
    end
    
    M::A.new
    M::B.new
    
    0 讨论(0)
提交回复
热议问题