How can I choose which version of a module to include dynamically in Ruby?

前端 未结 3 1915
没有蜡笔的小新
没有蜡笔的小新 2021-02-20 07:20

I\'m writing a small Ruby command-line application that uses fileutils from the standard library for file operations. Depending on how the user invokes the applicat

相关标签:
3条回答
  • 2021-02-20 07:48

    So what if it's private?

    class Worker
      def initialize(verbose=false)
        if verbose
          (class <<self; include FileUtils::Verbose; end)
        else
          (class <<self; include FileUtils; end)
        end
        touch "test"
      end
    end
    

    This includes FileUtils::something in particular's Worker's metaclass - not in the main Worker class. Different workers can use different FileUtils this way.

    0 讨论(0)
  • 2021-02-20 07:53

    If you would like to avoid the "switch" and inject the module, the

    def initialize(injected_module)
        class << self
            include injected_module
        end
    end
    

    syntax won't work (the injected_module variable is out of scope). You could use the self.class.send trick, but per object instance extending seems more reasonable to me, not only because it is shorter to write:

    def initialize(injected_module = MyDefaultModule)
        extend injected_module
    end
    

    but also it minimizes the side effects - the shared and easily changable state of the class, which can result in an unexpected behavior in a larger project. In Ruby the is no real "privacy" so to say, but some methods are marked private not without a reason.

    0 讨论(0)
  • 2021-02-20 08:08

    Conditionally including the module through the send methods works for me as in the below tested example:

    class Artefact
      include HPALMGenericApi
      # the initializer just sets the server name we will be using ans also the 'transport' method : Rest or OTA (set in the opt parameter)
      def initialize server, opt = {}  
        # conditionally include the Rest or OTA module
        self.class.send(:include, HPALMApiRest) if (opt.empty? || (opt && opt[:using] opt[:using] == :Rest)) 
        self.class.send(:include, HPALMApiOTA) if (opt && opt[:using] opt[:using] == :OTA)    
        # ... rest of initialization code  
      end
    end
    
    0 讨论(0)
提交回复
热议问题