Аргументы Ruby * вызывают ошибку сегмента, если аргументы не указаны - PullRequest
1 голос
/ 12 июля 2010

Я пытаюсь провести некоторое тестирование GUI в Windows с использованием Ruby. Я пользуюсь руководством книги 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.length, чтобы увидеть, что он пуст.

Почему это приведет к ошибке сегмента, а не к исключению? Было бы приемлемо разрешить это через что-то вроде ..

  raise BadArgs if args.length == 0

Еще один вопрос, который слишком длинный - извините за это.

ТИА! Боб

1 Ответ

1 голос
/ 12 июля 2010

Вероятная причина, по которой он вызывает ошибку seg, заключается в том, что где-то под Win32API отсутствие аргументов приводит к одному или нескольким разыменованиям NULL-указателей.

Если вы собираетесь создавать подобные функции, то вам следует рассмотреть возможность добавленияблок проверки (или лямбда-выражения) аргумента для вызова api-call, boolean-return в качестве аргумента 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.Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...