module VirtDisk # Utility module used by VirtDisk plug-ins, allowing them to export methods upstream. # # Typically, VirtDisk plug-ins are linked in a chain - each plug-in communicating with # the plug-in immediately upstream from it (where upstream is closer to the source of the data). # The last downstream plug-in (the volume head) is the object accessed directly by the client. # # This module enables upstream plug-ins to export methods, so they can be called directly # from the volume head. # # @note Every plug-in class must include this module, even if they don't export any methods. module ExportMethods module ClassMethods # Export one or more methods, making them callable from the volume head. # # @param syms [Symbol] the names of one or more methods to be exported. # @raise [RuntimeError] if any of the methods aren't defined in the class. def export(*syms) syms.each do |s| sym = s.to_sym raise "Method not defined in class: #{sym}" unless method_defined?(sym) return nil if exports.include?(sym) exports << sym end nil end # @return [Array<Symbol>] array of exported methods. def exports @__exported_methods ||= [] end # @param sym [Symbol] # @return [Boolean] - true if sym is exported by this class, false otherwise. def exported?(sym) exports.include?(sym.to_sym) end end def self.included(host_class) host_class.extend(ClassMethods) end # Set the module immediately upstream from this one. # # @param obj [Object] the upstream module. def delegate=(obj) @__delegate = obj end # The module immediately upstream from this one. # # @return [Object] the module immediately upstream from this one. def delegate @__delegate end # @param sym [Symbol] # @return [Boolean] - true if sym is exported by this module's class, false otherwise. def exported?(sym) self.class.exported?(sym) end def respond_to_missing?(sym, include_all = false) return false unless @__delegate @__delegate.exported?(sym) || @__delegate.send(:respond_to_missing?, sym, include_all) end def method_missing(sym, *args) super unless respond_to_missing?(sym) @__delegate.send(sym, *args) end end end