tarantool 0.2.5 → 0.3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/Gemfile +14 -12
  2. data/LICENSE +4 -4
  3. data/README.md +15 -9
  4. data/Rakefile +5 -129
  5. data/lib/tarantool/base_record.rb +288 -0
  6. data/lib/tarantool/block_db.rb +135 -0
  7. data/lib/tarantool/callback_db.rb +47 -0
  8. data/lib/tarantool/core-ext.rb +12 -0
  9. data/lib/tarantool/em_db.rb +37 -0
  10. data/lib/tarantool/exceptions.rb +52 -7
  11. data/lib/tarantool/fiber_db.rb +152 -0
  12. data/lib/tarantool/light_record.rb +68 -0
  13. data/lib/tarantool/query.rb +127 -0
  14. data/lib/tarantool/record/select.rb +59 -0
  15. data/lib/tarantool/record.rb +93 -282
  16. data/lib/tarantool/request.rb +351 -52
  17. data/lib/tarantool/response.rb +108 -45
  18. data/lib/tarantool/serializers/bson.rb +2 -2
  19. data/lib/tarantool/serializers.rb +32 -4
  20. data/lib/tarantool/space_array.rb +153 -0
  21. data/lib/tarantool/space_hash.rb +262 -0
  22. data/lib/tarantool/util.rb +182 -0
  23. data/lib/tarantool/version.rb +3 -0
  24. data/lib/tarantool.rb +79 -29
  25. data/test/box.pid +1 -0
  26. data/test/helper.rb +164 -0
  27. data/test/run_all.rb +3 -0
  28. data/test/shared_query.rb +73 -0
  29. data/test/shared_record.rb +474 -0
  30. data/test/shared_space_array.rb +284 -0
  31. data/test/shared_space_hash.rb +239 -0
  32. data/test/tarant/init.lua +22 -0
  33. data/test/tarantool.cfg +62 -0
  34. data/test/tarantool.log +6 -0
  35. data/{spec/tarantool.cfg → test/tarantool_repl.cfg} +11 -5
  36. data/test/test_light_record.rb +48 -0
  37. data/test/test_query_block.rb +6 -0
  38. data/test/test_query_fiber.rb +7 -0
  39. data/test/test_record.rb +88 -0
  40. data/{spec/tarantool/composite_primary_key_spec.rb → test/test_record_composite_pk.rb} +5 -7
  41. data/test/test_space_array_block.rb +6 -0
  42. data/test/test_space_array_callback.rb +255 -0
  43. data/test/test_space_array_callback_nodef.rb +190 -0
  44. data/test/test_space_array_fiber.rb +7 -0
  45. data/test/test_space_hash_block.rb +6 -0
  46. data/test/test_space_hash_fiber.rb +7 -0
  47. metadata +78 -55
  48. data/Gemfile.lock +0 -54
  49. data/examples/em_simple.rb +0 -16
  50. data/examples/record.rb +0 -68
  51. data/examples/simple.rb +0 -13
  52. data/lib/tarantool/requests/call.rb +0 -20
  53. data/lib/tarantool/requests/delete.rb +0 -18
  54. data/lib/tarantool/requests/insert.rb +0 -19
  55. data/lib/tarantool/requests/ping.rb +0 -16
  56. data/lib/tarantool/requests/select.rb +0 -22
  57. data/lib/tarantool/requests/update.rb +0 -35
  58. data/lib/tarantool/requests.rb +0 -19
  59. data/lib/tarantool/serializers/integer.rb +0 -14
  60. data/lib/tarantool/serializers/string.rb +0 -14
  61. data/lib/tarantool/space.rb +0 -39
  62. data/spec/helpers/let.rb +0 -11
  63. data/spec/helpers/truncate.rb +0 -12
  64. data/spec/spec_helper.rb +0 -21
  65. data/spec/tarantool/em_spec.rb +0 -22
  66. data/spec/tarantool/record_spec.rb +0 -316
  67. data/spec/tarantool/request_spec.rb +0 -103
  68. data/tarantool.gemspec +0 -69
metadata CHANGED
@@ -1,83 +1,89 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tarantool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andrew Rudenko
9
+ - Sokolov Yura 'funny-falcon'
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2012-06-02 00:00:00.000000000Z
13
+ date: 2012-07-16 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: iproto
16
- requirement: &70121541108760 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
17
18
  none: false
18
19
  requirements:
19
20
  - - ! '>='
20
21
  - !ruby/object:Gem::Version
21
- version: '0.2'
22
+ version: 0.3.3
22
23
  type: :runtime
23
24
  prerelease: false
24
- version_requirements: *70121541108760
25
- - !ruby/object:Gem::Dependency
26
- name: activemodel
27
- requirement: &70121541107900 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
28
26
  none: false
29
27
  requirements:
30
28
  - - ! '>='
31
29
  - !ruby/object:Gem::Version
32
- version: '3.1'
33
- - - <
34
- - !ruby/object:Gem::Version
35
- version: '4.0'
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: *70121541107900
30
+ version: 0.3.3
39
31
  description: Tarantool KV-storage client.
40
- email: ceo@prepor.ru
32
+ email:
33
+ - ceo@prepor.ru
34
+ - funny.falcon@gmail.com
41
35
  executables: []
42
36
  extensions: []
43
37
  extra_rdoc_files:
44
38
  - README.md
45
39
  - LICENSE
46
40
  files:
47
- - Gemfile
48
- - Gemfile.lock
49
- - LICENSE
50
- - README.md
51
- - Rakefile
52
- - examples/em_simple.rb
53
- - examples/record.rb
54
- - examples/simple.rb
55
- - lib/tarantool.rb
56
- - lib/tarantool/exceptions.rb
57
- - lib/tarantool/record.rb
58
41
  - lib/tarantool/request.rb
59
- - lib/tarantool/requests.rb
60
- - lib/tarantool/requests/call.rb
61
- - lib/tarantool/requests/delete.rb
62
- - lib/tarantool/requests/insert.rb
63
- - lib/tarantool/requests/ping.rb
64
- - lib/tarantool/requests/select.rb
65
- - lib/tarantool/requests/update.rb
42
+ - lib/tarantool/em_db.rb
43
+ - lib/tarantool/record/select.rb
66
44
  - lib/tarantool/response.rb
67
- - lib/tarantool/serializers.rb
45
+ - lib/tarantool/base_record.rb
46
+ - lib/tarantool/util.rb
47
+ - lib/tarantool/record.rb
48
+ - lib/tarantool/light_record.rb
49
+ - lib/tarantool/version.rb
50
+ - lib/tarantool/core-ext.rb
68
51
  - lib/tarantool/serializers/bson.rb
69
- - lib/tarantool/serializers/integer.rb
70
- - lib/tarantool/serializers/string.rb
71
- - lib/tarantool/space.rb
72
- - spec/helpers/let.rb
73
- - spec/helpers/truncate.rb
74
- - spec/spec_helper.rb
75
- - spec/tarantool.cfg
76
- - spec/tarantool/composite_primary_key_spec.rb
77
- - spec/tarantool/em_spec.rb
78
- - spec/tarantool/record_spec.rb
79
- - spec/tarantool/request_spec.rb
80
- - tarantool.gemspec
52
+ - lib/tarantool/callback_db.rb
53
+ - lib/tarantool/exceptions.rb
54
+ - lib/tarantool/space_hash.rb
55
+ - lib/tarantool/fiber_db.rb
56
+ - lib/tarantool/query.rb
57
+ - lib/tarantool/block_db.rb
58
+ - lib/tarantool/serializers.rb
59
+ - lib/tarantool/space_array.rb
60
+ - lib/tarantool.rb
61
+ - test/test_light_record.rb
62
+ - test/shared_record.rb
63
+ - test/tarantool_repl.cfg
64
+ - test/shared_space_array.rb
65
+ - test/test_space_hash_block.rb
66
+ - test/test_space_hash_fiber.rb
67
+ - test/test_record.rb
68
+ - test/test_record_composite_pk.rb
69
+ - test/tarantool.cfg
70
+ - test/helper.rb
71
+ - test/test_query_fiber.rb
72
+ - test/test_space_array_callback_nodef.rb
73
+ - test/run_all.rb
74
+ - test/test_space_array_callback.rb
75
+ - test/test_space_array_fiber.rb
76
+ - test/test_query_block.rb
77
+ - test/tarantool.log
78
+ - test/box.pid
79
+ - test/shared_query.rb
80
+ - test/test_space_array_block.rb
81
+ - test/shared_space_hash.rb
82
+ - test/tarant/init.lua
83
+ - Gemfile
84
+ - LICENSE
85
+ - Rakefile
86
+ - README.md
81
87
  homepage: http://github.com/mailru/tarantool-ruby
82
88
  licenses: []
83
89
  post_install_message:
@@ -98,14 +104,31 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
104
  - !ruby/object:Gem::Version
99
105
  version: '0'
100
106
  requirements: []
101
- rubyforge_project: tarantool
102
- rubygems_version: 1.8.10
107
+ rubyforge_project:
108
+ rubygems_version: 1.8.24
103
109
  signing_key:
104
- specification_version: 2
110
+ specification_version: 3
105
111
  summary: Tarantool KV-storage client.
106
112
  test_files:
107
- - spec/tarantool/composite_primary_key_spec.rb
108
- - spec/tarantool/em_spec.rb
109
- - spec/tarantool/record_spec.rb
110
- - spec/tarantool/request_spec.rb
111
- has_rdoc:
113
+ - test/test_light_record.rb
114
+ - test/shared_record.rb
115
+ - test/tarantool_repl.cfg
116
+ - test/shared_space_array.rb
117
+ - test/test_space_hash_block.rb
118
+ - test/test_space_hash_fiber.rb
119
+ - test/test_record.rb
120
+ - test/test_record_composite_pk.rb
121
+ - test/tarantool.cfg
122
+ - test/helper.rb
123
+ - test/test_query_fiber.rb
124
+ - test/test_space_array_callback_nodef.rb
125
+ - test/run_all.rb
126
+ - test/test_space_array_callback.rb
127
+ - test/test_space_array_fiber.rb
128
+ - test/test_query_block.rb
129
+ - test/tarantool.log
130
+ - test/box.pid
131
+ - test/shared_query.rb
132
+ - test/test_space_array_block.rb
133
+ - test/shared_space_hash.rb
134
+ - test/tarant/init.lua
data/Gemfile.lock DELETED
@@ -1,54 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- tarantool (0.2.4)
5
- activemodel (>= 3.1, < 4.0)
6
- iproto (>= 0.2)
7
-
8
- GEM
9
- remote: http://rubygems.org/
10
- specs:
11
- activemodel (3.1.1)
12
- activesupport (= 3.1.1)
13
- builder (~> 3.0.0)
14
- i18n (~> 0.6)
15
- activesupport (3.1.1)
16
- multi_json (~> 1.0)
17
- archive-tar-minitar (0.5.2)
18
- bson (1.4.0)
19
- bson_ext (1.4.0)
20
- builder (3.0.0)
21
- columnize (0.3.5)
22
- em-synchrony (1.0.0)
23
- eventmachine (>= 1.0.0.beta.1)
24
- eventmachine (1.0.0.beta.4)
25
- i18n (0.6.0)
26
- iproto (0.2)
27
- linecache19 (0.5.12)
28
- ruby_core_source (>= 0.1.4)
29
- multi_json (1.0.3)
30
- rr (1.0.4)
31
- ruby-debug-base19 (0.11.25)
32
- columnize (>= 0.3.1)
33
- linecache19 (>= 0.5.11)
34
- ruby_core_source (>= 0.1.4)
35
- ruby-debug19 (0.11.6)
36
- columnize (>= 0.3.1)
37
- linecache19 (>= 0.5.11)
38
- ruby-debug-base19 (>= 0.11.19)
39
- ruby_core_source (0.1.5)
40
- archive-tar-minitar (>= 0.5.2)
41
- yajl-ruby (1.1.0)
42
-
43
- PLATFORMS
44
- ruby
45
-
46
- DEPENDENCIES
47
- activemodel
48
- bson
49
- bson_ext
50
- em-synchrony
51
- rr
52
- ruby-debug19
53
- tarantool!
54
- yajl-ruby
@@ -1,16 +0,0 @@
1
- require 'bundler'
2
- ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
3
- Bundler.setup
4
-
5
- require 'tarantool'
6
-
7
- require 'em-synchrony'
8
- DB = Tarantool.new host: 'localhost', port: 33013, type: :em
9
- EM.synchrony do
10
- space = DB.space 0
11
- space.insert 'prepor', 'Andrew', 'ceo@prepor.ru'
12
- res = space.select 'prepor'
13
- puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
14
- space.delete 'prepor'
15
- EM.stop
16
- end
data/examples/record.rb DELETED
@@ -1,68 +0,0 @@
1
- require 'bundler'
2
- ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
3
- Bundler.setup
4
-
5
- require 'tarantool/record'
6
- require 'tarantool/serializers/bson'
7
-
8
- DB = Tarantool.new host: 'localhost', port: 33013
9
-
10
- class MyTarantool < Tarantool::Record
11
- set_tarantool DB
12
- end
13
-
14
- class User < MyTarantool
15
- set_space_no 0
16
-
17
- field :login, :string
18
- field :name, :string
19
- field :email, :string
20
- field :apples_count, :integer, default: 0
21
- field :info, :bson
22
- index :name, :email
23
-
24
- validates_length_of(:login, minimum: 3)
25
-
26
- after_create do
27
- # after work!
28
- end
29
- end
30
-
31
- User.tarantool.call
32
-
33
- # Now attribute positions are not important.
34
- User.create login: 'prepor', email: 'ceo@prepor.ru', name: 'Andrew'
35
- User.create login: 'ruden', name: 'Andrew', email: 'rudenkoco@gmail.com'
36
-
37
- # find by primary key login
38
- User.find 'prepor'
39
- # first 2 users with name Andrew
40
- User.where(name: 'Andrew').limit(2).all
41
- # second user with name Andrew
42
- User.where(name: 'Andrew').offset(1).limit(1).all
43
- # user with name Andrew and email ceo@prepor.ru
44
- User.where(name: 'Andrew', email: 'ceo@prepor.ru').first
45
- # raise exception, becouse we can't select from not first part of index
46
- begin
47
- User.where(email: 'ceo@prepor.ru')
48
- rescue Tarantool::ArgumentError => e
49
- end
50
- # increment field apples_count by one. Its atomic operation vie native Tarantool interface
51
- User.find('prepor').increment :apples_count
52
-
53
- # call lua func, which return record's tuples
54
- User.call('box.select_range', 0, 0, 5)
55
-
56
- # update only dirty attributes
57
- user = User.find('prepor')
58
- user.name = "Petr"
59
- user.save
60
-
61
- # field serialization to bson
62
- user.info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] }
63
- user.save
64
- User.find('prepor').info['bio'] # => 'hi!'
65
- user.destroy
66
- puts "Ok!"
67
-
68
-
data/examples/simple.rb DELETED
@@ -1,13 +0,0 @@
1
- require 'bundler'
2
- ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
3
- Bundler.setup
4
-
5
- require 'tarantool'
6
-
7
- DB = Tarantool.new host: 'localhost', port: 33013
8
- space = DB.space 0
9
-
10
- space.insert 'prepor', 'Andrew', 'ceo@prepor.ru'
11
- res = space.select 'prepor'
12
- puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
13
- space.delete 'prepor'
@@ -1,20 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Call < Request
4
- request_type :call
5
-
6
- attr_reader :flags, :proc_name, :tuple
7
- def parse_args
8
- @flags = params[:return_tuple] ? 1 : 0
9
- @proc_name = args.shift
10
- @tuple = args.map(&:to_s)
11
- end
12
-
13
- def make_body
14
- [flags].pack('L') +
15
- self.class.pack_field(proc_name) +
16
- self.class.pack_tuple(*tuple)
17
- end
18
- end
19
- end
20
- end
@@ -1,18 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Delete < Request
4
- request_type :delete
5
-
6
- attr_reader :flags, :key
7
- def parse_args
8
- @flags = params[:return_tuple] ? 1 : 0
9
- @key = params[:key] || args.first
10
- end
11
-
12
- def make_body
13
- [space_no, flags].pack('LL') +
14
- self.class.pack_tuple(*key)
15
- end
16
- end
17
- end
18
- end
@@ -1,19 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Insert < Request
4
- request_type :insert
5
-
6
- attr_reader :flags, :values
7
- def parse_args
8
- @flags = BOX_ADD
9
- @flags |= BOX_RETURN_TUPLE if params[:return_tuple]
10
- @values = params[:values] || args
11
- end
12
-
13
- def make_body
14
- [space_no, flags].pack('LL') +
15
- self.class.pack_tuple(*values)
16
- end
17
- end
18
- end
19
- end
@@ -1,16 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Ping < Request
4
- request_type :ping
5
-
6
- def make_body
7
- @start_time = Time.now
8
- ''
9
- end
10
-
11
- def make_response(data)
12
- Time.now - @start_time
13
- end
14
- end
15
- end
16
- end
@@ -1,22 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Select < Request
4
- request_type :select
5
-
6
- attr_reader :index_no, :offset, :limit, :count, :tuples
7
- def parse_args
8
- @index_no = params[:index_no] || 0
9
- @offset = params[:offset] || 0
10
- @limit = params[:limit] || -1
11
- @tuples = params[:values] || args
12
- raise(ArgumentError.new('values are required')) if tuples.empty?
13
- params[:return_tuple] = true
14
- end
15
-
16
- def make_body
17
- [space_no, index_no, offset, limit, tuples.size].pack('LLLLL') +
18
- tuples.map { |tuple| self.class.pack_tuple(*tuple) }.join
19
- end
20
- end
21
- end
22
- end
@@ -1,35 +0,0 @@
1
- class Tarantool
2
- module Requests
3
- class Update < Request
4
- request_type :update
5
-
6
- OP_CODES = { set: 0, add: 1, and: 2, or: 3, xor: 4, splice: 5 }
7
-
8
- def self.pack_ops(ops)
9
- ops.map do |op|
10
- raise ArgumentError.new('Operation should be array of size 3') unless op.size == 3
11
-
12
- field_no, op_symbol, op_arg = op
13
- op_code = OP_CODES[op_symbol] || raise(ArgumentError.new("Unsupported operation symbol '#{op_symbol}'"))
14
-
15
- [field_no, op_code].pack('LC') + self.pack_field(op_arg)
16
- end.join
17
- end
18
-
19
- attr_reader :flags, :key, :ops
20
- def parse_args
21
- @flags = params[:return_tuple] ? 1 : 0
22
- @key = params[:key] || args.first
23
- @ops = params[:ops]
24
- raise ArgumentError.new('Key is required') unless key
25
- end
26
-
27
- def make_body
28
- [space_no, flags].pack('LL') +
29
- self.class.pack_tuple(*key) +
30
- [ops.size].pack('L') +
31
- self.class.pack_ops(ops)
32
- end
33
- end
34
- end
35
- end
@@ -1,19 +0,0 @@
1
- class Tarantool
2
- require 'tarantool/request'
3
- module Requests
4
- REQUEST_TYPES = {
5
- insert: 13,
6
- select: 17,
7
- update: 19,
8
- delete: 21,
9
- call: 22,
10
- ping: 65280
11
- }
12
- BOX_RETURN_TUPLE = 1
13
- BOX_ADD = 2
14
-
15
- %w{insert select update delete call ping}.each do |v|
16
- require "tarantool/requests/#{v}"
17
- end
18
- end
19
- end
@@ -1,14 +0,0 @@
1
- class Tarantool
2
- module Serializers
3
- class Integer
4
- Serializers::MAP[:integer] = self
5
- def self.encode(value)
6
- value.to_i
7
- end
8
-
9
- def self.decode(field)
10
- field.to_i
11
- end
12
- end
13
- end
14
- end
@@ -1,14 +0,0 @@
1
- class Tarantool
2
- module Serializers
3
- class String
4
- Serializers::MAP[:string] = self
5
- def self.encode(value)
6
- value.to_s
7
- end
8
-
9
- def self.decode(field)
10
- field.to_s
11
- end
12
- end
13
- end
14
- end
@@ -1,39 +0,0 @@
1
- class Tarantool
2
- class Space
3
- attr_accessor :space_no
4
- attr_reader :connection
5
- def initialize(connection, space_no = nil)
6
- @connection = connection
7
- @space_no = space_no
8
- end
9
-
10
- def select(*args)
11
- request Requests::Select, args
12
- end
13
-
14
- def call(*args)
15
- request Requests::Call, args
16
- end
17
-
18
- def insert(*args)
19
- request Requests::Insert, args
20
- end
21
-
22
-
23
- def delete(*args)
24
- request Requests::Delete, args
25
- end
26
-
27
- def update(*args)
28
- request Requests::Update, args
29
- end
30
-
31
- def ping(*args)
32
- request Requests::Ping, args
33
- end
34
-
35
- def request(cls, args)
36
- cls.new(self, *args).perform
37
- end
38
- end
39
- end
data/spec/helpers/let.rb DELETED
@@ -1,11 +0,0 @@
1
- module Helpers
2
- module Let
3
- def let(name, &blk)
4
- define_method name do
5
- @let_assigments ||= {}
6
- @let_assigments[name] ||= send(:"original_#{name}")
7
- end
8
- define_method "original_#{name}", &blk
9
- end
10
- end
11
- end
@@ -1,12 +0,0 @@
1
- module Helpers
2
- module Truncate
3
- def teardown
4
- while (res = space.call('box.select_range', space.space_no, 0, 100, return_tuple: true)) && res.tuples.size > 0
5
- res.tuples.each do |keys|
6
- space.delete key: keys.take(@primary_key_size || 1)
7
- end
8
- end
9
- super
10
- end
11
- end
12
- end
data/spec/spec_helper.rb DELETED
@@ -1,21 +0,0 @@
1
- require 'bundler'
2
- ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
3
- Bundler.setup
4
-
5
- require 'minitest/spec'
6
- require 'minitest/autorun'
7
-
8
- require 'helpers/let'
9
- require 'helpers/truncate'
10
- require 'rr'
11
-
12
- require 'tarantool'
13
-
14
- TARANTOOL_CONFIG = { host: 'localhost', port: 33113, type: :block }
15
-
16
- DB = Tarantool.new TARANTOOL_CONFIG
17
-
18
- class MiniTest::Unit::TestCase
19
- extend Helpers::Let
20
- include RR::Adapters::MiniTest
21
- end
@@ -1,22 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'spec_helper'
3
- require "em-synchrony"
4
- describe "Tarantool with EM" do
5
- def space
6
- @space ||= Tarantool.new(TARANTOOL_CONFIG.merge(type: :em)).space 1
7
- end
8
-
9
- describe "insert, select and delete" do
10
- it "should insert tuple and return it" do
11
- EM.synchrony do
12
- space.insert 100, 'привет', return_tuple: true
13
- res = space.select 100
14
- int, string = res.tuple
15
- int.to_i.must_equal 100
16
- string.to_s.must_equal 'привет'
17
- space.delete 100
18
- EM.stop
19
- end
20
- end
21
- end
22
- end