要求失败并出现TypeError'不是类'通过RubyGems包装器运行rake时

时间:2014-10-29 23:14:53

标签: ruby rubygems

我有一个用C ++编写的ruby扩展,P4,它似乎通常有效:

  • 我可以运行irb -Ilib然后require 'P4',并使用它
  • 我可以通过访问rake gem的bin文件夹中的shell脚本来执行rake测试,例如${GEM_HOME}/gems/rake-10.3.2/bin/rake test

但是,当我通过路径中的RubyGems包装器访问rake时,例如rake test,我得到了这个TypeError

/Users/tjuricek/dev/p4ruby/lib/P4.rb:38:in `require': P4 is not a class (TypeError)
        from /Users/tjuricek/dev/p4ruby/lib/P4.rb:38:in `<top (required)>'
        from /Users/tjuricek/dev/p4ruby/test/testlib.rb:31:in `require'
        from /Users/tjuricek/dev/p4ruby/test/testlib.rb:31:in `<top (required)>'
        from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:15:in `require'
        from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:15:in `block in <main>'
        from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:4:in `select'
        from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:4:in `<main>'
rake aborted!

然后它会弹出“失败”的ruby命令。如果我复制并粘贴该命令并运行它,它就可以工作。

我注意到RubyGems创建了一个相当简单的包装器脚本:

#!/usr/bin/env ruby_executable_hooks
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0"

if ARGV.first
  str = ARGV.first
  str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
  if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
    version = $1
    ARGV.shift
  end
end

gem 'rake', version
load Gem.bin_path('rake', 'rake', version)

猜测最后一行load Gem.bin_path...引发了我在创建扩展程序时遇到的某种错误配置,但我不知道那会是什么。

有没有人知道只有在RubyGems包装器下运行时可能导致require失败的原因?

1 个答案:

答案 0 :(得分:3)

好的,调试方法是进入加载文件的行:

require 'P4.so'

看看它是否定义了:

puts "P4 #{P4.class}"
require 'P4.so'

在这种情况下,当直接在rake下运行时,它加载了.gemspec,它引入了一个版本定义(在我的情况下,错误地)P4模块:

module P4
  version = VERSION = '3000.0.0.pre0'
end

所以,对我而言,修复包括:

  1. module P4更改为class P4
  2. require 'P4.so'语句之前需要版本定义,通常为:require_relative 'P4/version'
  3. 没有在我的C ++扩展代码中定义类,而是加载它并扩展我的版本文件中定义的类:

    //确保该类已由版本规范定义 cP4 = rb_path2class(“P4”);