localmemcache 0.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.
@@ -0,0 +1,61 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '..'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'bacon'
5
+ require 'lmctestapi'
6
+ $a = Alloc.new(1000)
7
+
8
+ Bacon.summary_on_exit
9
+
10
+ describe 'Alloc' do
11
+
12
+ it 'should support basic allocation and freeing of memory' do
13
+ $a.dispose($a.get(100))
14
+ end
15
+
16
+ it 'should merge free chunks' do
17
+ free = $a.free_mem
18
+ v1 = $a.get(100)
19
+ $a.free_mem.should.equal(free - 108)
20
+ v2 = $a.get(100)
21
+ $a.free_mem.should.equal(free - 216)
22
+ $a.free_chunks.should.equal 1
23
+ $a.dispose(v1)
24
+ $a.free_mem.should.equal(free - 108)
25
+ $a.free_chunks.should.equal 2
26
+ $a.dispose(v2)
27
+ $a.free_mem.should.equal free
28
+ $a.free_chunks.should.equal 1
29
+ end
30
+
31
+ it 'should handle memory exhaustion' do
32
+ v1 = $a.get($a.free_mem)
33
+ $a.free_mem.should.equal 0
34
+ $a.free_mem.should.equal 0
35
+ $a.free_mem.should.equal 0
36
+ should.raise(OutOfMemoryError) { $a.get(1) }
37
+ $a.dispose(v1)
38
+ end
39
+
40
+ it 'should manage free memory only if there is enough mem left to hold the struct ' do
41
+ $a.free_chunks.should.equal 1
42
+ v1 = $a.get($a.free_mem - 100)
43
+ $a.free_chunks.should.equal 1
44
+ v2 = $a.get(90)
45
+ $a.dump
46
+ $a.free_chunks.should.equal 0
47
+ $a.dispose(v1)
48
+ $a.dispose(v2)
49
+ end
50
+
51
+ it 'should deal with calling free for already freed items' do
52
+ v = $a.get(90)
53
+ $a.dispose(v)
54
+ $a.dispose(v)
55
+ end
56
+
57
+ it 'should deal with calling free with nasty parameters' do
58
+ $a.dispose(0)
59
+ end
60
+
61
+ end
@@ -0,0 +1,301 @@
1
+ # Bacon -- small RSpec clone.
2
+ #
3
+ # "Truth will sooner come out from error than from confusion." ---Francis Bacon
4
+
5
+ # Copyright (C) 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>
6
+ #
7
+ # Bacon is freely distributable under the terms of an MIT-style license.
8
+ # See COPYING or http://www.opensource.org/licenses/mit-license.php.
9
+
10
+ module Bacon
11
+ VERSION = "0.9"
12
+
13
+ Counter = Hash.new(0)
14
+ ErrorLog = ""
15
+ Shared = Hash.new { |_, name|
16
+ raise NameError, "no such context: #{name.inspect}"
17
+ }
18
+
19
+ RestrictName = // unless defined? RestrictName
20
+ RestrictContext = // unless defined? RestrictContext
21
+
22
+ def self.summary_on_exit
23
+ return if Counter[:installed_summary] > 0
24
+ at_exit {
25
+ handle_summary
26
+ if $!
27
+ raise $!
28
+ elsif Counter[:errors] + Counter[:failed] > 0
29
+ exit 1
30
+ end
31
+ }
32
+ Counter[:installed_summary] += 1
33
+ end
34
+
35
+ module SpecDoxOutput
36
+ def handle_specification(name)
37
+ puts name
38
+ yield
39
+ puts
40
+ end
41
+
42
+ def handle_requirement(description)
43
+ print "- #{description}"
44
+ error = yield
45
+ puts error.empty? ? "" : " [#{error}]"
46
+ end
47
+
48
+ def handle_summary
49
+ print ErrorLog
50
+ puts "%d specifications (%d requirements), %d failures, %d errors" %
51
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
52
+ end
53
+ end
54
+
55
+ module TestUnitOutput
56
+ def handle_specification(name) yield end
57
+
58
+ def handle_requirement(description)
59
+ error = yield
60
+ if error.empty?
61
+ print "."
62
+ else
63
+ print error[0..0]
64
+ end
65
+ end
66
+
67
+ def handle_summary
68
+ puts "", ErrorLog
69
+ puts "%d tests, %d assertions, %d failures, %d errors" %
70
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
71
+ end
72
+ end
73
+
74
+ module TapOutput
75
+ def handle_specification(name) yield end
76
+
77
+ def handle_requirement(description)
78
+ ErrorLog.replace ""
79
+ error = yield
80
+ if error.empty?
81
+ printf "ok %-3d - %s\n" % [Counter[:specifications], description]
82
+ else
83
+ printf "not ok %d - %s: %s\n" %
84
+ [Counter[:specifications], description, error]
85
+ puts ErrorLog.strip.gsub(/^/, '# ')
86
+ end
87
+ end
88
+
89
+ def handle_summary
90
+ puts "1..#{Counter[:specifications]}"
91
+ puts "# %d tests, %d assertions, %d failures, %d errors" %
92
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
93
+ end
94
+ end
95
+
96
+ extend SpecDoxOutput # default
97
+
98
+ class Error < RuntimeError
99
+ attr_accessor :count_as
100
+
101
+ def initialize(count_as, message)
102
+ @count_as = count_as
103
+ super message
104
+ end
105
+ end
106
+
107
+ class Context
108
+ def initialize(name, &block)
109
+ @name = name
110
+ @before, @after = [], []
111
+
112
+ return unless name =~ RestrictContext
113
+ Bacon.handle_specification(name) { instance_eval(&block) }
114
+ end
115
+
116
+ def before(&block); @before << block; end
117
+ def after(&block); @after << block; end
118
+
119
+ def behaves_like(*names)
120
+ names.each { |name| instance_eval(&Shared[name]) }
121
+ end
122
+
123
+ def it(description, &block)
124
+ return unless description =~ RestrictName
125
+ Counter[:specifications] += 1
126
+ run_requirement description, block
127
+ end
128
+
129
+ def run_requirement(description, spec)
130
+ Bacon.handle_requirement description do
131
+ begin
132
+ Counter[:depth] += 1
133
+ @before.each { |block| instance_eval(&block) }
134
+ instance_eval(&spec)
135
+ rescue Object => e
136
+ ErrorLog << "#{e.class}: #{e.message}\n"
137
+ e.backtrace.find_all { |line| line !~ /bin\/bacon|\/bacon\.rb:\d+/ }.
138
+ each_with_index { |line, i|
139
+ ErrorLog << "\t#{line}#{i==0 ? ": #@name - #{description}" : ""}\n"
140
+ }
141
+ ErrorLog << "\n"
142
+
143
+ if e.kind_of? Error
144
+ Counter[e.count_as] += 1
145
+ e.count_as.to_s.upcase
146
+ else
147
+ Counter[:errors] += 1
148
+ "ERROR: #{e.class}"
149
+ end
150
+ else
151
+ ""
152
+ ensure
153
+ begin
154
+ @after.each { |block| instance_eval(&block) }
155
+ rescue
156
+ end
157
+ Counter[:depth] -= 1
158
+ end
159
+ end
160
+ end
161
+
162
+ def raise?(*args, &block); block.raise?(*args); end
163
+ def throw?(*args, &block); block.throw?(*args); end
164
+ def change?(*args, &block); block.change?(*args); end
165
+ end
166
+ end
167
+
168
+
169
+ class Object
170
+ def true?; false; end
171
+ def false?; false; end
172
+ end
173
+
174
+ class TrueClass
175
+ def true?; true; end
176
+ end
177
+
178
+ class FalseClass
179
+ def false?; true; end
180
+ end
181
+
182
+ class Proc
183
+ def raise?(*exceptions)
184
+ exceptions << RuntimeError if exceptions.empty?
185
+ call
186
+
187
+ # Only to work in 1.9.0, rescue with splat doesn't work there right now
188
+ rescue Object => e
189
+ case e
190
+ when *exceptions
191
+ e
192
+ else
193
+ raise e
194
+ end
195
+ else
196
+ false
197
+ end
198
+
199
+ def throw?(sym)
200
+ catch(sym) {
201
+ call
202
+ return false
203
+ }
204
+ return true
205
+ end
206
+
207
+ def change?
208
+ pre_result = yield
209
+ called = call
210
+ post_result = yield
211
+ pre_result != post_result
212
+ end
213
+ end
214
+
215
+ class Numeric
216
+ def close?(to, delta)
217
+ (to.to_f - self).abs <= delta.to_f rescue false
218
+ end
219
+ end
220
+
221
+
222
+ class Object
223
+ def should(*args, &block) Should.new(self).be(*args, &block) end
224
+ end
225
+
226
+ module Kernel
227
+ private
228
+
229
+ def describe(name, &block) Bacon::Context.new(name, &block) end
230
+ def shared(name, &block) Bacon::Shared[name] = block end
231
+ end
232
+
233
+
234
+ class Should
235
+ # Kills ==, ===, =~, eql?, equal?, frozen?, instance_of?, is_a?,
236
+ # kind_of?, nil?, respond_to?, tainted?
237
+ instance_methods.each { |method|
238
+ undef_method method if method =~ /\?|^\W+$/
239
+ }
240
+
241
+ def initialize(object)
242
+ @object = object
243
+ @negated = false
244
+ end
245
+
246
+ def not(*args, &block)
247
+ @negated = !@negated
248
+
249
+ if args.empty?
250
+ self
251
+ else
252
+ be(*args, &block)
253
+ end
254
+ end
255
+
256
+ def be(*args, &block)
257
+ if args.empty?
258
+ self
259
+ else
260
+ block = args.shift unless block_given?
261
+ satisfy(*args, &block)
262
+ end
263
+ end
264
+
265
+ alias a be
266
+ alias an be
267
+
268
+ def satisfy(*args, &block)
269
+ if args.size == 1 && String === args.first
270
+ description = args.shift
271
+ else
272
+ description = ""
273
+ end
274
+
275
+ r = yield(@object, *args)
276
+ if Bacon::Counter[:depth] > 0
277
+ raise Bacon::Error.new(:failed, description) unless @negated ^ r
278
+ Bacon::Counter[:requirements] += 1
279
+ end
280
+ @negated ^ r ? r : false
281
+ end
282
+
283
+ def method_missing(name, *args, &block)
284
+ name = "#{name}?" if name.to_s =~ /\w[^?]\z/
285
+
286
+ desc = @negated ? "not " : ""
287
+ desc << @object.inspect << "." << name.to_s
288
+ desc << "(" << args.map{|x|x.inspect}.join(", ") << ") failed"
289
+
290
+ satisfy(desc) { |x| x.__send__(name, *args, &block) }
291
+ end
292
+
293
+ def equal(value) self == value end
294
+ def match(value) self =~ value end
295
+ def identical_to(value) self.equal? value end
296
+ alias same_as identical_to
297
+
298
+ def flunk(reason="Flunked")
299
+ raise Bacon::Error.new(:failed, reason)
300
+ end
301
+ end
data/src/tests/bench ADDED
@@ -0,0 +1,11 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/bench.rb
5
+
6
+ if test "x$1" = "x-d"; then
7
+ irb -r $script
8
+ else
9
+ #valgrind --leak-check=full --tool=memcheck ruby $script
10
+ ruby $script
11
+ fi
@@ -0,0 +1,46 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '..', '../ruby-binding/'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'bacon'
5
+ require 'localmemcache'
6
+
7
+ Bacon.summary_on_exit
8
+
9
+ LocalMemCache.clear_namespace("speed-comparison");
10
+ $lm2 = LocalMemCache.new :namespace=>"speed-comparison"
11
+
12
+ def compare_speed(n)
13
+
14
+ puts "LocalMemCache"
15
+ measure_time(n) {
16
+ r = rand(10000).to_s
17
+ $lm2.set(r, r)
18
+ $lm2.get(r)
19
+ }
20
+
21
+ puts "builtin"
22
+ $hh = {}
23
+ measure_time(n) {
24
+ r = rand(10000).to_s
25
+ $hh[r] = r
26
+ $hh[r]
27
+ }
28
+ end
29
+
30
+ def measure_time(c, &block)
31
+ _then = Time.now
32
+ c.times { block.call }
33
+ now = Time.now
34
+ puts "#{(now - _then)*1000} ms"
35
+ end
36
+
37
+ compare_speed(2_000_000)
38
+
39
+ #$stdout.write "ht shm setting x 20000: "
40
+ #tmeasure (2_000_000) {
41
+ # v = $lm2.get("f").to_i + 1
42
+ # #puts "v:#{v}"
43
+ # $lm2.set("f", v)
44
+ #}
45
+ #puts "foo: #{$lm2.get("f")}"
46
+
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ dir = File.dirname(__FILE__)
4
+
5
+ $defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
6
+
7
+ $srcs = ['lmctestapi.c']
8
+ $objs = ['lmctestapi.o']
9
+
10
+ $CFLAGS << " -D_REENTRANT -g -I .."
11
+ $LDFLAGS << " ../liblmc.a -lpthread -lrt"
12
+
13
+ dir_config('lmctestapi')
14
+ create_makefile('lmctestapi')
data/src/tests/lmc ADDED
@@ -0,0 +1,11 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/lmc.rb
5
+
6
+ if test "x$1" = "x-d"; then
7
+ irb -r $script
8
+ else
9
+ #valgrind --leak-check=full --tool=memcheck ruby $script
10
+ ruby $script
11
+ fi
data/src/tests/lmc.rb ADDED
@@ -0,0 +1,85 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '..', '../ruby-binding/'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'bacon'
5
+ require 'localmemcache'
6
+
7
+ Bacon.summary_on_exit
8
+
9
+ $lm = LocalMemCache.new :namespace=>"testing"
10
+
11
+ describe 'LocalMemCache' do
12
+
13
+ it 'should allow to set and query keys' do
14
+ $lm.get("non-existant").should.be.nil
15
+ $lm.set("foo", "1")
16
+ $lm.get("foo").should.equal "1"
17
+ end
18
+
19
+ it 'should support the [] and []= operators' do
20
+ $lm["boo"] = "2"
21
+ $lm["boo"].should.equal "2"
22
+ end
23
+
24
+ it 'should allow deletion of keys' do
25
+ $lm["deleteme"] = "blah"
26
+ $lm["deleteme"].should.not.be.nil
27
+ $lm.delete("deleteme")
28
+ $lm["deleteme"].should.be.nil
29
+ $lm.delete("non-existant")
30
+ end
31
+
32
+ #it 'should support iteration' do
33
+ # puts "TBD"
34
+ #end
35
+
36
+ it 'should support clearing of namespaces' do
37
+ LocalMemCache.clear_namespace("testing");
38
+ end
39
+
40
+ end
41
+
42
+ def tmeasure(c, &block)
43
+ _then = Time.now
44
+ c.times { block.call }
45
+ now = Time.now
46
+ puts "#{(now - _then)*1000} ms"
47
+ end
48
+
49
+ $lm2 = LocalMemCache.new :namespace=>"speed-comparison"
50
+
51
+ def compare_speed(n)
52
+
53
+ puts "LocalMemCache"
54
+ tmeasure(n) {
55
+ r = rand(10000).to_s
56
+ # $lm2.get(r)
57
+ $lm2.set(r, r)
58
+ # nr = $lm2.get(r)
59
+ # if nr != r
60
+ # $stderr.puts "FAILED: #{nr.inspect} != #{r.inspect}"
61
+ # end
62
+ }
63
+
64
+ puts "builtin"
65
+ $hh = {}
66
+ tmeasure(n) {
67
+ r = rand(10000).to_s
68
+ # $hh[r]
69
+ $hh[r] = r
70
+ # if $hh[r] != r
71
+ # $stderr.puts "FAILED!"
72
+ # end
73
+ }
74
+ end
75
+
76
+ compare_speed(2_000_000)
77
+
78
+ #$stdout.write "ht shm setting x 20000: "
79
+ #tmeasure (2_000_000) {
80
+ # v = $lm2.get("f").to_i + 1
81
+ # #puts "v:#{v}"
82
+ # $lm2.set("f", v)
83
+ #}
84
+ #puts "foo: #{$lm2.get("f")}"
85
+
@@ -0,0 +1,162 @@
1
+ /*
2
+ * Copyright (C) 2009, Sven C. Koehler
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include "lmc_shm.h"
7
+ #include "lmc_hashtable.h"
8
+ #include "lmc_valloc.h"
9
+
10
+ void *memp = NULL;
11
+ static VALUE OutOfMemoryError;
12
+
13
+ long long_value(VALUE i) { return NUM2LONG(rb_Integer(i)); }
14
+ VALUE num2string(long i) { return rb_big2str(rb_int2big(i), 10); }
15
+ char *rstring_ptr(VALUE s) {
16
+ char* r = NIL_P(s) ? "nil" : RSTRING_PTR(rb_String(s));
17
+ return r ? r : "nil";
18
+ }
19
+ static VALUE ruby_string(char *s) { return s ? rb_str_new2(s) : Qnil; }
20
+
21
+ static VALUE Alloc__new(VALUE klass, VALUE size) {
22
+ size_t s = long_value(size);
23
+ memp = malloc(s);
24
+ #ifdef DEBUG_ALLOC
25
+ printf("memp: %0x, end: %0x\n", memp, memp+s);
26
+ memset(memp, 0xF0, s);
27
+ #endif
28
+ lmc_init_memory(memp, s);
29
+ return rb_class_new_instance(0, NULL, klass);
30
+ }
31
+
32
+ static VALUE Alloc__get(VALUE obj, VALUE size) {
33
+ size_t va = lmc_valloc(memp, long_value(size));
34
+ if (!va) { rb_raise(OutOfMemoryError, "Out of memory"); }
35
+ size_t v = long_value(size);
36
+ #ifdef DEBUG_ALLOC
37
+ memset(memp + va, va, v);
38
+ #endif
39
+ return rb_int2big(va);
40
+ }
41
+
42
+ static VALUE Alloc__dispose(VALUE obj, VALUE adr) {
43
+ lmc_free(memp, long_value(adr));
44
+ return Qnil;
45
+ }
46
+
47
+ static VALUE Alloc__dump(VALUE obj) {
48
+ lmc_dump(memp);
49
+ return Qnil;
50
+ }
51
+
52
+ static VALUE Alloc__free_mem(VALUE obj) {
53
+ return rb_int2inum(lmc_status(memp, "f").free_mem);
54
+ }
55
+
56
+ static VALUE Alloc__largest_chunk(VALUE obj) {
57
+ return rb_int2inum(lmc_status(memp, "lc").largest_chunk);
58
+ }
59
+
60
+ static VALUE Alloc__free_chunks(VALUE obj) {
61
+ return rb_int2inum(lmc_status(memp, "fc").free_chunks);
62
+ }
63
+
64
+ static VALUE SHMError;
65
+
66
+ static lmc_shm_t* get_Shm(VALUE obj) {
67
+ lmc_shm_t *ls;
68
+ Data_Get_Struct(obj, lmc_shm_t, ls);
69
+ if (ls == NULL) { rb_raise(SHMError, "Not active"); }
70
+ return ls;
71
+ }
72
+
73
+ static VALUE SHM__new(VALUE klass, VALUE namespace) {
74
+ Check_Type(namespace, T_STRING);
75
+ lmc_shm_t *ls = lmc_shm_create("test2", 2000000, 0, 0);
76
+ return Data_Wrap_Struct(klass, NULL, lmc_shm_destroy, ls);
77
+ }
78
+
79
+ static VALUE SHM__close(VALUE obj) {
80
+ lmc_shm_destroy(get_Shm(obj), 0);
81
+ DATA_PTR(obj) = NULL;
82
+ return Qnil;
83
+ }
84
+
85
+ static VALUE SHM__get(VALUE obj, VALUE id) {
86
+ return num2string(((int *)get_Shm(obj)->base)[long_value(id)]);
87
+ }
88
+
89
+ static VALUE SHM__set(VALUE obj, VALUE id, VALUE value) {
90
+ ((int *)get_Shm(obj)->base)[long_value(id)] = long_value(value);
91
+ return Qnil;
92
+ }
93
+
94
+ //typedef struct {
95
+ // va_ht_hash_t va;
96
+ // mem_cache_t *mc;
97
+ // lmc_lock_t *ll;
98
+ //} ht_desc_t;
99
+ //
100
+ //static VALUE Hashtable__new(VALUE klass) {
101
+ // lmc_lock_obtain("Hashtable__new");
102
+ // size_t s = 20401094656;
103
+ // lmc_lock_t *ll = lmc_lock_init("test11");
104
+ // mem_cache_t *mc = local_mem_cache_create(s); // namespace?
105
+ // lmc_init_memory(mc->shm, s);
106
+ // va_ht_hash_t va_ht = ht_hash_create(mc->shm);
107
+ // ht_desc_t* ht = malloc(sizeof(ht_desc_t));
108
+ // ht->va = va_ht;
109
+ // ht->mc = mc;
110
+ // ht->ll = ll;
111
+ // lmc_lock_release("Hashtable__new");
112
+ // return Data_Wrap_Struct(klass, NULL, NULL, ht);
113
+ //}
114
+ //
115
+ //ht_desc_t *get_Hashtable(VALUE obj) {
116
+ // ht_desc_t *ht;
117
+ // Data_Get_Struct(obj, ht_desc_t, ht);
118
+ // return ht;
119
+ //}
120
+ //
121
+ //static VALUE Hashtable__get(VALUE obj, VALUE key) {
122
+ // ht_desc_t *ht = get_Hashtable(obj);
123
+ // return ruby_string(ht_get(ht->mc->shm, ht->va, rstring_ptr(key)));
124
+ //}
125
+ //
126
+ //static VALUE Hashtable__set(VALUE obj, VALUE key, VALUE value) {
127
+ // ht_desc_t *ht = get_Hashtable(obj);
128
+ // ht_set(ht->mc->shm, ht->va, rstring_ptr(key), rstring_ptr(value));
129
+ // return Qnil;
130
+ //}
131
+
132
+ static VALUE Alloc;
133
+ static VALUE SHM;
134
+ //static VALUE Hashtable;
135
+
136
+ #include <stdio.h>
137
+ #include <fcntl.h>
138
+ #include <sys/stat.h>
139
+ #include <sys/mman.h>
140
+
141
+ void Init_lmctestapi() {
142
+ OutOfMemoryError = rb_define_class("OutOfMemoryError", rb_eStandardError);
143
+ Alloc = rb_define_class("Alloc", rb_cObject);
144
+ rb_define_singleton_method(Alloc, "new", Alloc__new, 1);
145
+ rb_define_method(Alloc, "get", Alloc__get, 1);
146
+ rb_define_method(Alloc, "dispose", Alloc__dispose, 1);
147
+ rb_define_method(Alloc, "dump", Alloc__dump, 0);
148
+ rb_define_method(Alloc, "free_mem", Alloc__free_mem, 0);
149
+ rb_define_method(Alloc, "largest_chunk", Alloc__largest_chunk, 0);
150
+ rb_define_method(Alloc, "free_chunks", Alloc__free_chunks, 0);
151
+
152
+ SHM = rb_define_class("SHM", rb_cObject);
153
+ rb_define_singleton_method(SHM, "new", SHM__new, 1);
154
+ rb_define_method(SHM, "get", SHM__get, 1);
155
+ rb_define_method(SHM, "set", SHM__set, 2);
156
+ rb_define_method(SHM, "close", SHM__close, 0);
157
+
158
+ //Hashtable = rb_define_class("Hashtable", rb_cObject);
159
+ //rb_define_singleton_method(Hashtable, "new", Hashtable__new, 0);
160
+ //rb_define_method(Hashtable, "get", Hashtable__get, 1);
161
+ //rb_define_method(Hashtable, "set", Hashtable__set, 2);
162
+ }
@@ -0,0 +1,9 @@
1
+ #! /bin/sh
2
+ cd `dirname $0`
3
+
4
+ test -f Makefile || ruby extconf.rb
5
+ test -f mctestapi.so || make
6
+ make clean
7
+ make
8
+ ./hashtable
9
+