rdbxml 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|