On Tue, Feb 5, 2013 at 9:15 PM, Rob Marshall <lists / ruby-forum.com> wrote:
> Hi,
>
> I'm working on my first Ruby project...and I'm trying to adhere to the
> DRY principle. What I have is a lot, and I mean a LOT, of repetition.
> The calls all look similar to this (by the way I'm writing an interface
> to a library with FFI):
>
> module MyLibrary
>   extend FFI::Library
>   ffi_lib [MyLibrary]
>
>   attach_function :LibFunc, [ :string, :pointer ], :void
>   attach_function :CheckError, [], :int
>
>   class SubClass
>      def lib_func(name)
>         ret = FFI::MemoryPointer.new(:char,256)
>         MyLibrary.LibFunc(name,ret)
>         if MyLibrary.CheckError != 0
>           raise "You got an error"
>         end
>      end
>   end
> end
>
> That's the basic idea, but I have several classes within the module,
> each with a dozen, or more, functions. What I am doing now is, within
> the module:
>
>   def call_check_error(function)
>     ret = lambda {function}.call
>     if MyLibrary.CheckError != 0
>       raise "You got an error"
>     end
>     return ret
>   end
>
> For functions that don't actually return a value, ret is nil, so I can
> just ignore it when I don't need it, and that way I avoid having to have
> two methods, one with, and one without, a return. So that in lib_func I
> do:
>
>     def lib_func(name)
>       ret = FFI::MemoryPointer.new(:char, 256)
>       MyLibrary.call_check_error(MyLibrary.LibFunc(name,ret))
>     end

This is not doing what you think it does. Ruby evaluates the arguments
of a method before calling the method. So that that line you are
actually calling the MyLibrary.LibFunc, getting its return value and
passing it to call_check_error.
Say for example that LibFunc returns "a", you are passing that string
"a" to the call_check_error, so that you do:

lambda {"a"}.call, which also returns "a".

> This seems to be working fine, although I've just started doing it this
> way.
>
> So my question is: Is that a good way to implement this? I'm assuming
> it's probably not the best way, and I would hope someone with more
> experience with Ruby might have a suggestion. It kind of feels like:
>
> lambda {function}.call
>
> is a bit hokey, but I wasn't sure how else to do it.

If I remember correctly, you asked some time ago a way to refactor
this and Robert Klemme suggested to use blocks. So something like:

def call_with_check_error
  ret = yield
  if MyLibrary.CheckError != 0
    raise "You got an error"
  end
  return ret
end

def lib_func(name)
  pointer = FFI::MemoryPointer.new(:char, 256)
  call_with_check_error { MyLibrary.LibFunc(name,ret) }
end

Hope this helps,

Jesus.