Module: Svn::Utils::Extensions

Defined in:
lib/svn/utils.rb

Overview

this module contains extensions for classes that inherit from FFI::Struct and FFI::AutoPointer to make binding instance methods to C methods more concise

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bind(sym, options = {}, &block) ⇒ Object

binds a method on the current target to self

arguments

sym

the method on the target (set by bind_to) to use

options

a Hash of optional method aliases or returned arguments

options

:as

method name to use for the bound method

:to

function name to use from the target object

:returning

an array of types for out parameters

:validate

a validation to call on the bound method’s return value

:before_return

a function to call on the return value

TODO: call to_proc on symbols that should be procs



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/svn/utils.rb', line 187

def bind( sym, options={}, &block )
  # look up the method in the target module
  meth_name = ( options[:to] || sym ).to_sym
  # get a method obj from the target receiver so that if @@target is
  # changed by another call to :bind_to, the method/target will not be
  # changed (and broken)
  meth = @@target.method( meth_name )
  name = ( options[:as] || sym ).to_sym

  # get the return types as an Array and save a copy
  single_return = !options[:returning].is_a?( Array )
  return_types = Array( options[:returning] ).dup

  # get the C function validation
  validation = options[:validate]

  # get the before_return filter
  before_return = options[:before_return] || lambda { |x| x }

  # create a new method; blocks are used to re-arrange arguments
  define_method( name ) do |*args|
    # create new pointers for the specified out arguments
    return_ptrs = return_types.map { |type|
      FFI::MemoryPointer.new( type )
    }

    # create the argument list for the function
    call_args = return_ptrs.dup
    call_args << self
    call_args += args

    return_val = nil # keep it in scope
    if block
      # call the method with the arguments after re-arranging via block
      return_val = meth.call( *instance_exec( *call_args, &block ) )
    else
      # call the method with the standard argument order
      return_val = meth.call( *call_args )
    end

    # call the return check, if present
    instance_exec( return_val, &validation ) if validation

    # if there are return types (out pointers), read the values out of
    # the pointers and replace the return_val
    unless return_types.empty?
      return_val = return_ptrs.zip( return_types ).map do |ptr, type|
        Utils.content_from( ptr, type )
      end
      return_val = return_val.first if single_return
    end

    # run the before_return filter and return the value from it; if no
    # :before_return was in options, this will be the id function
    instance_exec( return_val, &before_return )
  end

end

.bind_to(target) ⇒ Object

sets the module that will be used for all bound methods, until bind_to is called again



169
170
171
# File 'lib/svn/utils.rb', line 169

def bind_to( target )
  @@target = target
end

Instance Method Details

#factory(*args) ⇒ Object

convenience method that returns a Factory instance for self with the given args

the following are equivalent:

NativeHash.factory( :string, :string )

Factory( NativeHash, :string, :string )


161
162
163
# File 'lib/svn/utils.rb', line 161

def factory( *args )
  Factory.new( self, *args )
end