Subject:
Re: [ruby-ffi] attach_function a bit draconian
From:
Colby Gutierrez-Kraybill
Date:
9/5/11 2:52 PM
To:
ruby-ffi@googlegroups.com


On Sep 5, 2011, at 12:45 PM, Colby Gutierrez-Kraybill wrote:


On Sep 5, 2011, at 12:10 AM, Matijs van Zuijlen wrote:

Hi Charlie,

On 04/09/2011 23:19, cfis wrote:
I've written a ffi wrapper for the free image library, which is here:

http://cfis.github.com/free-image-ruby/

The problem is that I've coded against the latest version of
FreeImage, and most linux distributions have older versions
installed.  Thus when I try to load the gem it fails since
attach_function throws an error because the older versions don't have
all the functions.

You can just wrap the call to attach_function in a begin-rescue-end construct. Then in the rescue block, you can do whatever you want. In your case, this would probably mean issuing a warning and then defining a stub function. You can even wrap that in a method, say, attach_function_safely.

Regards,
Matijs

this++

I had a need to create convenience aliases for GSL routines and I created a new method that wrapped around attach_function as well as a side-along override of method_missing:

By using method_missing, you could capture any calls that a developer expects to be in the library (a more current one) and do exactly what you need doing.

See:

attach_gsl_function,
http://gsl4r.rubyforge.org/git?p=gsl4r.git;a=blob;f=lib/gsl4r/util.rb;h=3c2ce22ac866b5053b8fed7a34058e299950eae5;hb=HEAD


OH, and,

There's a lot of extra cruft in the attach_gsl_function that creates both ruby and C based tests so that the C code can be compiled and the results tested against the output of the FFI wrapper around GSL calls.  I wanted to avoid having to write those tests by hand.  Hope this helps.

The bit to pay attention to is:

129     module AutoPrefix 
131       $prefixLock = Monitor.new
133       # This traps method calls intended to create shortened versions
134       # of the GSL function calls.
135       # 
136       # This first checks if the called method matches the Module
137       # function call gsl_complex_#{called_method} (where called_method
138       # might be 'abs').
139       #
140       # If it finds a match (respond_to), it will then create a new
141       # method for the class as a whole (class_eval), making the method
142       # available to not just this instance of the class, but all
143       # existing instances and all those created after.
144       # 
145       # Finally, the creation is wrapped up in a synchronized call
146       # to ensure thread safety.  It is only unsafe the first time
147       # the method is invoked (and non-existent at that point).  Every
148       # time the method is invoked after, it should not hit method_missing.
149       # TODO: Is this true for java threads too, or is it per 'vm' per
150       # thread?
151       def method_missing( called_method, *args, &block )
153         $prefixLock.synchronize do
155           prefix = self.class::GSL_PREFIX
157           if ( self.class::GSL_MODULE::Methods.respond_to?("#{prefix}#{called_method}") == false )
158             prefix = ""
159             if ( self.class::GSL_MODULE::Methods.respond_to?("#{called_method}") == false )
160               super # NoMethodError
161             end
162           end
164           # TODO: this could be smoothed out with the #args/#parameters parts of
165           # Ruby 1.9.
166           # This could inspect the definition of the parameter and if the
167           # first argument in the definition were of the same type as self
168           # then self could be inserted into the args list per below
169           # rather than requiring the #{called_method.to_s.upcase}_ADD_SELF
170           # boolean definition and check
171           self.class.class_eval <<-end_eval
172           def #{called_method}(*args, &block)
173             if ::#{self.class::GSL_MODULE.to_s}::Methods::#{prefix.to_s.upcase}#{called_method.to_s.upcase}_ADD_SELF 
174               args.insert(0, self)
175             end
176             ::#{self.class::GSL_MODULE.to_s}::Methods::#{prefix}#{called_method}( *args, &block )
177           end
178           end_eval
180           __send__(called_method, *args, &block)
181         end # prefixLock.synchronize
182       end # method_missing
183     end # AutoPrefix