memcached 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,23 +1,24 @@
1
1
 
2
- require 'libmemcached'
2
+ require 'rlibmemcached'
3
3
  require 'memcached/integer'
4
4
  require 'memcached/exceptions'
5
5
  require 'memcached/behaviors'
6
6
  require 'memcached/memcached'
7
+ require 'memcached/rails'
7
8
 
8
9
  =begin rdoc
9
10
  The generated SWIG module for accessing libmemcached's C API.
10
11
 
11
12
  Includes the full set of libmemcached static methods (as defined in <tt>$INCLUDE_PATH/libmemcached/memcached.h</tt>), and classes for the available structs:
12
13
 
13
- * Libmemcached::MemcachedResultSt
14
- * Libmemcached::MemcachedServerSt
15
- * Libmemcached::MemcachedSt
16
- * Libmemcached::MemcachedStatSt
17
- * Libmemcached::MemcachedStringSt
14
+ * <b>Rlibmemcached::MemcachedResultSt</b>
15
+ * <b>Rlibmemcached::MemcachedServerSt</b>
16
+ * <b>Rlibmemcached::MemcachedSt</b>
17
+ * <b>Rlibmemcached::MemcachedStatSt</b>
18
+ * <b>Rlibmemcached::MemcachedStringSt</b>
18
19
 
19
20
  A number of SWIG typemaps and C helper methods are also defined in <tt>ext/libmemcached.i</tt>.
20
21
 
21
22
  =end
22
- module Libmemcached
23
+ module Rlibmemcached
23
24
  end
@@ -4,8 +4,8 @@ class Memcached
4
4
  #:stopdoc:
5
5
 
6
6
  def self.load_constants(prefix, hash = {}, offset = 0)
7
- Libmemcached.constants.grep(/^#{prefix}/).each do |const_name|
8
- hash[const_name[prefix.length..-1].downcase.to_sym] = Libmemcached.const_get(const_name) + offset
7
+ Rlibmemcached.constants.grep(/^#{prefix}/).each do |const_name|
8
+ hash[const_name[prefix.length..-1].downcase.to_sym] = Rlibmemcached.const_get(const_name) + offset
9
9
  end
10
10
  hash
11
11
  end
@@ -42,8 +42,8 @@ class Memcached
42
42
  # STDERR.puts "Setting #{behavior}:#{b_id} => #{value}:#{v_id}"
43
43
 
44
44
  unless value == false
45
- # XXX Setting false still turns on the behavior; maybe a Libmemcached bug
46
- Libmemcached.memcached_behavior_set(@struct, b_id, v_id)
45
+ # XXX Setting false still turns on the behavior; maybe a Rlibmemcached bug
46
+ Rlibmemcached.memcached_behavior_set(@struct, b_id, v_id)
47
47
  end
48
48
 
49
49
  end
@@ -44,6 +44,9 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
44
44
  class Error < RuntimeError
45
45
  end
46
46
 
47
+ class SynchronizationError < RuntimeError
48
+ end
49
+
47
50
  # Raised if a method depends on functionality not yet completed in libmemcached.
48
51
  class NotImplemented < NoMethodError
49
52
  end
@@ -58,12 +61,12 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
58
61
  end
59
62
 
60
63
  EXCEPTIONS = []
61
- EMPTY_STRUCT = Libmemcached::MemcachedSt.new
62
- Libmemcached.memcached_create(EMPTY_STRUCT)
64
+ EMPTY_STRUCT = Rlibmemcached::MemcachedSt.new
65
+ Rlibmemcached.memcached_create(EMPTY_STRUCT)
63
66
 
64
67
  # Generate exception classes
65
- Libmemcached::MEMCACHED_MAXIMUM_RETURN.times do |index|
66
- description = Libmemcached.memcached_strerror(EMPTY_STRUCT, index)
68
+ Rlibmemcached::MEMCACHED_MAXIMUM_RETURN.times do |index|
69
+ description = Rlibmemcached.memcached_strerror(EMPTY_STRUCT, index)
67
70
  exception_class = eval("class #{camelize(description)} < Error; self; end")
68
71
  EXCEPTIONS << exception_class
69
72
  end
@@ -16,7 +16,11 @@ class Memcached
16
16
  :namespace => nil
17
17
  }
18
18
 
19
- IGNORED = 0 #:nodoc:
19
+ #:stopdoc:
20
+ IGNORED = 0
21
+
22
+ NOTFOUND_INSTANCE = NotFound.new
23
+ #:startdoc:
20
24
 
21
25
  attr_reader :options # Return the options Hash used to configure this instance.
22
26
 
@@ -42,8 +46,8 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
42
46
  =end
43
47
 
44
48
  def initialize(servers, opts = {})
45
- @struct = Libmemcached::MemcachedSt.new
46
- Libmemcached.memcached_create(@struct)
49
+ @struct = Rlibmemcached::MemcachedSt.new
50
+ Rlibmemcached.memcached_create(@struct)
47
51
 
48
52
  # Servers
49
53
  Array(servers).each_with_index do |server, index|
@@ -51,12 +55,7 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
51
55
  raise ArgumentError, "Servers must be in the format ip:port (e.g., '127.0.0.1:11211')"
52
56
  end
53
57
  host, port = server.split(":")
54
- Libmemcached.memcached_server_add(@struct, host, port.to_i)
55
-
56
- # XXX To be removed once Krow fixes the write_ptr bug
57
- Libmemcached.memcached_repair_server_st(@struct,
58
- Libmemcached.memcached_select_server_at(@struct, index)
59
- )
58
+ Rlibmemcached.memcached_server_add(@struct, host, port.to_i)
60
59
  end
61
60
 
62
61
  # Behaviors
@@ -73,12 +72,11 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
73
72
 
74
73
  # Namespace
75
74
  raise ArgumentError, "Invalid namespace" if options[:namespace].to_s =~ / /
76
- @namespace = options[:namespace]
75
+ @namespace = options[:namespace].to_s
76
+ @namespace_size = @namespace.size
77
77
  end
78
78
 
79
- =begin rdoc
80
- Return the array of server strings used to configure this instance.
81
- =end
79
+ # Return the array of server strings used to configure this instance.
82
80
  def servers
83
81
  server_structs.map do |server|
84
82
  "#{server.hostname}:#{server.port}"
@@ -87,12 +85,34 @@ Return the array of server strings used to configure this instance.
87
85
 
88
86
  # Safely copy this instance. Returns a Memcached instance.
89
87
  #
90
- # <tt>clone</tt> is useful for threading, since each thread must have its own unshared Memcached object.
88
+ # <tt>clone</tt> is useful for threading, since each thread must have its own unshared Memcached
89
+ # object. However, you must call destroy before each thread returns or you will leak significant memory.
90
+ #
91
91
  def clone
92
- # XXX Could be more efficient if we used Libmemcached.memcached_clone(@struct)
93
- self.class.new(servers, options)
92
+ memcached = super
93
+ memcached.instance_variable_set('@struct', Rlibmemcached.memcached_clone(nil, @struct))
94
+ memcached
94
95
  end
95
96
 
97
+ # Destroy this instance. Frees memory associated with the C implementation.
98
+ #
99
+ # Accepts an optional parameter <tt>disable_methods</tt>. When <tt>false</tt>, destroy
100
+ # runs much faster, but your instance will segfault if you try to call any other methods on it
101
+ # after destroy. Defaults to <tt>true</tt>, which safely overwrites all instance methods.
102
+ def destroy(disable_methods = true)
103
+ Rlibmemcached.memcached_free(@struct)
104
+ @struct = nil
105
+ if disable_methods
106
+ class << self
107
+ Memcached.instance_methods.each do |method_name|
108
+ define_method method_name do |*args|
109
+ raise Memcached::ClientError, "Instance has been explicitly destroyed"
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+
96
116
  #:stopdoc:
97
117
  alias :dup :clone #:nodoc:
98
118
  #:startdoc:
@@ -105,7 +125,7 @@ Return the array of server strings used to configure this instance.
105
125
  def server_structs
106
126
  array = []
107
127
  @struct.hosts.count.times do |i|
108
- array << Libmemcached.memcached_select_server_at(@struct, i)
128
+ array << Rlibmemcached.memcached_select_server_at(@struct, i)
109
129
  end
110
130
  array
111
131
  end
@@ -118,14 +138,14 @@ Return the array of server strings used to configure this instance.
118
138
 
119
139
  # Set a key/value pair. Accepts a String <tt>key</tt> and an arbitrary Ruby object. Overwrites any existing value on the server.
120
140
  #
121
- # Accepts an optional <tt>timeout</tt> value to specify the maximum lifetime of the key on the server. <tt>timeout</tt> can be either an integer number of seconds, or a Time elapsed time object. (There is no guarantee that the key will persist as long as the <tt>timeout</tt>, but it will not persist longer.)
141
+ # Accepts an optional <tt>timeout</tt> value to specify the maximum lifetime of the key on the server. <tt>timeout</tt> can be either an integer number of seconds, or a Time elapsed time object. <tt>0</tt> means no timeout. Note that there is no guarantee that the key will persist as long as the <tt>timeout</tt>, but it will not persist longer.
122
142
  #
123
143
  # Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be set directly.
124
144
  #
125
145
  def set(key, value, timeout=0, marshal=true)
126
146
  value = marshal ? Marshal.dump(value) : value.to_s
127
147
  check_return_code(
128
- Libmemcached.memcached_set(@struct, ns(key), value, timeout, FLAGS)
148
+ Rlibmemcached.memcached_set(@struct, ns(key), value, timeout, FLAGS)
129
149
  )
130
150
  end
131
151
 
@@ -133,7 +153,7 @@ Return the array of server strings used to configure this instance.
133
153
  def add(key, value, timeout=0, marshal=true)
134
154
  value = marshal ? Marshal.dump(value) : value.to_s
135
155
  check_return_code(
136
- Libmemcached.memcached_add(@struct, ns(key), value, timeout, FLAGS)
156
+ Rlibmemcached.memcached_add(@struct, ns(key), value, timeout, FLAGS)
137
157
  )
138
158
  end
139
159
 
@@ -143,14 +163,14 @@ Return the array of server strings used to configure this instance.
143
163
  #
144
164
  # Note that the key must be initialized to an unmarshalled integer first, via <tt>set</tt>, <tt>add</tt>, or <tt>replace</tt> with <tt>marshal</tt> set to <tt>false</tt>.
145
165
  def increment(key, offset=1)
146
- ret, value = Libmemcached.memcached_increment(@struct, ns(key), offset)
166
+ ret, value = Rlibmemcached.memcached_increment(@struct, ns(key), offset)
147
167
  check_return_code(ret)
148
168
  value
149
169
  end
150
170
 
151
171
  # Decrement a key's value. The parameters and exception behavior are the same as <tt>increment</tt>.
152
172
  def decrement(key, offset=1)
153
- ret, value = Libmemcached.memcached_decrement(@struct, ns(key), offset)
173
+ ret, value = Rlibmemcached.memcached_decrement(@struct, ns(key), offset)
154
174
  check_return_code(ret)
155
175
  value
156
176
  end
@@ -164,7 +184,7 @@ Return the array of server strings used to configure this instance.
164
184
  def replace(key, value, timeout=0, marshal=true)
165
185
  value = marshal ? Marshal.dump(value) : value.to_s
166
186
  check_return_code(
167
- Libmemcached.memcached_replace(@struct, ns(key), value, timeout, FLAGS)
187
+ Rlibmemcached.memcached_replace(@struct, ns(key), value, timeout, FLAGS)
168
188
  )
169
189
  end
170
190
 
@@ -174,7 +194,7 @@ Return the array of server strings used to configure this instance.
174
194
  def append(key, value)
175
195
  # Requires memcached 1.2.4
176
196
  check_return_code(
177
- Libmemcached.memcached_append(@struct, ns(key), value.to_s, IGNORED, FLAGS)
197
+ Rlibmemcached.memcached_append(@struct, ns(key), value.to_s, IGNORED, FLAGS)
178
198
  )
179
199
  end
180
200
 
@@ -182,7 +202,7 @@ Return the array of server strings used to configure this instance.
182
202
  def prepend(key, value)
183
203
  # Requires memcached 1.2.4
184
204
  check_return_code(
185
- Libmemcached.memcached_prepend(@struct, ns(key), value.to_s, IGNORED, FLAGS)
205
+ Rlibmemcached.memcached_prepend(@struct, ns(key), value.to_s, IGNORED, FLAGS)
186
206
  )
187
207
  end
188
208
 
@@ -204,7 +224,7 @@ Return the array of server strings used to configure this instance.
204
224
  # Deletes a key/value pair from the server. Accepts a String <tt>key</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist.
205
225
  def delete(key)
206
226
  check_return_code(
207
- Libmemcached.memcached_delete(@struct, ns(key), IGNORED)
227
+ Rlibmemcached.memcached_delete(@struct, ns(key), IGNORED)
208
228
  )
209
229
  end
210
230
 
@@ -214,30 +234,36 @@ Return the array of server strings used to configure this instance.
214
234
  #
215
235
  # Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be returned directly as a String. Otherwise it will be assumed to be a marshalled Ruby object and unmarshalled.
216
236
  #
217
- # If you pass a single key, and the key does not exist on the server, <b>Memcached::NotFound</b> will be raised. If you pass an array of keys, memcached's <tt>multiget</tt> mode will be used, and an array of values will be returned. Missing values in the array will be represented as instances of <b>Memcached::NotFound</b>. This behavior may change in the future.
237
+ # If you pass a String key, and the key does not exist on the server, <b>Memcached::NotFound</b> will be raised. If you pass an array of keys, memcached's <tt>multiget</tt> mode will be used, and a hash of key/value pairs will be returned. The hash will contain only the keys that were found.
238
+ #
239
+ # The multiget behavior is subject to change in the future; however, for multiple lookups, it is much faster than normal mode.
218
240
  #
219
- def get(key, marshal=true)
220
- # XXX Could be faster if it didn't have to branch on the key type
221
- if key.is_a? Array
241
+ # Note that when you rescue Memcached::NotFound exceptions, you should use a the block rescue syntax instead of the inline syntax. Block rescues are very fast, but inline rescues are very slow.
242
+ #
243
+ def get(keys, marshal=true)
244
+ if keys.is_a? Array
222
245
  # Multi get
223
- # XXX Waiting on the real implementation
224
- key.map do |this_key|
225
- begin
226
- get(this_key, marshal)
227
- rescue NotFound => e
228
- e
229
- end
246
+ keys.map! { |key| ns(key) }
247
+ hash = {}
248
+
249
+ Rlibmemcached.memcached_mget(@struct, keys);
250
+
251
+ keys.size.times do
252
+ value, key, flags, ret = Rlibmemcached.memcached_fetch_rvalue(@struct)
253
+ break if ret == Rlibmemcached::MEMCACHED_END
254
+ check_return_code(ret)
255
+ value = Marshal.load(value) if marshal
256
+ # Assign the value, removing the namespace, if present
257
+ hash[key[@namespace_size..-1]] = value
230
258
  end
259
+ hash
231
260
  else
232
261
  # Single get
233
- # XXX Server doesn't validate keys. Regex is possibly a performance problem.
234
- raise ClientError, "Invalid key" if key =~ /\s/
235
-
236
- value, flags, ret = Libmemcached.memcached_get_ruby_string(@struct, ns(key))
262
+ value, flags, ret = Rlibmemcached.memcached_get_rvalue(@struct, ns(keys))
237
263
  check_return_code(ret)
238
264
  value = Marshal.load(value) if marshal
239
265
  value
240
- end
266
+ end
241
267
  end
242
268
 
243
269
  ### Information methods
@@ -246,18 +272,18 @@ Return the array of server strings used to configure this instance.
246
272
  def stats
247
273
  stats = Hash.new([])
248
274
 
249
- stat_struct, ret = Libmemcached.memcached_stat(@struct, "")
275
+ stat_struct, ret = Rlibmemcached.memcached_stat(@struct, "")
250
276
  check_return_code(ret)
251
277
 
252
- keys, ret = Libmemcached.memcached_stat_get_keys(@struct, stat_struct)
278
+ keys, ret = Rlibmemcached.memcached_stat_get_keys(@struct, stat_struct)
253
279
  check_return_code(ret)
254
280
 
255
281
  keys.each do |key|
256
282
  server_structs.size.times do |index|
257
283
 
258
- value, ret = Libmemcached.memcached_stat_get_value(
284
+ value, ret = Rlibmemcached.memcached_stat_get_rvalue(
259
285
  @struct,
260
- Libmemcached.memcached_select_stat_at(@struct, stat_struct, index),
286
+ Rlibmemcached.memcached_select_stat_at(@struct, stat_struct, index),
261
287
  key)
262
288
  check_return_code(ret)
263
289
 
@@ -271,7 +297,7 @@ Return the array of server strings used to configure this instance.
271
297
  end
272
298
  end
273
299
 
274
- Libmemcached.memcached_stat_free(@struct, stat_struct)
300
+ Rlibmemcached.memcached_stat_free(@struct, stat_struct)
275
301
  stats
276
302
  end
277
303
 
@@ -281,14 +307,21 @@ Return the array of server strings used to configure this instance.
281
307
 
282
308
  # Return a namespaced key for this Memcached instance. Accepts a String <tt>key</tt> value.
283
309
  def ns(key) #:doc:
310
+ # raise ClientError, "Invalid key" if key =~ /\s/ # XXX Slow
284
311
  "#{@namespace}#{key}"
285
312
  end
286
313
 
287
- # Checks the return code from Libmemcached against the exception list. Raises the corresponding exception if the return code is not Memcached::Success or Memcached::ActionQueued. Accepts an integer return code.
314
+ # Checks the return code from Rlibmemcached against the exception list. Raises the corresponding exception if the return code is not Memcached::Success or Memcached::ActionQueued. Accepts an integer return code.
288
315
  def check_return_code(ret) #:doc:
289
- # XXX 0.14 already returns 0 for an ActionQueued result
316
+ # 0.14 returns 0 for an ActionQueued result but 0.15 does not.
290
317
  return if ret == 0 or ret == 31
291
318
  raise EXCEPTIONS[ret], ""
319
+ rescue UnknownReadFailure
320
+ # libmemcached got out of sync; rebuild the struct
321
+ new_struct = Rlibmemcached.memcached_clone(nil, @struct)
322
+ Rlibmemcached.memcached_free(@struct)
323
+ @struct = new_struct
324
+ raise SynchronizationError, "Rebuilding @struct"
292
325
  end
293
326
 
294
327
  end
@@ -0,0 +1,55 @@
1
+
2
+ class Memcached
3
+
4
+ alias :get_multi :get #:nodoc:
5
+
6
+ # A legacy compatibility wrapper for the Memcached class. It has basic compatibility with the <b>memcache-client</b> API.
7
+ class Rails < ::Memcached
8
+
9
+ DEFAULTS = {}
10
+
11
+ # See Memcached#new for details.
12
+ def initialize(servers, opts = {})
13
+ super(servers, DEFAULTS.merge(opts))
14
+ end
15
+
16
+ # Wraps Memcached#get so that it doesn't raise. This has the side-effect of preventing you from
17
+ # storing <tt>nil</tt> values.
18
+ def get(key, raw = false)
19
+ super(key, !raw)
20
+ rescue NotFound
21
+ end
22
+
23
+ # Wraps Memcached#get with multiple arguments.
24
+ def get_multi(*keys)
25
+ super(keys)
26
+ end
27
+
28
+ # Wraps Memcached#set.
29
+ def set(key, value, ttl = 0, raw = false)
30
+ super(key, value, ttl, !raw)
31
+ end
32
+
33
+ # Wraps Memcached#delete so that it doesn't raise.
34
+ def delete(key)
35
+ super(key)
36
+ rescue NotFound
37
+ end
38
+
39
+ # Namespace accessor.
40
+ def namespace
41
+ @namespace
42
+ end
43
+
44
+ # Alias for get.
45
+ def [](key)
46
+ get key
47
+ end
48
+
49
+ # Alias for Memcached#set.
50
+ def []=(key, value)
51
+ set key, value
52
+ end
53
+
54
+ end
55
+ end
@@ -1,27 +1,27 @@
1
1
 
2
- # Gem::Specification for Memcached-0.6
2
+ # Gem::Specification for Memcached-0.7
3
3
  # Originally generated by Echoe
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = %q{memcached}
7
- s.version = "0.6"
7
+ s.version = "0.7"
8
8
 
9
9
  s.specification_version = 2 if s.respond_to? :specification_version=
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.authors = ["Evan Weaver"]
13
- s.date = %q{2008-01-21}
13
+ s.date = %q{2008-02-05}
14
14
  s.description = %q{An interface to the libmemcached C client.}
15
15
  s.email = %q{}
16
16
  s.extensions = ["ext/extconf.rb"]
17
- s.files = ["CHANGELOG", "ext/extconf.rb", "ext/libmemcached.i", "ext/libmemcached_wrap.c", "lib/memcached/behaviors.rb", "lib/memcached/exceptions.rb", "lib/memcached/integer.rb", "lib/memcached/memcached.rb", "lib/memcached.rb", "LICENSE", "Manifest", "README", "test/benchmark/benchmark.rb", "test/benchmark/benchmark_set_get.rb", "test/benchmark/profile.rb", "test/setup.rb", "test/teardown.rb", "test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "TODO", "memcached.gemspec"]
17
+ s.files = ["BENCHMARKS", "CHANGELOG", "COMPATIBILITY", "ext/extconf.rb", "ext/rlibmemcached.i", "ext/rlibmemcached_wrap.c", "lib/memcached/behaviors.rb", "lib/memcached/exceptions.rb", "lib/memcached/integer.rb", "lib/memcached/memcached.rb", "lib/memcached/rails.rb", "lib/memcached.rb", "LICENSE", "Manifest", "README", "test/profile/benchmark.rb", "test/profile/profile.rb", "test/profile/valgrind.rb", "test/setup.rb", "test/teardown.rb", "test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "test/unit/rails_test.rb", "TODO", "memcached.gemspec"]
18
18
  s.has_rdoc = true
19
19
  s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/memcached/}
20
20
  s.require_paths = ["lib", "ext"]
21
21
  s.rubyforge_project = %q{fauna}
22
22
  s.rubygems_version = %q{1.0.1}
23
23
  s.summary = %q{An interface to the libmemcached C client.}
24
- s.test_files = ["test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb"]
24
+ s.test_files = ["test/test_helper.rb", "test/unit/binding_test.rb", "test/unit/memcached_test.rb", "test/unit/rails_test.rb"]
25
25
  end
26
26
 
27
27
 
@@ -35,7 +35,7 @@ end
35
35
  # p.summary = "An interface to the libmemcached C client."
36
36
  # p.url = "http://blog.evanweaver.com/files/doc/fauna/memcached/"
37
37
  # p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
38
- # p.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|exceptions|behaviors|memcached.rb/
38
+ # p.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|exceptions|behaviors|rails.rb|memcached.rb/
39
39
  # end
40
40
  #
41
41
  # task :exceptions do
@@ -49,3 +49,11 @@ end
49
49
  # end
50
50
  # end
51
51
  # end
52
+ #
53
+ # task :valgrind do
54
+ # exec("valgrind --tool=memcheck --leak-check=yes --show-reachable=no --num-callers=15 --track-fds=yes ruby #{File.dirname(__FILE__)}/test/profile/valgrind.rb")
55
+ # end
56
+ #
57
+ # task :profile do
58
+ # exec("ruby #{File.dirname(__FILE__)}/test/profile/profile.rb")
59
+ # end