rufus-tokyo 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,17 @@
2
2
  = rufus-tokyo CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-tokyo - 0.1.7 released 2009/02/19
6
+
7
+ - todo : Rufus::Tokyo::Cabinet.new('filename', :type => :hash) now OK (Zev)
8
+ - todo : more documentation for Rufus::Tokyo::Cabinet#new
9
+ - added : Rufus::Tokyo::Cabinet has a open method that takes a block like
10
+ File.open (Zev)
11
+ - todo : aligned Rufus::Tokyo::Table#new on ::Cabinet#new
12
+ - todo : added opts (:prefix, :limit, :native) to Rufus::Tokyo::Cabinet#keys,
13
+ Rufus::Tokyo::Table#keys and the corresponding Tyrant classes
14
+
15
+
5
16
  == rufus-tokyo - 0.1.6 released 2009/02/16
6
17
 
7
18
  - todo : Tyrant and TyrantTable now complain when used in lieu of each other
@@ -4,13 +4,15 @@
4
4
 
5
5
  == authors
6
6
 
7
- John Mettraux http://jmettraux.wordpress.com
8
- Justin Reagor http://blog.kineticweb.com/
7
+ John Mettraux http://jmettraux.wordpress.com
8
+ Justin Reagor http://blog.kineticweb.com/
9
+ Zev Blut http://www.iknow.co.jp/users/zev
9
10
 
10
11
 
11
12
  == finally
12
13
 
13
- many thanks to the author of Tokyo Cabinet (Mikio Hirabayashi) and of ruby-ffi
14
+ many thanks to the author of Tokyo Cabinet (Mikio Hirabayashi) and
15
+ the authors of ruby-ffi
14
16
 
15
17
  http://tokyocabinet.sourceforge.net
16
18
  http://kenai.com/projects/ruby-ffi
data/README.txt CHANGED
@@ -240,6 +240,7 @@ many thanks to the author of Tokyo Cabinet, Mikio Hirabayashi, and to the author
240
240
 
241
241
  John Mettraux, jmettraux@gmail.com, http://jmettraux.wordpress.com
242
242
  Justin Reagor, http://blog.kineticweb.com/
243
+ Zev Blut, http://www.iknow.co.jp/users/zev
243
244
 
244
245
 
245
246
  == the rest of Rufus
@@ -22,13 +22,19 @@
22
22
  #++
23
23
  #
24
24
 
25
+ #
26
+ # "made in Japan"
27
+ #
28
+ # jmettraux@gmail.com
29
+ #
30
+
25
31
  require 'ffi' # sudo gem install ffi
26
32
 
27
33
 
28
34
  module Rufus
29
35
  module Tokyo
30
36
 
31
- VERSION = '0.1.6'
37
+ VERSION = '0.1.7'
32
38
 
33
39
  #
34
40
  # A common error class
@@ -40,7 +46,3 @@ end
40
46
 
41
47
  require 'rufus/tokyo/cabinet'
42
48
 
43
- # TODO : do not include me
44
- #require 'rufus/tokyo/tyrant'
45
- #require 'rufus/tokyo/dystopia'
46
-
@@ -74,48 +74,140 @@ module Rufus
74
74
  # 'casket.tch' with a bucket number of 100000 and the 'large' and
75
75
  # 'deflate' options (opts) turned on.
76
76
  #
77
- # == :hash or :tree
77
+ # Note that there is an #open method similar to File#open for openening
78
+ # a db and closing it when it's no longer needed :
78
79
  #
79
- # Setting the name to :hash or :tree simply will create a in-memory hash
80
- # or tree respectively (see #new_tree and #new_hash).
80
+ # Rufus::Tokyo::Cabinet.new('data.tch') do |db|
81
+ # db['key'] = value
82
+ # end
81
83
  #
82
- # == tuning parameters
84
+ # == database name
83
85
  #
84
- # It's ok to use the optional params hash to pass tuning parameters and
85
- # options, thus
86
+ # From http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi :
86
87
  #
87
- # db = Rufus::Tokyo::Cabinet.new('casket.tch#bnum=100000#opts=ld')
88
+ # 'If it is "*", the database will be an on-memory hash database. If it is
89
+ # "+", the database will be an on-memory tree database. If its suffix is
90
+ # ".tch", the database will be a hash database. If its suffix is ".tcb",
91
+ # the database will be a B+ tree database. If its suffix is ".tcf", the
92
+ # database will be a fixed-length database. If its suffix is ".tct", the
93
+ # database will be a table database.'
94
+ #
95
+ # You're supposed to give a path to the database file you want to use and
96
+ # Cabinet expects you to give the proper prefix.
97
+ #
98
+ # db = Rufus::Tokyo::Cabinet.new('data.tch') # hash database
99
+ # db = Rufus::Tokyo::Cabinet.new('data.tcb') # B+ tree db
100
+ # db = Rufus::Tokyo::Cabinet.new('data.tcf') # fixed-length db
101
+ #
102
+ # will result with the same file names :
103
+ #
104
+ # db = Rufus::Tokyo::Cabinet.new('data', :type => :hash) # hash database
105
+ # db = Rufus::Tokyo::Cabinet.new('data', :type => :btree) # B+ tree db
106
+ # db = Rufus::Tokyo::Cabinet.new('data', :type => :fixed) # fixed-length db
107
+ #
108
+ # You can open an in-memory hash and an in-memory B+ tree with :
109
+ #
110
+ # h = Rufus::Tokyo::Cabinet.new(:mem_hash) # or
111
+ # h = Rufus::Tokyo::Cabinet.new('*')
112
+ #
113
+ # t = Rufus::Tokyo::Cabinet.new(:mem_tree) # or
114
+ # t = Rufus::Tokyo::Cabinet.new('+')
115
+ #
116
+ # == parameters
88
117
  #
89
- # and
118
+ # There are two ways to pass parameters at the opening of a db :
119
+ #
120
+ # db = Rufus::Tokyo::Cabinet.new('data.tch#opts=ld#mode=w') # or
121
+ # db = Rufus::Tokyo::Cabinet.new('data.tch', :opts => 'ld', :mode => 'w')
122
+ #
123
+ # most verbose :
90
124
  #
91
125
  # db = Rufus::Tokyo::Cabinet.new(
92
- # 'casket.tch', :bnum => 100000, :opts => 'ld')
126
+ # 'data', :type => :hash, :opts => 'ld', :mode => 'w')
127
+ #
128
+ # === mode
129
+ #
130
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
131
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
132
+ #
133
+ # === other parameters
134
+ #
135
+ # 'On-memory hash database supports "bnum", "capnum", and "capsiz".
136
+ # On-memory tree database supports "capnum" and "capsiz".
137
+ # Hash database supports "mode", "bnum", "apow", "fpow", "opts",
138
+ # "rcnum", and "xmsiz".
139
+ # B+ tree database supports "mode", "lmemb", "nmemb", "bnum", "apow",
140
+ # "fpow", "opts", "lcnum", "ncnum", and "xmsiz".
141
+ # Fixed-length database supports "mode", "width", and "limsiz"'
142
+ #
143
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
144
+ # (usually empty or something like 'ld' or 'lb')
145
+ #
146
+ # * :bnum number of elements of the bucket array
147
+ # * :apow size of record alignment by power of 2 (defaults to 4)
148
+ # * :fpow maximum number of elements of the free block pool by
149
+ # power of 2 (defaults to 10)
150
+ # * :mutex when set to true, makes sure only 1 thread at a time
151
+ # accesses the table (well, Ruby, global thread lock, ...)
93
152
  #
94
- # are equivalent.
153
+ # * :rcnum specifies the maximum number of records to be cached.
154
+ # If it is not more than 0, the record cache is disabled.
155
+ # It is disabled by default.
156
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
157
+ # If it is not more than 0, the default value is specified.
158
+ # The default value is 2048.
159
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
160
+ # cached. If it is not more than 0, the default value is
161
+ # specified. The default value is 512.
95
162
  #
96
- # == mode
163
+ # * :xmsiz specifies the size of the extra mapped memory. If it is
164
+ # not more than 0, the extra mapped memory is disabled.
165
+ # The default size is 67108864.
97
166
  #
98
- # To open a db in read-only mode :
167
+ # * :capnum specifies the capacity number of records.
168
+ # * :capsiz specifies the capacity size of using memory.
99
169
  #
100
- # db = Rufus::Tokyo::Cabinet.new('casket.tch#mode=r')
101
- # db = Rufus::Tokyo::Cabinet.new('casket.tch', :mode => 'r')
170
+ #
171
+ # = NOTE :
172
+ #
173
+ # On reopening a file, Cabinet will tend to stick to the parameters as
174
+ # set when the file was opened. To change that, have a look at the
175
+ # man pages of the various command line tools coming with Tokyo Cabinet.
102
176
  #
103
177
  def initialize (name, params={})
104
178
 
105
179
  @db = lib.tcadbnew
106
180
 
107
- name = '*' if name == :hash # in memory hash database
108
- name = '+' if name == :tree # in memory B+ tree database
181
+ name = '*' if name == :mem_hash # in memory hash database
182
+ name = '+' if name == :mem_tree # in memory B+ tree database
183
+
184
+ if type = params.delete(:type)
185
+ name += { :hash => '.tch', :btree => '.tcb', :fixed => '.tcf' }[type]
186
+ end
109
187
 
110
188
  name = name + params.collect { |k, v| "##{k}=#{v}" }.join('')
111
189
 
112
190
  (lib.tcadbopen(@db, name) == 1) ||
113
- raise("failed to open/create db '#{name}'")
191
+ raise("failed to open/create db '#{name}' #{params.inspect}")
114
192
 
115
193
  self.default = params[:default]
116
194
  @default_proc ||= params[:default_proc]
117
195
  end
118
196
 
197
+ # Same args as initialize, but can take a block form that will
198
+ # close the db when done. Similar to File.open
199
+ def self.open (name, params={})
200
+ db = self.new(name, params)
201
+ if block_given?
202
+ yield db
203
+ nil
204
+ else
205
+ db
206
+ end
207
+ ensure
208
+ db.close if block_given? && db
209
+ end
210
+
119
211
  #
120
212
  # Returns a new in-memory hash. Accepts the same optional params hash
121
213
  # as new().
@@ -229,11 +321,41 @@ module Rufus
229
321
  #
230
322
  # Returns an array with all the keys in the databse
231
323
  #
232
- def keys
233
- a = []
234
- lib.abs_iterinit(@db)
235
- while (k = (lib.abs_iternext2(@db) rescue nil)); a << k; end
236
- a
324
+ # With no options given, this method will return all the keys (strings)
325
+ # in a Ruby array.
326
+ #
327
+ # :prefix --> returns only the keys who match a given string prefix
328
+ #
329
+ # :limit --> returns a limited number of keys
330
+ #
331
+ # :native --> returns an instance of Rufus::Tokyo::List instead of
332
+ # a Ruby Hash, you have to call #free on that List when done with it !
333
+ # Else you're exposing yourself to a memory leak.
334
+ #
335
+ def keys (options={})
336
+
337
+ if pref = options[:prefix]
338
+
339
+ l = lib.abs_fwmkeys2(@db, pref, options[:limit] || -1)
340
+ l = Rufus::Tokyo::List.new(l)
341
+ options[:native] ? l : l.release
342
+
343
+ else
344
+
345
+ limit = options[:limit] || -1
346
+ limit = nil if limit < 1
347
+
348
+ l = options[:native] ? Rufus::Tokyo::List.new : []
349
+
350
+ lib.abs_iterinit(@db)
351
+
352
+ while (k = (lib.abs_iternext2(@db) rescue nil))
353
+ break if limit and l.size >= limit
354
+ l << k
355
+ end
356
+
357
+ l
358
+ end
237
359
  end
238
360
  end
239
361
 
@@ -97,12 +97,18 @@ module Rufus
97
97
  attfunc :abs_sync, :tcadbsync, [ :pointer ], :int
98
98
  attfunc :abs_copy, :tcadbcopy, [ :pointer, :string ], :int
99
99
 
100
+ attfunc :abs_fwmkeys2, :tcadbfwmkeys2, [ :pointer, :string, :int ], :pointer
101
+
100
102
  #
101
103
  # tctdb functions
102
104
  #
103
105
  # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
104
106
 
105
107
  attfunc :tctdbnew, [], :pointer
108
+ attfunc :tctdbsetmutex, [ :pointer ], :int
109
+ attfunc :tctdbtune, [ :pointer, :uint64, :uint8, :uint8, :uint8 ], :int
110
+ attfunc :tctdbsetcache, [ :pointer, :uint32, :uint32, :uint32 ], :int
111
+ attfunc :tctdbsetxmsiz, [ :pointer, :uint64 ], :int
106
112
 
107
113
  attfunc :tctdbopen, [ :pointer, :string, :int ], :int
108
114
 
@@ -137,6 +143,8 @@ module Rufus
137
143
  attfunc :tctdbtrancommit, [ :pointer ], :int
138
144
  attfunc :tctdbtranabort, [ :pointer ], :int
139
145
 
146
+ attfunc :tab_fwmkeys2, :tctdbfwmkeys2, [ :pointer, :string, :int ], :pointer
147
+
140
148
  #
141
149
  # tctdbqry functions
142
150
  #
@@ -31,61 +31,94 @@
31
31
  module Rufus
32
32
  module Tokyo
33
33
 
34
- module OpenModes
34
+ #
35
+ # Methods for setting up / tuning a Cabinet.
36
+ #
37
+ # Gets included into Table.
38
+ #
39
+ module CabinetConfig
40
+
41
+ protected
35
42
 
36
43
  #
37
- # some Tokyo constants
44
+ # Given a path, a hash of parameters and a suffix,
45
+ #
46
+ # a) makes sure that the path has the given suffix or raises an exception
47
+ # b) gathers params found in the path (#) or in params
48
+ # c) determines the config as set by the parameters
49
+ #
50
+ def determine_conf (path, params, suffix)
38
51
 
39
- OREADER = 1 << 0 # open as a reader
40
- OWRITER = 1 << 1 # open as a writer
41
- OCREAT = 1 << 2 # writer creating
42
- OTRUNC = 1 << 3 # writer truncating
43
- ONOLCK = 1 << 4 # open without locking
44
- OLCKNB = 1 << 5 # lock without blocking
52
+ if path.index('#')
45
53
 
46
- OTSYNC = 1 << 6 # synchronize every transaction (tctdb.h)
54
+ ss = path.split('#')
55
+ path = ss.shift
47
56
 
48
- #
49
- # Makes sure that a set of parameters is a hash (will transform an
50
- # array into a hash if necessary)
51
- #
52
- def params_to_h (params)
57
+ ss.each { |p| pp = p.split('='); params[pp[0]] = pp[1] }
58
+ end
59
+
60
+ raise "path '#{path}' must be suffixed with #{suffix}" \
61
+ unless path[-suffix.length..-1] == suffix
62
+
63
+ params = params.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
53
64
 
54
- params.is_a?(Hash) ?
55
- params :
56
- Array(params).inject({}) { |h, e| h[e] = true; h }
65
+ conf = {
66
+ :params => params,
67
+ :path => path,
68
+ :mode => determine_open_mode(params),
69
+ :mutex => (params[:mutex].to_s == 'true'),
70
+ #:indexes => params[:idx] || params[:indexes],
71
+ :xmsiz => (params[:xmsiz] || 67108864).to_i
72
+ }
73
+ conf.merge!(determine_tuning_values(params))
74
+ conf.merge(determine_cache_values(params))
57
75
  end
58
76
 
59
- #
60
- # Given params (array or hash), computes the open mode (an int)
61
- # for the Tokyo Cabinet object.
62
- #
63
- def compute_open_mode (params)
77
+ def determine_open_mode (params) #:nodoc#
64
78
 
65
- params = params_to_h(params)
79
+ mode = params[:mode].to_s
80
+ mode = 'wc' if mode.size < 1
66
81
 
67
- i = {
68
- :read => OREADER,
69
- :reader => OREADER,
70
- :write => OWRITER,
71
- :writer => OWRITER,
72
- :create => OCREAT,
73
- :truncate => OTRUNC,
74
- :no_lock => ONOLCK,
75
- :lock_no_block => OLCKNB,
76
- :sync_every => OTSYNC
82
+ {
83
+ 'r' => (1 << 0), # open as a reader
84
+ 'w' => (1 << 1), # open as a writer
85
+ 'c' => (1 << 2), # writer creating
86
+ 't' => (1 << 3), # writer truncating
87
+ 'e' => (1 << 4), # open without locking
88
+ 'f' => (1 << 5), # lock without blocking
89
+ 's' => (1 << 6), # synchronize every transaction (tctdb.h)
77
90
 
78
- }.inject(0) { |r, (k, v)|
91
+ }.inject(0) { |r, (c, v)|
79
92
 
80
- r = r | v if params[k]; r
93
+ r = r | v if mode.index(c); r
81
94
  }
95
+ end
82
96
 
83
- unless params[:read_only] || params[:readonly]
84
- i = i | OCREAT
85
- i = i | OWRITER
86
- end
97
+ def determine_tuning_values (params) #:nodoc#
98
+
99
+ bnum = (params[:bnum] || 131071).to_i
100
+ apow = (params[:apow] || 4).to_i
101
+ fpow = (params[:fpow] || 10).to_i
87
102
 
88
- i
103
+ o = params[:opts] || ''
104
+ o = {
105
+ 'l' => 1 << 0, # large
106
+ 'd' => 1 << 1, # deflate
107
+ 'b' => 1 << 2, # bzip2
108
+ 't' => 1 << 3, # tcbs
109
+ 'x' => 1 << 4
110
+ }.inject(0) { |i, (k, v)| i = i | v if o.index(k); i }
111
+
112
+ { :bnum => bnum, :apow => apow, :fpow => fpow, :opts => o }
113
+ end
114
+
115
+ def determine_cache_values (params) #:nodoc#
116
+
117
+ {
118
+ :rcnum => params[:rcnum].to_i,
119
+ :lcnum => (params[:lcnum] || 2048).to_i,
120
+ :ncnum => (params[:ncnum] || 512).to_i
121
+ }
89
122
  end
90
123
  end
91
124
 
@@ -122,31 +155,82 @@ module Rufus
122
155
  class Table
123
156
 
124
157
  include HashMethods
125
- include OpenModes
158
+ include CabinetConfig
126
159
 
127
160
  #
128
161
  # Creates a Table instance (creates or opens it depending on the args)
129
162
  #
130
163
  # For example,
131
164
  #
132
- # t = Rufus::Tokyo::Table.new('table.tdb', :create, :write)
165
+ # t = Rufus::Tokyo::Table.new('table.tdb')
133
166
  # # '.tdb' suffix is a must
134
167
  #
135
168
  # will create the table.tdb (or simply open it if already present)
136
169
  # and make sure we have write access to it.
137
- # Note that the suffix (.tdc) is relevant to Tokyo Cabinet, using another
138
- # will result in a Tokyo Cabinet error.
139
170
  #
140
- def initialize (*args)
141
-
142
- path = args.first # car
143
- params = args[1..-1] # cdr
171
+ # == parameters
172
+ #
173
+ # Parameters can be set in the path or via the optional params hash (like
174
+ # in Rufus::Tokyo::Cabinet)
175
+ #
176
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
177
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
178
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
179
+ # (usually empty or something like 'ld' or 'lb')
180
+ #
181
+ # * :bnum number of elements of the bucket array
182
+ # * :apow size of record alignment by power of 2 (defaults to 4)
183
+ # * :fpow maximum number of elements of the free block pool by
184
+ # power of 2 (defaults to 10)
185
+ # * :mutex when set to true, makes sure only 1 thread at a time
186
+ # accesses the table (well, Ruby, global thread lock, ...)
187
+ #
188
+ # * :rcnum specifies the maximum number of records to be cached.
189
+ # If it is not more than 0, the record cache is disabled.
190
+ # It is disabled by default.
191
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
192
+ # If it is not more than 0, the default value is specified.
193
+ # The default value is 2048.
194
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
195
+ # cached. If it is not more than 0, the default value is
196
+ # specified. The default value is 512.
197
+ #
198
+ # * :xmsiz specifies the size of the extra mapped memory. If it is
199
+ # not more than 0, the extra mapped memory is disabled.
200
+ # The default size is 67108864.
201
+ #
202
+ # Some examples :
203
+ #
204
+ # t = Rufus::Tokyo::Table.new('table.tdb')
205
+ # t = Rufus::Tokyo::Table.new('table.tdb#mode=r')
206
+ # t = Rufus::Tokyo::Table.new('table.tdb', :mode => 'r')
207
+ # t = Rufus::Tokyo::Table.new('table.tdb#opts=ld#mode=r')
208
+ # t = Rufus::Tokyo::Table.new('table.tdb', :opts => 'ld', :mode => 'r')
209
+ #
210
+ def initialize (path, params={})
144
211
 
145
- mode = compute_open_mode(params)
212
+ conf = determine_conf(path, params, '.tdb')
146
213
 
147
214
  @db = lib.tctdbnew
148
215
 
149
- libcall(:tctdbopen, path, mode)
216
+ #
217
+ # tune table
218
+
219
+ libcall(:tctdbsetmutex) if conf[:mutex]
220
+
221
+ libcall(:tctdbtune, conf[:bnum], conf[:apow], conf[:fpow], conf[:opts])
222
+
223
+ # TODO : set indexes here... well, there is already #set_index
224
+ #conf[:indexes]...
225
+
226
+ libcall(:tctdbsetcache, conf[:rcnum], conf[:lcnum], conf[:ncnum])
227
+
228
+ libcall(:tctdbsetxmsiz, conf[:xmsiz])
229
+
230
+ #
231
+ # open table
232
+
233
+ libcall(:tctdbopen, conf[:path], conf[:mode])
150
234
  end
151
235
 
152
236
  #
@@ -245,25 +329,43 @@ module Rufus
245
329
  end
246
330
 
247
331
  #
248
- # Returns the value (as a Ruby Hash) else nil
332
+ # Returns an array of all the primary keys in the table
249
333
  #
250
- # (the actual #[] method is provided by HashMethods)
334
+ # With no options given, this method will return all the keys (strings)
335
+ # in a Ruby array.
251
336
  #
252
- def get (k)
253
- m = lib.tab_get(@db, k, CabinetLib.strlen(k))
254
- return nil if m.address == 0 # :( too bad, but it works
255
- Map.to_h(m) # which frees the map
256
- end
257
- protected :get
258
-
337
+ # :prefix --> returns only the keys who match a given string prefix
259
338
  #
260
- # Returns an array of all the primary keys in the table
339
+ # :limit --> returns a limited number of keys
261
340
  #
262
- def keys
263
- a = []
264
- lib.tab_iterinit(@db)
265
- while (k = (lib.tab_iternext2(@db) rescue nil)); a << k; end
266
- a
341
+ # :native --> returns an instance of Rufus::Tokyo::List instead of
342
+ # a Ruby Hash, you have to call #free on that List when done with it !
343
+ # Else you're exposing yourself to a memory leak.
344
+ #
345
+ def keys (options={})
346
+
347
+ if pref = options[:prefix]
348
+
349
+ l = lib.tab_fwmkeys2(@db, pref, options[:limit] || -1)
350
+ l = Rufus::Tokyo::List.new(l)
351
+ options[:native] ? l : l.release
352
+
353
+ else
354
+
355
+ limit = options[:limit] || -1
356
+ limit = nil if limit < 1
357
+
358
+ l = options[:native] ? Rufus::Tokyo::List.new : []
359
+
360
+ lib.tab_iterinit(@db)
361
+
362
+ while (k = (lib.tab_iternext2(@db) rescue nil))
363
+ break if limit and l.size >= limit
364
+ l << k
365
+ end
366
+
367
+ l
368
+ end
267
369
  end
268
370
 
269
371
  #
@@ -377,6 +479,17 @@ module Rufus
377
479
 
378
480
  protected
379
481
 
482
+ #
483
+ # Returns the value (as a Ruby Hash) else nil
484
+ #
485
+ # (the actual #[] method is provided by HashMethods)
486
+ #
487
+ def get (k)
488
+ m = lib.tab_get(@db, k, CabinetLib.strlen(k))
489
+ return nil if m.address == 0 # :( too bad, but it works
490
+ Map.to_h(m) # which frees the map
491
+ end
492
+
380
493
  def libcall (lib_method, *args)
381
494
 
382
495
  #(lib.send(lib_method, @db, *args) == 1) or raise_error
@@ -179,7 +179,7 @@ module Rufus
179
179
  # (by passing a list pointer, one can wrap an existing list pointer
180
180
  # into a handy instance of this class)
181
181
  #
182
- def initialize (list_pointer = nil)
182
+ def initialize (list_pointer=nil)
183
183
  @list = list_pointer || clib.tclistnew
184
184
  end
185
185
 
@@ -333,6 +333,17 @@ module Rufus
333
333
  alias :free :close
334
334
  alias :destroy :close
335
335
 
336
+ #
337
+ # Closes (frees memory from it) this list and returns the ruby version
338
+ # of it
339
+ #
340
+ def release
341
+
342
+ a = self.to_a
343
+ self.close
344
+ a
345
+ end
346
+
336
347
  protected
337
348
 
338
349
  #
@@ -84,6 +84,8 @@ module Rufus
84
84
  attfunc :abs_sync, :tcrdbsync, [ :pointer ], :int
85
85
  attfunc :abs_copy, :tcrdbcopy, [ :pointer, :string ], :int
86
86
 
87
+ attfunc :abs_fwmkeys2, :tcrdbfwmkeys2, [ :pointer, :string, :int ], :pointer
88
+
87
89
  #
88
90
  # table functions
89
91
 
@@ -111,6 +113,8 @@ module Rufus
111
113
 
112
114
  attfunc :tab_setindex, :tcrdbtblsetindex, [ :pointer, :string, :int ], :int
113
115
 
116
+ attfunc :tab_fwmkeys2, :tcrdbfwmkeys2, [ :pointer, :string, :int ], :pointer
117
+
114
118
  #
115
119
  # qry functions
116
120
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufus-tokyo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-02-16 00:00:00 +09:00
13
+ date: 2009-02-19 00:00:00 +09:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency