From: "Jesús Gabriel y Galán" Date: 2013-02-06T19:50:58+09:00 Subject: Re: Implementing DRY with a function call On Tue, Feb 5, 2013 at 9:15 PM, Rob Marshall 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.