1

我正在尝试使用 Ruby 在 Windows 中进行一些脚本化的 GUI 测试。我正在利用一本pragprog 书的指导,但遇到了一些障碍。我已经提取了一些代码来帮助重复映射 win32api 函数。代码如下:

module WindowsGui

  def self.def_api(function, parameters, return_value)              
    api = Win32API.new 'user32', function, parameters, return_value

    define_method(function.snake_case) do |*args|                  
      api.call *args                                                
    end

  end
end

...所以我可以使用该块以以下方式在模块中定义几个 win32API:

def_api 'FindWindow', ['P', 'P'], 'L' 

我已经进行了一些 RSpec 测试以确保其行为正常。

  it 'wraps a Windows call with a method' do
    find_window(nil, nil).should_not == 0
  end
  
  it 'enforces the argument count' do
    lambda {find_window}.should raise_error
  end

第一次测试一切正常,第二次导致段错误。似乎如果我在没有参数的情况下调用它,我就无法触摸 *args - 但我可以做一个 args.length 来查看它是空的。

为什么这会导致段错误而不是异常?通过类似的方式解决这个问题是否可以接受?

  raise BadArgs if args.length == 0

还有一个问题太长了——抱歉。

蒂亚!鲍勃

4

1 回答 1

1

它出现段错误的可能原因是因为Win32API缺少参数的某个地方正在转换为一个或多个 NULL 指针取消引用。

如果您要创建这样的函数,那么您应该考虑添加一个按 API 调用、返回布尔值的参数验证块(或 lambda)作为参数,def_api然后将其作为派生函数的第一部分调用。像这样的东西:

def self.def_api(function, parameters, return_value, &valid_args?)              
  api = Win32API.new 'user32', function, parameters, return_value

  define_method(function.snake_case) do |*args|
    if valid_args? and valid_args?.call(*args)               
      api.call *args
    else
      // raise argument error, etc
    end                                         
  end

end

然后

def_api 'FindWindow', ['P', 'P'], 'L', { |args| return true if // API specific checks succeed }

更新:应提问者的要求添加更多颜色

&valid_args?是块参数的名称。& 号前缀 (&) 是告诉 ruby​​ 你传递了一个块的方式。您只能将一个块传递给方法,并且它必须是参数列表中的最后一个参数。问号后缀 (?) 只是 Ruby 编程中用于命名返回布尔值的函数的约定。

如果传递了一个块,则调用它&block.call(args)

要使用块参数调用方法,您可以执行以下操作:

method { |args| // block implementation }

或者

method do |args|
  // block implementation
end

args通过call method. 希望这可以帮助。

于 2010-07-12T13:06:10.713 回答