user419017
user419017

Reputation:

Ruby inheritance and advised approach?

What I want is a single API which determines the class to delegate methods to based on a parameter passed through initializer. Here is a basic example:

module MyApp
  class Uploader
    def initialize(id)
      # stuck here
      # extend, etc. "include Uploader#{id}"
    end
  end
end

# elsewhere
module MyApp
  class UploaderGoogle
    def upload(file)
      # provider-specific uploader
    end
  end
end

My desired outcome:

MyApp::Uploader('Google').upload(file)
# calls MyApp::UploaderGoogle.upload method

Please be aware the above is for demonstration purposes only. I will actually be passing an object which contains an attribute with the uploader id. Is there a better way to handle this?

Upvotes: 0

Views: 41

Answers (2)

mrcasals
mrcasals

Reputation: 1171

Haven't tested it, but if you want to include a module:

module MyApp
  class Uploader
    def initialize(id)
      mod = ("Uploader"+id).constantize
      self.send(:include, mod)
    end
  end
end

If you want to extend your class with a module:

module MyApp
  class Uploader
    def initialize(id)
      mod = ("Uploader"+id).constantize
      self.class.send(:extend, mod)
    end
  end
end

Upvotes: 1

jxpx777
jxpx777

Reputation: 3641

Sounds like you want a simple subclass. UploaderGoogle < Uploader Uploader defines the basic interface and then the subclasses define the provider specific methods, calling super as necessary to perform the upload. Untested code OTTOMH below…

module MyApp
    class Uploader
        def initialize(id)
            @id = id
        end

        def upload
            #perform upload operation based on configuration of self. Destination, filename, whatever
        end
    end

    class GoogleUploader < Uploader
        def initialize(id)
            super
            #google-specific stuff
        end

        def upload
            #final configuration/preparation
            super
        end
    end
end

Something along those lines. To base this on a passed parameter, I'd use a case statement.

klass = case paramObject.identifierString
    when 'Google'
        MyApp::GoogleUploader
    else
        MyApp::Uploader
    end

Two things: If you do this in several places, probably extract it into a method. Second, if you're getting the input from the user, you've got a lot of anti-injection work to do as well if you, for instance, create a class name directly from a provided string.

Upvotes: 1

Related Questions