如何在 Ruby 模块中扩展 class
How to extend a class within a Ruby module
我一直在使用 OilyPNG(一组用于处理 PNG 的 C 扩展),我想开始添加一些我自己的方法。因此,我编写了一个简单的小 C 扩展,它创建了 class Hola
并包含方法 Hola.bonjour
(以简单的 "hello" 响应)和 Hola.wazzup(input)
立即返回输入。
OilyPNG 是一个包含单个 class :Canvas
和一堆方法 :decode_png_image_pass
、:from_data_url
、:from_rgb_stream
等的模块。我想将我的方法(bonjour
和 wazzup
)添加到 Canvas
,这样我就可以开始使用它们了。我该怎么做呢?
这似乎是一个非常基本的 Ruby 问题,但我似乎无法在任何地方找到它的解决方法。我已经尝试过(除其他外)以下内容:
module ChunkyPNG
class Canvas
include Hola
end
end
...但是 returns 以下内容:
Error: #TypeError: wrong argument type Class (expected Module)
我只想做一些简单的事情,比如创建一个新的 Canvas 对象,然后 运行 我的方法,即 OilyPNG::Canvas.new.bonjour
我完全卡住了。
更新:用于生成扩展的 C 代码
#include <ruby.h>
/* our new native method; it just returns the string "bonjour!" */
static VALUE hola_bonjour(VALUE self) {
return rb_str_new2("bonjour, Zack!");
}
void Init_hola(void) {
VALUE klass = rb_define_module("Hola"); /*DEFINED AS A MODULE*/
rb_define_singleton_method(klass, "bonjour", hola_bonjour, 0);
}
更新 2:
终于让它工作了——在 C 代码中使用 rb_define module
,然后将方法定义为 rb_define_method
(而不是单例)。然后构建gem,安装它,然后需要.so文件,然后打开OilyPNG包含Hola模块,如下:
module OilyPNG
class Canvas < ChunkyPNG::Canvas
def your_method
puts "hello"
end
include Hola
end
end
然后加载一个png文件作为测试对象:
test = OilyPNG::Canvas.from_file("C:/code/testfiles/orange.png"); nil
(nil 是为了防止 Sketchup 在尝试将 PNG 对象发送到命令行时崩溃),然后测试输出:
test.bonjour
而且有效!
module OilyPNG
class Canvas < ChunkyPNG::Canvas # You must match the superclass when opening class and adding more definitions
def your_method
puts "hello"
end
include Hola # this will "insert" the Hola module at this point in the code... not sure what Hola contains so, not sure if that works or not.
end
end
查看 OilyPNG 的源代码,上面应该可以工作...
不确定为什么会出现该错误。鉴于此在这里起作用的原因是:重新打开它时必须匹配 classes,super class。
根据这篇文章:伟大的 Peter Cooper 的 http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html,我相信您应该使用 rb_define_method
,而不是 rb_define_singleton_method
如果您仍然遇到问题,请从 peter 的示例开始,然后根据您的需要进行调整。
你说你
[...] coded up a simple little C extension that creates the class "Hola"
所以 Hola
是一个 class。但是 include
需要 模块 ,而不是 class。如果您想 include Hola
修补 ChunkyPNG::Canvas
,您必须将 Hola
作为一个模块重建。
考虑这个例子:
class C
end
class D
include C
end
这将为您提供与您所看到的完全相同的 TypeError
。但是,如果您说:
module M
end
class E
include M
end
那就可以正常工作了。
我一直在使用 OilyPNG(一组用于处理 PNG 的 C 扩展),我想开始添加一些我自己的方法。因此,我编写了一个简单的小 C 扩展,它创建了 class Hola
并包含方法 Hola.bonjour
(以简单的 "hello" 响应)和 Hola.wazzup(input)
立即返回输入。
OilyPNG 是一个包含单个 class :Canvas
和一堆方法 :decode_png_image_pass
、:from_data_url
、:from_rgb_stream
等的模块。我想将我的方法(bonjour
和 wazzup
)添加到 Canvas
,这样我就可以开始使用它们了。我该怎么做呢?
这似乎是一个非常基本的 Ruby 问题,但我似乎无法在任何地方找到它的解决方法。我已经尝试过(除其他外)以下内容:
module ChunkyPNG
class Canvas
include Hola
end
end
...但是 returns 以下内容:
Error: #TypeError: wrong argument type Class (expected Module)
我只想做一些简单的事情,比如创建一个新的 Canvas 对象,然后 运行 我的方法,即 OilyPNG::Canvas.new.bonjour
我完全卡住了。
更新:用于生成扩展的 C 代码
#include <ruby.h>
/* our new native method; it just returns the string "bonjour!" */
static VALUE hola_bonjour(VALUE self) {
return rb_str_new2("bonjour, Zack!");
}
void Init_hola(void) {
VALUE klass = rb_define_module("Hola"); /*DEFINED AS A MODULE*/
rb_define_singleton_method(klass, "bonjour", hola_bonjour, 0);
}
更新 2:
终于让它工作了——在 C 代码中使用 rb_define module
,然后将方法定义为 rb_define_method
(而不是单例)。然后构建gem,安装它,然后需要.so文件,然后打开OilyPNG包含Hola模块,如下:
module OilyPNG
class Canvas < ChunkyPNG::Canvas
def your_method
puts "hello"
end
include Hola
end
end
然后加载一个png文件作为测试对象:
test = OilyPNG::Canvas.from_file("C:/code/testfiles/orange.png"); nil
(nil 是为了防止 Sketchup 在尝试将 PNG 对象发送到命令行时崩溃),然后测试输出:
test.bonjour
而且有效!
module OilyPNG
class Canvas < ChunkyPNG::Canvas # You must match the superclass when opening class and adding more definitions
def your_method
puts "hello"
end
include Hola # this will "insert" the Hola module at this point in the code... not sure what Hola contains so, not sure if that works or not.
end
end
查看 OilyPNG 的源代码,上面应该可以工作...
不确定为什么会出现该错误。鉴于此在这里起作用的原因是:重新打开它时必须匹配 classes,super class。
根据这篇文章:伟大的 Peter Cooper 的 http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html,我相信您应该使用 rb_define_method
,而不是 rb_define_singleton_method
如果您仍然遇到问题,请从 peter 的示例开始,然后根据您的需要进行调整。
你说你
[...] coded up a simple little C extension that creates the class "Hola"
所以 Hola
是一个 class。但是 include
需要 模块 ,而不是 class。如果您想 include Hola
修补 ChunkyPNG::Canvas
,您必须将 Hola
作为一个模块重建。
考虑这个例子:
class C
end
class D
include C
end
这将为您提供与您所看到的完全相同的 TypeError
。但是,如果您说:
module M
end
class E
include M
end
那就可以正常工作了。