从gem继承一个类并添加本地方法

时间:2016-01-13 12:58:25

标签: ruby-on-rails ruby

我使用gem来管理gmail api集成的某些属性,并且我对它的工作方式非常满意。

我想添加一些本地方法来处理该gem中使用的Gmail :: Message类。

即。我想做这样的事情。

models/GmailMessage.rb
  class GmailMessage < Gmail::Message

    def initialize(gmail)
      #create a Gmail::Message instance as a GmailMessage instance 
      self = gmail
    end

    def something_clever
      #do something clever utilising the Gmail::Message methods
    end
  end

我不想坚持下去。但显然我无法以这种方式定义自我。

为了澄清,我想采用Gmail :: Message的实例并创建一个GmailMessage实例,该实例是该其他消息的直接副本。

然后我可以运行@ gmail.subject和@ gmail.html之类的方法,还可以运行@ gmail.something_clever ...并在必要时保存本地属性。

我完全疯了吗?

5 个答案:

答案 0 :(得分:2)

您可以使用mixin的概念,其中您在另一个类中包含Module,以通过其他功能对其进行增强。

以下是如何做到这一点。为了创建一个完整的工作示例,我创建了类似于代码库中的模块。

# Assumed to be present in 3rd party gem, dummy implementation used for demonstration
module Gmail
    class Message
        def initialize
            @some_var = "there"
        end
        def subject
            "Hi"
        end
    end
end

# Your code
module GmailMessage
    # You can code this method assuming as if it is an instance method
    # of Gmail::Message. Once we include this module in that class, it
    # will be able to call instance methods and access instance variables.
    def something_clever
        puts "Subject is #{subject} and @some_var = #{@some_var}"
    end
end

# Enhance 3rd party class with your code by including your module
Gmail::Message.include(GmailMessage)

# Below gmail object will actually be obtained by reading the user inbox
# Lets create it explicitly for demonstration purposes.
gmail = Gmail::Message.new

# Method can access methods and instance variables of gmail object
p gmail.something_clever  
#=> Subject is Hi and @some_var = there

# You can call the methods of original class as well on same object
p gmail.subject
#=> "Hi"

答案 1 :(得分:1)

以下应该工作:

class GmailMessage < Gmail::Message

  def initialize(extra)
    super
    # some additional stuff
    @extra = extra
  end

  def something_clever
    #do something clever utilising the Gmail::Message methods
  end

end

GmailMessage.new # => will call first the initializer of Gmail::Message class..

答案 2 :(得分:1)

我不确定为什么你不能只有一个简单的包装类...

class GmailMessage

  def initialize(message)
    @message = message
  end

  def something_clever
    # do something clever here
  end

  def method_missing(m, *args, &block)  
    if @message.class.instance_methods.include?(m)
      @message.send(m, *args, &block)
    else
      super
    end  
  end 
end

然后你可以......

  @my_message = GmailMessage.new(@original_message)

@my_message将正确响应@original_message支持的所有方法,您可以将自己的方法添加到类中。

编辑 - 感谢@ jeeper在评论中的观察

答案 3 :(得分:1)

根据其他海报所说的内容,您可以在ruby中使用内置类SimpleDelegator来包装现有消息:

require 'delegate'

class MyMessage < SimpleDelegator
  def my_clever_method
    some_method_on_the_original_message + "woohoo"
  end
end

class OriginalMessage
  def some_method_on_the_original_message
    "hey"
  end

  def another_original_method
    "zoink"
  end
end

original = OriginalMessage.new
wrapper = MyMessage.new(original)

puts wrapper.my_clever_method
# => "heywoohoo"

puts wrapper.another_original_method
# => "zoink"

如您所见,包装器自动将方法调用转发给包装对象。

答案 4 :(得分:-1)

这不是最漂亮的,但它有效......

class GmailMessage < Gmail::Message

  def initialize(message)
    message.instance_variables.each do |variable|
      self.instance_variable_set(
        variable, 
        message.instance_variable_get(variable)
        )
    end
  end

  def something_clever
    # do something clever here
  end

end

感谢所有帮助人员。