[英]Inherit a class from a gem and add local methods
I use a gem to manage certain attributes of a gmail api integration, and I'm pretty happy with the way it works. 我使用gem来管理gmail api集成的某些属性,我对它的工作方式非常满意。
I want to add some local methods to act on the Gmail::Message class that is used in that gem. 我想添加一些本地方法来处理该gem中使用的Gmail :: Message类。
ie I want to do something like this. 即我想做这样的事情。
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
I don't want to persist it. 我不想坚持下去。 But obviously I can't define self in that way. 但显然我无法以这种方式定义自我。
To clarify, I want to take an instance of Gmail::Message and create a GmailMessage instance which is a straight copy of that other message. 为了澄清,我想采用Gmail :: Message的实例并创建一个GmailMessage实例,该实例是该其他消息的直接副本。
I can then run methods like @gmail.subject and @gmail.html, but also run @gmail.something_clever... and save local attributes if necessary. 然后我可以运行@ gmail.subject和@gmail.html等方法,但也可以运行@ gmail.something_clever ...并在必要时保存本地属性。
Am I completely crazy? 我完全疯了吗?
You can use concept of mixin
, wherein you include a Module
in another class to enhance it with additional functions. 您可以使用mixin
概念,其中您在另一个类中包含一个Module
,以通过其他功能来增强它。
Here is how to do it. 这是怎么做的。 To create a complete working example, I have created modules that resemble what you may have in your code base. 为了创建一个完整的工作示例,我创建了类似于您的代码库中的模块。
# 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"
Following should work: 以下应该工作:
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..
I'm not sure why you can't just have a simple wrapper class... 我不确定为什么你不能只有一个简单的包装类......
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
Then you can do... 然后你可以......
@my_message = GmailMessage.new(@original_message)
@my_message will correctly respond to all the methods that were supported with @original_message and you can add your own methods to the class. @my_message将正确响应@original_message支持的所有方法,您可以将自己的方法添加到类中。
EDIT - changed thanks to @jeeper's observations in the comments 编辑 - 感谢@ jeeper在评论中的观察结果
Building upon what the other posters have said, you can use built-in class SimpleDelegator in ruby to wrap an existing message: 基于其他海报所说的内容,您可以在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"
As you can see, the wrapper automatically forwards method calls to the wrapped object. 如您所见,包装器自动将方法调用转发给包装对象。
It's not the prettiest, but it works... 这不是最漂亮的,但它有效......
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
Thanks for all your help guys. 谢谢你们的帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.