rufus-tokyo 0.1.6 → 0.1.7

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.
@@ -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