Ruby's *args causing seg fault when no args supplied
I'm trying to do some scripted GUI testing in Windows using Ruby. I'm leveraging the g开发者_如何学JAVAuidance of a pragprog book and I'm hitting a bit of a snag. I've factored out some code to help with the repeatitive mapping of win32api functions. The code is as follows:
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
...So I can use that block to define several win32APIs in the module in the following fashion:
def_api 'FindWindow', ['P', 'P'], 'L'
I've got some RSpec tests to ensure this behaves as it should.
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
Everything works fine as for the first test, the second results in a seg fault. Seems that if I call this with no args, I can't touch *args - but I can do a args.length to see that it's empty.
Why would this result in a seg fault and not an exception? Would it be acceptable to resolve this through something like..
raise BadArgs if args.length == 0
Yet another question that is way too long - sorry for that.
TIA! Bob
The likely reason it's seg faulting is because somewhere underneath Win32API
the lack of arguments is translating into one or more NULL pointer dereferences.
If you are going to create functions like this then you should consider adding a per-api-call, boolean-returning argument validation block (or lambda) as an argument to def_api
which you would then invoke as the first part of your derived function. Something like this:
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
Then
def_api 'FindWindow', ['P', 'P'], 'L', { |args| return true if // API specific checks succeed }
UPDATE: Adding more color at questioner's request
The &valid_args?
is the name of a block parameter. The ampersand prefix (&) is how you tell ruby that you passing a block. You can only pass one block to a methodand it must be the last parameter in the argument list. The question mark suffix (?) is just a convention in Ruby programming for naming functions which return boolean values.
If a block is passed you invoke it with &block.call(args)
To call a method with a block argument you do something like this:
method { |args| // block implementation }
or
method do |args|
// block implementation
end
The args
are passed to the block through the call method
. Hope this helps.
精彩评论