Module: NiceFFI::Library
- Defined in:
- lib/nice-ffi/library.rb
Overview
A module to be used in place of FFI::Library. It acts mostly like FFI::Library, but with some nice extra features and conveniences to make life easier:
-
load_library method to help find and load libraries from common (or custom) places for the current OS. Use it instead of ffi_lib.
-
attach_function accepts TypedPointers as return type, in which case it wraps the return value of the bound function in the TypedPointer’s type.
-
Shorthand aliases to improve code readability:
-
func = attach_function
-
var = attach_variable
-
Class Method Summary collapse
Instance Method Summary collapse
- #attach_function(methname, arg1, arg2, arg3 = nil) ⇒ Object
-
#load_library(names, search_paths = NiceFFI::PathSet::DEFAULT) ⇒ Object
Try to find and load a library (e.g. “SDL_ttf”) into an FFI wrapper module (e.g. SDL::TTF).
-
#optional(warn_message = nil, &block) ⇒ Object
Calls the given block, but rescues and prints a warning if FFI::NotFoundError is raised.
-
#optional_function(*args) ⇒ Object
(also: #optfunc)
Like #attach_function, but wrapped in #optional.
Class Method Details
.extend_object(klass) ⇒ Object
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/nice-ffi/library.rb', line 48 def self.extend_object( klass ) klass.extend FFI::Library super class << klass alias :func :attach_function alias :var :attach_variable end end |
Instance Method Details
#attach_function(methname, arg1, arg2, arg3 = nil) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/nice-ffi/library.rb', line 106 def attach_function( methname, arg1, arg2, arg3=nil ) # To match the normal attach_function's weird syntax. # The arguments can be either: # # 1. methname, args, retrn_type (funcname = methname) # 2. methname, funcname, args, retrn_type # funcname, args, retrn_type = if arg1.kind_of?(Array) [methname, arg1, arg2] else [arg1, arg2, arg3] end unless retrn_type.kind_of? NiceFFI::TypedPointer # Normal FFI::Library.attach_function behavior. super else # Create the raw FFI binding, which returns a pointer. # We call it __methname because it's not meant to be called # by users. We also make it private below. # super( "__#{methname}".to_sym, funcname, args, :pointer ) # CAUTION: Metaclass hackery ahead! Handle with care! = class << self; self; end .instance_eval { # Create the nice method, which calls __methname and wraps the # return value (a pointer) the appropriate class using # TypedPointer#wrap. This is the one that users should call, # so we don't prepend the name with _'s. # define_method( methname ) do |*args| retrn_type.wrap( send("__#{methname}".to_sym, *args) ) end # __methname is private. private "__#{methname}".to_sym } end end |
#load_library(names, search_paths = NiceFFI::PathSet::DEFAULT) ⇒ Object
Try to find and load a library (e.g. “SDL_ttf”) into an FFI wrapper module (e.g. SDL::TTF). This method searches in different locations depending on your OS. See PathSet.
Returns the path to the library that was loaded.
Raises LoadError if it could not find or load the library.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/nice-ffi/library.rb', line 68 def load_library( names, search_paths=NiceFFI::PathSet::DEFAULT ) names = [names] unless names.kind_of? Array paths = search_paths.find( *names ) # Try just the plain library name(s), as last resort. paths += names # Try loading each path until one works. loaded = paths.find { |path| begin self.module_eval { ffi_lib path } rescue LoadError false else true end } if loaded.nil? # Oops, none of them worked. pretty_names = if names.size == 1 names[0] else names[0..-2].join(", ") + ", or " + names[-1] end raise( LoadError, "Could not load #{pretty_names}." ) else # Return the one that did work return loaded end end |
#optional(warn_message = nil, &block) ⇒ Object
Calls the given block, but rescues and prints a warning if FFI::NotFoundError is raised. If warn_message is nil, the error message is printed instead.
This is intended to be used around #attach_function for cases where the function may not exist (e.g. because the user has an old version of the library) and the library should continue loading anyway (with the function missing).
Example:
module Foo
extend NiceFFI::Library
load_library( "libfoo" )
optional( "Warning: Your libfoo doesn't have opt_func()" ) do
attach_function :opt_func, [], :int
end
end
178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/nice-ffi/library.rb', line 178 def optional( =nil, &block ) raise LocalJumpError, "no block given" unless block_given? begin block.call() rescue FFI::NotFoundError => e if puts else puts "Warning: #{e.}" end end end |
#optional_function(*args) ⇒ Object Also known as: optfunc
Like #attach_function, but wrapped in #optional.
193 194 195 |
# File 'lib/nice-ffi/library.rb', line 193 def optional_function( *args ) optional { attach_function( *args ) } end |