diff --git a/lib/redland.rb b/lib/redland.rb index c9c8a94..2f8551a 100644 --- a/lib/redland.rb +++ b/lib/redland.rb @@ -1,21 +1,92 @@ # @api private # FFI bindings module Redland - # Handling FFI difference between MRI and Rubinius - if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby' - require 'ffi' - extend FFI::Library - ffi_lib "rdf" - else - # TODO: This might be outdated already, check with Rubinius - extend FFI::Library - ffi_lib "librdf.so.0" + + class << self + + def mri? + defined?(RUBY_DESCRIPTION) && (/^ruby/ =~ RUBY_DESCRIPTION) + end + + def jruby? + defined?(RUBY_PLATFORM) && ("java" == RUBY_PLATFORM) + end + + def rubinius? + defined?(RUBY_ENGINE) && ("rbx" == RUBY_ENGINE) + end + + # @api_private + # Determine FFI constant for this ruby engine. + def find_ffi + if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx" + if const_defined? "::Rubinius::FFI" + ::Rubinius::FFI + elsif const_defined? "::FFI" + ::FFI + else + require "ffi" + ::FFI + end + else # mri, jruby, etc + require "ffi" + ::FFI + end + end + + # @api_private + # Extend with the correct ffi implementation. + def load_ffi + ffi_module = Redland::find_ffi + extend ffi_module::Library + ffi_module + end + + # @api_private + # Loads the librdf shared library. + def load_librdf + begin + ffi_lib "rdf" + rescue LoadError + ffi_lib "librdf.so.0" + end + end + + # @api_private + # Loads the libraptor shared library. + def load_raptor + begin + ffi_lib "raptor2" + rescue LoadError + ffi_lib "libraptor2.so.0" + end + end end + # Constant holding the FFI module for this ruby engine. + FFI = Redland::load_ffi + Redland::load_raptor + + # Defines raptor2 enum raptor_world_flag + enum :raptor_world_flag, [ + :RAPTOR_WORLD_FLAG_LIBXML_GENERIC_ERROR_SAVE, 1, + :RAPTOR_WORLD_FLAG_LIBXML_STRUCTURED_ERROR_SAVE, 2, + :RAPTOR_WORLD_FLAG_URI_INTERNING, 3, + :RAPTOR_WORLD_FLAG_WWW_SKIP_INIT_FINISH, 4 + ] + + # Raptor + attach_variable :raptor_version_decimal, :int + attach_function :raptor_new_world_internal, [:int], :pointer + attach_function :raptor_world_set_flag, [:pointer, :raptor_world_flag, :int], :int + + Redland::load_librdf + # World attach_function :librdf_new_world, [], :pointer attach_function :librdf_free_world, [:pointer], :void attach_function :librdf_world_open, [:pointer], :void + attach_function :librdf_world_set_raptor, [:pointer, :pointer], :void # Storage attach_function :librdf_new_storage, [:pointer, :string, :string, :string], :pointer diff --git a/lib/redlander.rb b/lib/redlander.rb index cbb9372..6fcfd92 100644 --- a/lib/redlander.rb +++ b/lib/redlander.rb @@ -13,15 +13,17 @@ module Redlander class << self + RDF_WORLD = Redland.librdf_new_world + Redland.librdf_world_open(RDF_WORLD) + if Redland::jruby? + raptor_world_ptr = Redland.raptor_new_world_internal(Redland.raptor_version_decimal) + Redland.raptor_world_set_flag(raptor_world_ptr, :RAPTOR_WORLD_FLAG_URI_INTERNING, 0) + Redland.librdf_world_set_raptor(RDF_WORLD, raptor_world_ptr) + end + # @api private def rdf_world - unless @rdf_world - @rdf_world = Redland.librdf_new_world - raise RedlandError, "Could not create a new RDF world" if @rdf_world.null? - ObjectSpace.define_finalizer(self, finalize_world(@rdf_world)) - Redland.librdf_world_open(@rdf_world) - end - @rdf_world + RDF_WORLD end diff --git a/lib/redlander/node.rb b/lib/redlander/node.rb index 8799232..c3de0a1 100644 --- a/lib/redlander/node.rb +++ b/lib/redlander/node.rb @@ -14,7 +14,7 @@ def finalize_node(rdf_node_ptr) def rdf_node unless instance_variable_defined?(:@rdf_node) @rdf_node = case @arg - when FFI::Pointer + when Redland::FFI::Pointer @arg when NilClass Redland.librdf_new_node_from_blank_identifier(Redlander.rdf_world, @options[:blank_id]) @@ -62,9 +62,9 @@ def datatype # @option options [Boolean] :resource interpret arg as URI string and create an RDF "resource". # @raise [RedlandError] if it fails to create a node from the given args. def initialize(arg = nil, options = {}) - # If FFI::Pointer is passed, wrap it instantly, + # If Redland::FFI::Pointer is passed, wrap it instantly, # because it can be freed outside before it is used here. - @arg = arg.is_a?(FFI::Pointer) ? wrap(arg) : arg + @arg = arg.is_a?(Redland::FFI::Pointer) ? wrap(arg) : arg @options = options end diff --git a/lib/redlander/statement.rb b/lib/redlander/statement.rb index f2ce078..40d4772 100644 --- a/lib/redlander/statement.rb +++ b/lib/redlander/statement.rb @@ -14,7 +14,7 @@ def finalize_statement(rdf_statement_ptr) def rdf_statement unless instance_variable_defined?(:@rdf_statement) @rdf_statement = case @source - when FFI::Pointer + when Redland::FFI::Pointer @source when Hash # Create a new statement from nodes @@ -40,9 +40,9 @@ def rdf_statement # @raise [NotImplementedError] if cannot create a Statement from the given source. # @raise [RedlandError] if it fails to create a Statement. def initialize(source = {}) - # If FFI::Pointer is passed, wrap it instantly, + # If Redland::FFI::Pointer is passed, wrap it instantly, # because it can be freed outside before it is used here. - @source = source.is_a?(FFI::Pointer) ? wrap(source) : source + @source = source.is_a?(Redland::FFI::Pointer) ? wrap(source) : source end # Subject of the statment. diff --git a/lib/redlander/uri.rb b/lib/redlander/uri.rb index f869e31..08bd214 100644 --- a/lib/redlander/uri.rb +++ b/lib/redlander/uri.rb @@ -6,7 +6,7 @@ class Uri def rdf_uri unless instance_variable_defined?(:@rdf_uri) @rdf_uri = case @source - when FFI::Pointer + when Redland::FFI::Pointer @source when URI, String Redland.librdf_new_uri(Redlander.rdf_world, @source.to_s) @@ -34,7 +34,7 @@ def finalize_uri(rdf_uri_ptr) # @raise [NotImplementedError] if cannot create a Uri from the given source. # @raise [RedlandError] if it fails to create a Uri. def initialize(source) - @source = source.is_a?(FFI::Pointer) ? wrap(source) : source + @source = source.is_a?(Redland::FFI::Pointer) ? wrap(source) : source end def to_s