rdbxml 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +21 -0
- data/README +80 -0
- data/Rakefile +100 -0
- data/docs/db.rb +6 -0
- data/docs/dbxml.rb +6 -0
- data/ext/db.i +23 -0
- data/ext/dbxml.i +1708 -0
- data/ext/dbxml_ruby.i +14 -0
- data/extconf.rb +37 -0
- data/lib/rdbxml.rb +79 -0
- data/rake/extensiontask.rb +194 -0
- data/rake/swigextensiontask.rb +62 -0
- data/test/db_test.rb +11 -0
- data/test/dbxml_test.rb +48 -0
- data/test/rdbxml_test.rb +40 -0
- metadata +75 -0
data/ext/dbxml_ruby.i
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
%module dbxml
|
2
|
+
%include "std_string.i"
|
3
|
+
|
4
|
+
%exception {
|
5
|
+
try {
|
6
|
+
$action
|
7
|
+
} catch ( DbException &ex ) {
|
8
|
+
static VALUE rb_DBException = rb_define_class("DBException", rb_eStandardError);
|
9
|
+
rb_raise( rb_DBException, ex.what() );
|
10
|
+
} catch ( DbXml::XmlException &ex ) {
|
11
|
+
static VALUE rb_XmlException = rb_define_class("XmlException", rb_eStandardError);
|
12
|
+
rb_raise( rb_XmlException, ex.what() );
|
13
|
+
}
|
14
|
+
}
|
data/extconf.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
DBXML_DIST=ENV['DBXML_DIST'] || './dbxml-2.2.13'
|
3
|
+
|
4
|
+
# Build makefile that just calls rakefile
|
5
|
+
File.open( 'Makefile', 'w' ) do |mk|
|
6
|
+
targets = ['all', 'clean', 'test', 'install']
|
7
|
+
mk.puts ".PHONY: #{targets.join(' ')}\n"
|
8
|
+
targets.each { |t| mk.puts "#{t}:\n\t@rake $@\n" }
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
=begin
|
13
|
+
require 'mkmf2'
|
14
|
+
|
15
|
+
MAKEFILE_CONFIG['CC'].gsub! 'gcc', 'g++'
|
16
|
+
MAKEFILE_CONFIG['CPP'].gsub! 'gcc', 'g++'
|
17
|
+
|
18
|
+
###############################################################################
|
19
|
+
|
20
|
+
#b.libs += ['db-4.3', 'db_cxx-4.3', 'dbxml-2.2', 'xquery-1.2', 'xerces-c', 'pathan']
|
21
|
+
|
22
|
+
add_include_path File.join( DBXML_DIST, 'install', 'include' )
|
23
|
+
add_library_path File.join( DBXML_DIST, 'install', 'lib' )
|
24
|
+
require_library 'db', 'db_version', 'db.h'
|
25
|
+
require_library 'db_cxx', 'DbEnv::version', 'db_cxx.h'
|
26
|
+
declare_binary_library 'db', 'db_wrap.cc'
|
27
|
+
|
28
|
+
#add_include_path File.join( DBXML_DIST, 'install', 'include', 'dbxml' )
|
29
|
+
require_library 'xerces-c', 'XERCES_VERSIONSTR', 'xercesc/util/XercesVersion.hpp'
|
30
|
+
require_library 'pathan'
|
31
|
+
require_library 'xquery'
|
32
|
+
require_library 'dbxml', 'DBXML_VERSION_STRING', 'dbxml/DbXmlFwd.hpp'
|
33
|
+
declare_binary_library 'dbxml', 'dbxml_wrap.cc'
|
34
|
+
|
35
|
+
|
36
|
+
File.open( 'Makefile', 'a' ) { |mk| mk.puts "DBXML_DIST=#{DBXML_DIST}", 'include Makefile.swig' }
|
37
|
+
=end
|
data/lib/rdbxml.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'db'
|
2
|
+
require 'dbxml'
|
3
|
+
|
4
|
+
# = RDBXML -- Pure-Ruby DB XML interface
|
5
|
+
# This module provides Ruby-ish convenience functions for DBXML. See the unit
|
6
|
+
# tests for usage examples.
|
7
|
+
|
8
|
+
module RDBXML
|
9
|
+
include Dbxml
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Creates a BDB environment with files stored in +dir+, with the following options:
|
13
|
+
# [:create] Create the environment if it doesn't exist (default: +true+)
|
14
|
+
# [:lock] Use locking (default: +true+)
|
15
|
+
# [:log] Use logging (default: +true+)
|
16
|
+
# [:mpool] Use memory pool (default: +true+)
|
17
|
+
# [:txn] Use transactions (default: +true+)
|
18
|
+
def env( dir, opts = {} )
|
19
|
+
opts = {
|
20
|
+
:create => true,
|
21
|
+
:lock => true,
|
22
|
+
:log => true,
|
23
|
+
:mpool => true,
|
24
|
+
:txn => true,
|
25
|
+
}.merge(opts)
|
26
|
+
flags = {
|
27
|
+
:create => Dbxml::DB_CREATE,
|
28
|
+
:lock => Dbxml::DB_INIT_LOCK,
|
29
|
+
:log => Dbxml::DB_INIT_LOG,
|
30
|
+
:mpool => Dbxml::DB_INIT_MPOOL,
|
31
|
+
:txn => Dbxml::DB_INIT_TXN,
|
32
|
+
}.inject(0) { |flags, (key, val)| flags|val if opts[key] }
|
33
|
+
|
34
|
+
env = Db::DbEnv.new 0
|
35
|
+
env.open dir, flags, 0
|
36
|
+
env
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Dbxml::XmlManager
|
42
|
+
# Opens the container named +name+, creating it if it doesn't exist.
|
43
|
+
def []( name )
|
44
|
+
openContainer name.to_s, Dbxml::DB_CREATE
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Dbxml::XmlContainer
|
49
|
+
# Returns the document named +name+, or +nil+ if it doesn't exist.
|
50
|
+
def []( name )
|
51
|
+
begin
|
52
|
+
getDocument name.to_s
|
53
|
+
rescue XmlException => ex
|
54
|
+
raise unless ex.to_s =~ /document not found/i
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates/updates the document named +name+ with the string +content+.
|
60
|
+
def []=( name, content )
|
61
|
+
ctx = getManager.createUpdateContext
|
62
|
+
begin
|
63
|
+
putDocument name, content, ctx, 0
|
64
|
+
rescue XmlException => ex
|
65
|
+
raise unless ex.to_s =~ /document exists/i
|
66
|
+
doc = getManager.createDocument
|
67
|
+
doc.setName name
|
68
|
+
doc.setContent content
|
69
|
+
updateDocument doc, ctx
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Dbxml::XmlDocument
|
75
|
+
# Returns the document XML as a string.
|
76
|
+
def to_s
|
77
|
+
getContentAsString
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/tasklib'
|
4
|
+
|
5
|
+
module Rake
|
6
|
+
|
7
|
+
# Create a build task that will generate a Ruby extension (e.g. .so) from one or more
|
8
|
+
# C (.c) or C++ (.cc, .cpp, .cxx) files, and is intended as a replcaement for mkmf.
|
9
|
+
# It determines platform-specific settings (e.g. file extensions, compiler flags, etc.)
|
10
|
+
# from rbconfig (note: examples assume *nix file extensions).
|
11
|
+
#
|
12
|
+
# *Note*: Strings vs Symbols
|
13
|
+
# In places where filenames are expected (i.e. lib_name and objs), +String+s are used
|
14
|
+
# as verbatim filenames, while, +Symbol+s have the platform-dependant extension
|
15
|
+
# appended (e.g. '.so' for libraries and '.o' for objects).
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# desc "build sample extension"
|
19
|
+
# # build sample.so (from foo.{c,cc,cxx,cpp}, through foo.o)
|
20
|
+
# Rake::ExtensionTask.new :sample => :foo do |t|
|
21
|
+
# # all extension files under this directory
|
22
|
+
# t.dir = 'ext'
|
23
|
+
# # don't include, but rebuild library if it changes
|
24
|
+
# t.deps << 'config.h'
|
25
|
+
# # link libraries (libbar.so)
|
26
|
+
# t.link_libs << 'bar'
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Author:: Steve Sloan (mailto:steve@finagle.org)
|
30
|
+
# Copyright:: Copyright (c) 2006 Steve Sloan
|
31
|
+
# License:: GPL
|
32
|
+
|
33
|
+
class ExtensionTask < Rake::TaskLib
|
34
|
+
# The name of the extension
|
35
|
+
attr_accessor :name
|
36
|
+
|
37
|
+
# The filename of the extension library file (e.g. 'extension.so')
|
38
|
+
attr_accessor :lib_name
|
39
|
+
|
40
|
+
# Object files to build and link into the extension.
|
41
|
+
attr_accessor :objs
|
42
|
+
|
43
|
+
# Depency files that aren't linked into the library, but cause it to be
|
44
|
+
# rebuilt when they change.
|
45
|
+
attr_accessor :deps
|
46
|
+
|
47
|
+
# The directory where the extension files (source, output, and
|
48
|
+
# intermediate) are stored.
|
49
|
+
attr_accessor :dir
|
50
|
+
|
51
|
+
# Environment configuration -- i.e. CONFIG from rbconfig, with a few other
|
52
|
+
# settings, and converted to lowercase-symbols.
|
53
|
+
attr_accessor :env
|
54
|
+
|
55
|
+
# Additional link libraries
|
56
|
+
attr_accessor :link_libs
|
57
|
+
|
58
|
+
|
59
|
+
# List of paths to object files to build
|
60
|
+
def output_objs
|
61
|
+
@objs.collect do |o|
|
62
|
+
f = (Symbol === o) ? "#{o}.#{env[:objext]}" : o
|
63
|
+
File.join( dir, f )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Path to the output library file
|
68
|
+
def output_lib
|
69
|
+
File.join( dir, lib_name )
|
70
|
+
end
|
71
|
+
|
72
|
+
# Same arguments as Rake::define_task
|
73
|
+
def initialize( args, &blk )
|
74
|
+
@env = @@DefaultEnv.dup
|
75
|
+
@name, @objs = resolve_args(args)
|
76
|
+
set_defaults
|
77
|
+
yield self if block_given?
|
78
|
+
define_tasks
|
79
|
+
end
|
80
|
+
|
81
|
+
# Generate default values. This is called from initialize _before_ the
|
82
|
+
# yield block.
|
83
|
+
#
|
84
|
+
# Defaults:
|
85
|
+
# - lib_name: name.so
|
86
|
+
# - objs: name.o
|
87
|
+
# - dir: .
|
88
|
+
def set_defaults
|
89
|
+
@lib_name = (Symbol === name) ? "#{name}.#{env[:dlext]}" : name
|
90
|
+
@objs = [name.to_sym]
|
91
|
+
@dir = '.'
|
92
|
+
@deps, @link_libs = [], []
|
93
|
+
end
|
94
|
+
|
95
|
+
# Defines the library task.
|
96
|
+
def define_tasks
|
97
|
+
task name => (deps.collect { |d| File.join( dir, d ) } << output_lib) do end
|
98
|
+
|
99
|
+
file output_lib => output_objs do |t|
|
100
|
+
sh_cmd :ldshared, {'-L' => :libdirs}, '-o', t.name, t.prerequisites,
|
101
|
+
{'-l' => link_libs}, :libs, :dlibs
|
102
|
+
end
|
103
|
+
|
104
|
+
CLEAN.include output_objs
|
105
|
+
CLOBBER.include output_lib
|
106
|
+
define_rules
|
107
|
+
end
|
108
|
+
|
109
|
+
# Defines C and C++ source-to-object rules, using the source extensions from env.
|
110
|
+
def define_rules
|
111
|
+
for ext in env[:c_exts]
|
112
|
+
Rake::Task.create_rule '.'+env[:objext] => '.'+ext do |r|
|
113
|
+
sh_cmd :cc, :cflags, :cppflags, {'-D' => :defines}, {'-I' => :includedirs}, {'-I' => :topdir},
|
114
|
+
'-c', '-o', r.name, r.sources
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
for ext in env[:cpp_exts]
|
119
|
+
Rake::Task.create_rule '.'+env[:objext] => '.'+ext do |r|
|
120
|
+
sh_cmd :cxx, :cxxflags, :cppflags, {'-D' => :defines}, {'-I' => :includedirs}, {'-I' => :topdir},
|
121
|
+
'-o', r.name, '-c', r.sources
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class << self
|
127
|
+
# The default environment for all extensions.
|
128
|
+
def env
|
129
|
+
@@DefaultEnv
|
130
|
+
end
|
131
|
+
|
132
|
+
@@DefaultEnv = {
|
133
|
+
:cxx => ENV['CXX'] || 'c++',
|
134
|
+
:cxxflags => ENV['CXXFLAGS'] || '',
|
135
|
+
|
136
|
+
:c_exts => ['c'],
|
137
|
+
:cpp_exts => ['cc', 'cxx', 'cpp'],
|
138
|
+
:swig => 'swig',
|
139
|
+
:swig_flags => ['-ruby', '-c++'],
|
140
|
+
:swig_includedirs => ['.'],
|
141
|
+
|
142
|
+
:includedirs => [], #['/usr/local/include'],
|
143
|
+
:libdirs => [], #['/usr/local/lib'],
|
144
|
+
}
|
145
|
+
Config::CONFIG.each { |k, v| @@DefaultEnv[k.downcase.to_sym] = v }
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
|
150
|
+
# Convenience function for cnstructing command lines for build tools.
|
151
|
+
def optify( *opts )
|
152
|
+
return optify(*opts.first) if opts.size == 1 and opts.first.kind_of? Array
|
153
|
+
opts.collect do |opt|
|
154
|
+
case opt
|
155
|
+
when String then opt
|
156
|
+
when Symbol then optify env[opt]
|
157
|
+
when Hash
|
158
|
+
opt.collect do |k, v|
|
159
|
+
v = env[v] if v.kind_of? Symbol
|
160
|
+
if v.kind_of? Array
|
161
|
+
optify v.collect { |w| k.to_s + w.to_s }
|
162
|
+
elsif v
|
163
|
+
k.to_s + v.to_s
|
164
|
+
end
|
165
|
+
end
|
166
|
+
else
|
167
|
+
opt.to_s
|
168
|
+
end
|
169
|
+
end.join(' ')
|
170
|
+
end
|
171
|
+
|
172
|
+
def sh_cmd( cmd, *opts )
|
173
|
+
sh optify( cmd, *opts )
|
174
|
+
end
|
175
|
+
|
176
|
+
# For some reason, Rake::TaskManager.resolve_args can't be found, so snarf it.
|
177
|
+
def resolve_args(args)
|
178
|
+
case args
|
179
|
+
when Hash
|
180
|
+
fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
|
181
|
+
fail "No Task Name Given" if args.size < 1
|
182
|
+
task_name = args.keys[0]
|
183
|
+
deps = args[task_name]
|
184
|
+
deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
|
185
|
+
else
|
186
|
+
task_name = args
|
187
|
+
deps = []
|
188
|
+
end
|
189
|
+
[task_name, deps]
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/extensiontask'
|
3
|
+
|
4
|
+
module Rake
|
5
|
+
|
6
|
+
# Create a build task that will generate a Ruby wrapper extension from
|
7
|
+
# a SWIG interface definition. Requires SWIG[http://www.swig.org] version 1.3.x.
|
8
|
+
#
|
9
|
+
# See ExtensionTask for more information.
|
10
|
+
#
|
11
|
+
# Example (from RDBXML):
|
12
|
+
# # dbxml.i -> dbxml_wrap.cc -> dbxml_wrap.o -> dbxml.so
|
13
|
+
# Rake::SWIGExtensionTask.new :dbxml do |t|
|
14
|
+
# # keep it all under ext/
|
15
|
+
# t.dir = 'ext'
|
16
|
+
# # dbxml.i includes dbxml_ruby.i -- rebuild if it changes
|
17
|
+
# t.deps << 'dbxml_ruby.i'
|
18
|
+
# # link in dbxml libraries
|
19
|
+
# t.link_libs += ['db', 'db_cxx', 'dbxml', 'xquery', 'xerces-c', 'pathan']
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Author:: Steve Sloan (mailto:steve@finagle.org)
|
23
|
+
# Copyright:: Copyright (c) 2006 Steve Sloan
|
24
|
+
# License:: GPL
|
25
|
+
class SWIGExtensionTask < ExtensionTask
|
26
|
+
# Defaults:
|
27
|
+
# - lib_name: name.so
|
28
|
+
# - objs: name_wrap.o
|
29
|
+
# - deps: name.i
|
30
|
+
# - dir: .
|
31
|
+
def set_defaults
|
32
|
+
super
|
33
|
+
@lib_name = (Symbol === name) ? "#{name}.#{env[:dlext]}" : name
|
34
|
+
@objs = ["#{name}_wrap".to_sym]
|
35
|
+
@deps = ["#{name}.i"]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add rule for generating C++ wrapper code (_wrap.cc) from SWIG interface definition (.i).
|
39
|
+
def define_rules
|
40
|
+
verify_swig_version
|
41
|
+
Rake::Task.create_rule( '_wrap.cc' => [proc {|t| t.gsub /_wrap\.cc$/, '.i' }] ) do |r|
|
42
|
+
sh_cmd :swig, :swig_flags, {'-I' => :swig_includedirs}, {'-I' => :includedirs},
|
43
|
+
'-o', r.name, r.sources
|
44
|
+
end
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
# Raise an exception unless we have SWIG version 1.3 or later.
|
51
|
+
def verify_swig_version
|
52
|
+
@@swig_version ||= IO.popen "#{env[:swig]} -version 2>&1" do |swig|
|
53
|
+
banner = swig.readlines.reject { |l| l.strip.empty? }
|
54
|
+
banner[0].match(/SWIG Version ([^ ]+)/i)[1]
|
55
|
+
end
|
56
|
+
unless @@swig_version >= '1.3'
|
57
|
+
raise "Need SWIG version 1.3 or later (have #{@@swig_version[0]})"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/test/db_test.rb
ADDED
data/test/dbxml_test.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'db'
|
3
|
+
require 'dbxml'
|
4
|
+
|
5
|
+
include Dbxml
|
6
|
+
|
7
|
+
class DBXMLTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@dir = File.join( File.dirname(__FILE__), File.basename(__FILE__, '.rb') + '.db' )
|
10
|
+
Dir.mkdir @dir unless File.exists? @dir
|
11
|
+
@name = "test document ##{rand(10000)}"
|
12
|
+
@content = '<test>This is a test</test>'
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create_environment
|
16
|
+
@env = Db::DbEnv.new 0
|
17
|
+
assert_not_nil @env
|
18
|
+
|
19
|
+
@env.open @dir, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_create_manager
|
23
|
+
test_create_environment unless @env
|
24
|
+
@db = XmlManager.new @env, 0
|
25
|
+
assert_not_nil @db
|
26
|
+
|
27
|
+
@db.setDefaultContainerType XmlContainer::WholedocContainer
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_open_container
|
31
|
+
test_create_manager unless @db
|
32
|
+
@docs = @db.openContainer 'test', DB_CREATE
|
33
|
+
assert_not_nil @docs
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_put_doument
|
37
|
+
test_open_container unless @docs
|
38
|
+
assert_not_nil @docs
|
39
|
+
|
40
|
+
@docs.putDocument @name, @content, @db.createUpdateContext, 0
|
41
|
+
|
42
|
+
doc = @docs.getDocument @name
|
43
|
+
assert_not_nil doc
|
44
|
+
assert_equal doc.getName, @name
|
45
|
+
assert_equal doc.getContentAsString, @content
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|