如何在Ruby模块中扩展类

时间:2016-02-19 23:00:26

标签: ruby class module include extend

我一直在使用OilyPNG(一组用于处理PNG的C扩展),我想开始添加一些自己的方法。因此,我编写了一个简单的小C扩展,它创建了类Hola,并包含方法Hola.bonjour(用简单的“hello”响应)和Hola.wazzup(input)吐出输入权限背部。

OilyPNG是一个包含单个类:Canvas的模块,其中包含一系列方法:decode_png_image_pass:from_data_url:from_rgb_stream等。我想将我的方法(bonjourwazzup)添加到Canvas,以便我可以开始使用它们。我该怎么做呢?

这似乎是一个非常基本的Ruby问题,但我似乎无法在任何地方找到它。我已经尝试了(在许多其他事情中)以下内容:

module ChunkyPNG
  class Canvas
    include Hola
  end
end

...但它会返回以下内容:

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

它有效!

2 个答案:

答案 0 :(得分:1)

你说你

  

[...]编写了一个简单的小C扩展,创建了类“Hola”

所以Hola是一个类。但是include需要模块,而不是类。如果您希望Hola修补include Hola,则必须重建ChunkyPNG::Canvas作为模块。

考虑这个例子:

class C
end
class D
  include C
end

这将为您提供与您所看到的完全相同的TypeError。但是,如果你说:

module M
end
class E
  include M
end

然后它会正常工作。

答案 1 :(得分:0)

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的来源,上述应该有效......

不确定为什么会出现这个错误。鉴于这一点,这里的原因是:为了重新打开它,你必须匹配类,超类。

基于这篇文章:伟大的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

如果您仍然遇到问题,请从彼得的例子开始,然后根据您的需要进行调整。