ruby-memcached 0.1.0

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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 11f93dfef10cbbbc92972e071a7662c78ada89bbc098fc59905ad386c5a62c25
4
+ data.tar.gz: e94b21ce9b83b03bd204114b2344ae398971428e1154f1508daeebbfb17ca7cc
5
+ SHA512:
6
+ metadata.gz: 10d7e9ca7df90a8f07f66d5627cc4b9012b2e66762014800d796650424403a49ae2855bd20052982051094bd2f862e515ae84ef9e87c0ff43210a53075d3064f
7
+ data.tar.gz: 0a25744a8187a5d3f1d48a23e10ebe89d4ab6e830ff5f6ddb42ea7f881c0488ffd0aed2a5f025ac754832bdf618aa427ad0551ffe03f8d1cb62c6ace741a16f4
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require_relative '../lib/ruby-memcached.rb'
5
+
6
+
7
+ host = ARGV[0]
8
+ port = ARGV[1]
9
+ server = TCPSocket.new(host, port)
10
+
11
+ listener = Thread.new {
12
+ while response = server.gets()
13
+ puts("Server: " + response)
14
+ end
15
+ }
16
+
17
+ speaker = Thread.new {
18
+ while true
19
+ print("> ")
20
+ server.puts(STDIN.gets())
21
+ break if $_ =~ RubyMemcached::CommandsRegex.end
22
+ sleep(0.1)
23
+ end
24
+ }
25
+
26
+ listener.join()
27
+ speaker.join()
28
+
29
+ server.close()
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/ruby-memcached.rb'
4
+
5
+ puts('Creating server...')
6
+ host = ARGV[0]
7
+ port = ARGV[1]
8
+ gc_interval = ARGV[2].to_i()
9
+
10
+ server = RubyMemcached::Server.new(host, port)
11
+
12
+ main = Thread.new {
13
+ puts('Starting server...')
14
+ server.start()
15
+ }
16
+
17
+ gc = Thread.new {
18
+ server.start_gc(gc_interval) if gc_interval > 0
19
+ }
20
+
21
+ main.join()
22
+ puts('Server closed')
@@ -0,0 +1,3 @@
1
+ require_relative './ruby-memcached/Memcached.rb'
2
+ require_relative './ruby-memcached/Server.rb'
3
+ require_relative './ruby-memcached/Client.rb'
@@ -0,0 +1,161 @@
1
+ require 'socket'
2
+
3
+ require_relative './Memcached.rb'
4
+ require_relative './Constants.rb'
5
+
6
+ module RubyMemcached
7
+ class Client
8
+
9
+ attr_reader :host
10
+ attr_reader :port
11
+
12
+ def initialize(host, port)
13
+ @host = host
14
+ @port = port
15
+ @server = TCPSocket.new(host, port)
16
+ end
17
+
18
+ def get(keys)
19
+ keys_string = keys.reduce { |ss, s| ss + ' ' + s }
20
+ @server.puts(Commands.get % keys_string)
21
+
22
+ items = []
23
+
24
+ loop do
25
+ case @server.gets()
26
+ when ResponsesRegex.get
27
+ key = $~['key']
28
+ flags = $~['flags'].to_i()
29
+ bytes = $~['bytes'].to_i()
30
+ data = @server.read(bytes + 1).chomp()
31
+
32
+ items << Memcached::Item.new(key, data, flags, 0, bytes, nil)
33
+
34
+ when ResponsesRegex.end
35
+ break
36
+
37
+ when /.*ERROR.*/
38
+ break
39
+ end
40
+ end
41
+
42
+ return items
43
+ end
44
+
45
+ def gets(keys)
46
+ keys_string = keys.reduce { |ss, s| ss + ' ' + s }
47
+ @server.puts(Commands.gets % keys_string)
48
+
49
+ items = []
50
+
51
+ loop do
52
+ case @server.gets()
53
+ when ResponsesRegex.gets
54
+ key = $~['key']
55
+ flags = $~['flags'].to_i()
56
+ bytes = $~['bytes'].to_i()
57
+ cas_id = $~['cas_id'].to_i()
58
+ data = @server.read(bytes + 1).chomp()
59
+
60
+ items << Memcached::Item.new(key, data, flags, 0, bytes, cas_id)
61
+
62
+ when ResponsesRegex.end
63
+ break
64
+
65
+ when /.*ERROR.*/
66
+ break
67
+ end
68
+ end
69
+
70
+ return items
71
+ end
72
+
73
+ def set(key, flags, exptime, bytes, data)
74
+ @server.puts(Commands.set % [
75
+ key,
76
+ flags,
77
+ exptime,
78
+ bytes,
79
+ '',
80
+ data
81
+ ])
82
+
83
+ return Responses.to_h[Responses.key @server.gets()]
84
+ end
85
+
86
+ def add(key, flags, exptime, bytes, data)
87
+ @server.puts(Commands.add % [
88
+ key,
89
+ flags,
90
+ exptime,
91
+ bytes,
92
+ '',
93
+ data
94
+ ])
95
+
96
+ return Responses.to_h[Responses.key @server.gets()]
97
+ end
98
+
99
+ def replace(key, flags, exptime, bytes, data)
100
+ @server.puts(Commands.replace % [
101
+ key,
102
+ flags,
103
+ exptime,
104
+ bytes,
105
+ '',
106
+ data
107
+ ])
108
+
109
+ return Responses.to_h[Responses.key @server.gets()]
110
+ end
111
+
112
+ def append(key, bytes, data)
113
+ @server.puts(Commands.append % [
114
+ key,
115
+ bytes,
116
+ '',
117
+ data
118
+ ])
119
+
120
+ return Responses.to_h[Responses.key @server.gets()]
121
+ end
122
+
123
+ def prepend(key, bytes, data)
124
+ @server.puts(Commands._prepend % [
125
+ key,
126
+ bytes,
127
+ '',
128
+ data
129
+ ])
130
+
131
+ return Responses.to_h[Responses.key @server.gets()]
132
+ end
133
+
134
+ def cas(key, flags, exptime, bytes, cas_id, data)
135
+ @server.puts(Commands.cas % [
136
+ key,
137
+ flags,
138
+ exptime,
139
+ bytes,
140
+ cas_id,
141
+ '',
142
+ data
143
+ ])
144
+
145
+ return Responses.to_h[Responses.key @server.gets()]
146
+ end
147
+
148
+ def delete(key)
149
+ @server.puts(Commands.delete % key)
150
+ return Responses.to_h[Responses.key @server.gets()]
151
+ end
152
+
153
+ def end()
154
+ @server.puts(Commands.end)
155
+ end
156
+
157
+ def reconnect()
158
+ @server = TCPSocket.new(@host, @port)
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,5 @@
1
+ require_relative './constants/Commands.rb'
2
+ require_relative './constants/CommandsRegex.rb'
3
+ require_relative './constants/Errors.rb'
4
+ require_relative './constants/Responses.rb'
5
+ require_relative './constants/ResponsesRegex.rb'
@@ -0,0 +1,38 @@
1
+ module RubyMemcached
2
+ class Memcached::Item
3
+
4
+ attr_accessor :key
5
+ attr_accessor :data
6
+ attr_accessor :flags
7
+ attr_accessor :exptime
8
+ attr_accessor :bytes
9
+ attr_accessor :cas_id
10
+
11
+ attr_accessor :lock
12
+
13
+ def initialize(key, data, flags, exptime, bytes, cas_id)
14
+ @key = key
15
+ @data = data
16
+ @flags = flags
17
+ @bytes = bytes
18
+ @exptime = get_exptime(exptime.to_i)
19
+ @cas_id = cas_id
20
+
21
+ @lock = Mutex.new()
22
+ end
23
+
24
+ def to_s()
25
+ return @key
26
+ end
27
+ end
28
+ end
29
+
30
+ def get_exptime(exptime)
31
+ if (exptime == 0)
32
+ return nil
33
+ elsif (exptime < 1592000)
34
+ return Time.now().getutc() + exptime
35
+ else
36
+ return Time.at(exptime)
37
+ end
38
+ end
@@ -0,0 +1,121 @@
1
+ require 'concurrent'
2
+
3
+ module RubyMemcached
4
+ class Memcached
5
+
6
+ attr_reader :storage
7
+
8
+ def initialize
9
+ @storage = Concurrent::Hash.new()
10
+ end
11
+
12
+ def get(key)
13
+ self.check_exptime(key)
14
+ return @storage[key]
15
+ end
16
+
17
+ def get_multi(keys)
18
+ result = []
19
+ for key in keys do
20
+ item = self.get(key)
21
+ result.append(item) unless item.nil?
22
+ end
23
+ return result
24
+ end
25
+
26
+ def set(key, flags, exptime, bytes, data)
27
+ if(@storage.key?(key))
28
+ cas_id = @storage[key].cas_id + 1
29
+ else
30
+ cas_id = 0
31
+ end
32
+ new_item = Item.new(key, data, flags, exptime, bytes, cas_id)
33
+ @storage.store(key, new_item)
34
+ return Responses.stored
35
+ end
36
+
37
+ def add(key, flags, exptime, bytes, data)
38
+ self.check_exptime(key)
39
+
40
+ return Responses.not_stored if @storage.key?(key)
41
+ new_item = Item.new(key, data, flags, exptime, bytes, 0)
42
+ @storage.store(key, new_item)
43
+ return Responses.stored
44
+ end
45
+
46
+ def replace(key, flags, exptime, bytes, data)
47
+ self.check_exptime(key)
48
+
49
+ return Responses.not_stored unless @storage.key?(key)
50
+ cas_id = @storage[key].cas_id + 1
51
+ new_item = Item.new(key, data, flags, exptime, bytes, cas_id)
52
+ @storage.store(key, new_item)
53
+ return Responses.stored
54
+ end
55
+
56
+ def append(key, bytes, data)
57
+ self.check_exptime(key)
58
+
59
+ return Responses.not_stored unless @storage.key?(key)
60
+ @storage[key].data.concat(data)
61
+ @storage[key].bytes += bytes
62
+ @storage[key].cas_id += 1
63
+ return Responses.stored
64
+ end
65
+
66
+ def prepend(key, bytes, data)
67
+ self.check_exptime(key)
68
+
69
+ return Responses.not_stored unless @storage.key?(key)
70
+ @storage[key].data.prepend(data)
71
+ @storage[key].bytes += bytes
72
+ @storage[key].cas_id += 1
73
+ return Responses.stored
74
+ end
75
+
76
+ def cas(key, flags, exptime, bytes, cas_id, data)
77
+ self.check_exptime(key)
78
+
79
+ return Responses.not_found unless @storage.key?(key)
80
+
81
+ old_item = @storage[key]
82
+ old_item.lock.synchronize do
83
+ return Responses.exists if old_item.cas_id != cas_id
84
+
85
+ new_item = Item.new(key, data, flags, exptime, bytes, old_item.cas_id + 1)
86
+ @storage.store(key, new_item)
87
+ return Responses.stored
88
+ end
89
+ end
90
+
91
+ def delete(key)
92
+ return Responses.not_found unless @storage.key?(key)
93
+ @storage.delete(key)
94
+ return Responses.deleted
95
+ end
96
+
97
+ def check_exptime(key)
98
+ value = @storage[key]
99
+ return true if value.nil?() || value.exptime.nil?()
100
+
101
+ current_time = Time.now().getutc()
102
+
103
+ if (current_time > value.exptime)
104
+ @storage.delete(key)
105
+ return false
106
+ end
107
+
108
+ return true
109
+ end
110
+
111
+ def check_exptimes()
112
+ deleted = 0
113
+ @storage.each_key do | key |
114
+ delete += 1 unless self.check_exptime(key)
115
+ end
116
+ return deleted
117
+ end
118
+ end
119
+ end
120
+
121
+ require_relative './Item.rb'
@@ -0,0 +1,194 @@
1
+ require 'socket'
2
+
3
+ require_relative './/Memcached.rb'
4
+ require_relative './Constants.rb'
5
+
6
+ module RubyMemcached
7
+ class Server
8
+
9
+ attr_reader :host
10
+ attr_reader :port
11
+ attr_accessor :storage
12
+
13
+ def initialize(host, port)
14
+ @host = host
15
+ @port = port
16
+ @connection = TCPServer.new(host, port)
17
+ @memc = Memcached.new()
18
+ end
19
+
20
+ def start
21
+ loop do
22
+ Thread.start(@connection.accept()) do | client |
23
+
24
+ puts('Opening connection to %s' % client.to_s)
25
+
26
+ continue_condition = true
27
+
28
+ while command = client.gets()
29
+ printf('%s: %s' % [client.to_s(), command])
30
+ begin
31
+ continue_condition = parse(command, client) unless command.nil?
32
+ rescue => e
33
+ client.puts(Errors.server_error % e.message)
34
+ puts(Errors.server_error % e.message)
35
+ end
36
+ break unless continue_condition
37
+ end
38
+
39
+ client.close()
40
+ puts('Closing connection to %s' % [client.to_s()])
41
+ end
42
+ end
43
+ end
44
+
45
+ def parse(command, client)
46
+ case command
47
+ when CommandsRegex.get
48
+ self.get(client, $~)
49
+
50
+ when CommandsRegex.gets
51
+ self.gets(client, $~)
52
+
53
+ when CommandsRegex.set
54
+ self.set(client, $~)
55
+
56
+ when CommandsRegex.add
57
+ self.add(client, $~)
58
+
59
+ when CommandsRegex.replace
60
+ self.replace(client, $~)
61
+
62
+ when CommandsRegex.append
63
+ self.append(client, $~)
64
+
65
+ when CommandsRegex.prepend
66
+ self.prepend(client, $~)
67
+
68
+ when CommandsRegex.cas
69
+ self.cas(client, $~)
70
+
71
+ when CommandsRegex.delete
72
+ self.delete(client, $~)
73
+
74
+ when CommandsRegex.end
75
+ return false;
76
+ else
77
+ client.puts(Errors.client_error % [": Invalid command"])
78
+ end
79
+
80
+ return true
81
+ end
82
+
83
+ def get_data(client, bytes)
84
+ return client.read(bytes + 1).chomp()
85
+ end
86
+
87
+ def get(client, command)
88
+ keys = command['keys'].split(' ')
89
+ items = @memc.get_multi(keys)
90
+
91
+ for item in items
92
+ client.puts(Responses.get % [item.key, item.flags, item.bytes, item.data]) unless item.nil?()
93
+ end
94
+ client.puts(Responses.end)
95
+ end
96
+
97
+ def gets(client, command)
98
+ keys = command['keys'].split(' ')
99
+ items = @memc.get_multi(keys)
100
+
101
+ for item in items
102
+ client.puts(Responses.gets % [item.key, item.flags, item.bytes, item.cas_id, item.data]) unless item.nil?()
103
+ end
104
+ client.puts(Responses.end)
105
+ end
106
+
107
+ def set(client, command)
108
+ key = command['key']
109
+ flags = command['flags']
110
+ exptime = command['exptime']
111
+ bytes = command['bytes'].to_i()
112
+ data = self.get_data(client, bytes)
113
+ noreply = !command['noreply'].nil?
114
+
115
+ response = @memc.set(key, flags, exptime, bytes, data)
116
+ client.puts(response) unless noreply
117
+ end
118
+
119
+ def add(client, command)
120
+ key = command['key']
121
+ flags = command['flags']
122
+ exptime = command['exptime']
123
+ bytes = command['bytes'].to_i()
124
+ data = self.get_data(client, bytes)
125
+ noreply = !command['noreply'].nil?
126
+
127
+ response = @memc.add(key, flags, exptime, bytes, data)
128
+ client.puts(response) unless noreply
129
+ end
130
+
131
+ def replace(client, command)
132
+ key = command['key']
133
+ flags = command['flags']
134
+ exptime = command['exptime']
135
+ bytes = command['bytes'].to_i()
136
+ data = self.get_data(client, bytes)
137
+ noreply = !command['noreply'].nil?
138
+
139
+ response = @memc.replace(key, flags, exptime, bytes, data)
140
+ client.puts(response) unless noreply
141
+ end
142
+
143
+ def append(client, command)
144
+ key = command['key']
145
+ bytes = command['bytes'].to_i()
146
+ data = self.get_data(client, bytes)
147
+ noreply = !command['noreply'].nil?
148
+
149
+ response = @memc.append(key, bytes, data)
150
+ client.puts(response) unless noreply
151
+ end
152
+
153
+ def prepend(client, command)
154
+ key = command['key']
155
+ bytes = command['bytes'].to_i()
156
+ data = self.get_data(client, bytes)
157
+ noreply = !command['noreply'].nil?
158
+
159
+ response = @memc.prepend(key, bytes, data)
160
+ client.puts(response) unless noreply
161
+
162
+ end
163
+
164
+ def cas(client, command)
165
+ key = command['key']
166
+ flags = command['flags']
167
+ exptime = command['exptime']
168
+ bytes = command['bytes'].to_i()
169
+ data = self.get_data(client, bytes)
170
+ cas_id = command['cas_id'].to_i()
171
+ noreply = !command['noreply'].nil?
172
+
173
+ response = @memc.cas(key, flags, exptime, bytes, cas_id, data)
174
+ client.puts(response) unless noreply
175
+ end
176
+
177
+ def delete(client, command)
178
+ key = command['key']
179
+ noreply = !command['noreply'].nil?
180
+
181
+ response = @memc.delete(key)
182
+ client.puts(response) unless noreply
183
+ end
184
+
185
+ def start_gc(interval, loops = nil)
186
+
187
+ while loops.nil?() || loops > 0
188
+ sleep(interval)
189
+ puts('Garbage collector deleted: %d' % @memc.check_exptimes())
190
+ loops -= 1 unless loops.nil?()
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,26 @@
1
+ require 'ruby-enum'
2
+
3
+ module RubyMemcached
4
+ class Commands
5
+ include Ruby::Enum
6
+
7
+ define :get, "get %s\n"
8
+ define :gets, "gets %s\n"
9
+
10
+ define :set, "set %s %d %d %d%s\n%s\n"
11
+ define :add, "add %s %d %d %d%s\n%s\n"
12
+ define :replace, "replace %s %d %d %d%s\n%s\n"
13
+
14
+ define :append, "append %s %d%s\n%s\n"
15
+ define :_prepend, "prepend %s %d%s\n%s\n"
16
+
17
+ define :cas, "cas %s %d %d %d %d%s\n%s\n"
18
+
19
+ define :delete, "delete %s%s\n"
20
+
21
+ define :incr, "incr %s %d%s\n%d\n"
22
+ define :decr, "decr %s %d%s\n%d\n"
23
+
24
+ define :end, "END\n"
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require 'ruby-enum'
2
+
3
+ module RubyMemcached
4
+ class CommandsRegex
5
+ include Ruby::Enum
6
+
7
+ define :get, /^get (?<keys>(\w|[ ])+)\n/
8
+ define :gets, /^gets (?<keys>(\w|[ ])+)\n/
9
+
10
+ define :set, /^set (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
11
+ define :add, /^add (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
12
+ define :replace, /^replace (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
13
+
14
+ define :append, /^append (?<key>(\w)+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
15
+ define :prepend, /^prepend (?<key>(\w)+) (?<bytes>[0-9]+)(?<noreply> noreply)?\n/
16
+
17
+ define :cas, /^cas (?<key>(\w)+) (?<flags>[0-9]+) (?<exptime>[0-9]+) (?<bytes>[0-9]+) (?<cas_id>[0-9]+)(?<noreply> noreply)?\n/
18
+
19
+ define :delete, /^delete (?<key>(\w)+)(?<noreply> noreply)?\n/
20
+
21
+ define :incr, /^incr (?<key>(\w)+) (?<value>[0-9]+)(?<noreply> noreply)?\n/
22
+ define :decr, /^decr (?<key>(\w)+) (?<value>[0-9]+)(?<noreply> noreply)?\n/
23
+
24
+ define :end, /END\n/
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'ruby-enum'
2
+
3
+ module RubyMemcached
4
+ class Errors
5
+ include Ruby::Enum
6
+
7
+ define :error, "ERROR\r\n"
8
+ define :client_error, "CLIENT_ERROR %s\r\n"
9
+ define :server_error, "SERVER_ERROR %s\r\n"
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'ruby-enum'
2
+
3
+ module RubyMemcached
4
+ class Responses
5
+ include Ruby::Enum
6
+
7
+ define :stored, "STORED\n"
8
+ define :not_stored, "NOT_STORED\n"
9
+ define :exists, "EXISTS\n"
10
+ define :not_found, "NOT_FOUND\n"
11
+ define :deleted, "DELETED\n"
12
+
13
+ define :get, "VALUE %s %d %d\n%s\n"
14
+ define :gets, "VALUE %s %d %d %d\n%s\n"
15
+
16
+ define :end, "END\n"
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ require 'ruby-enum'
2
+
3
+ module RubyMemcached
4
+ class ResponsesRegex
5
+ include Ruby::Enum
6
+
7
+ define :get, /VALUE (?<key>(\w)+) (?<flags>[0-9]+) (?<bytes>[0-9]+)/
8
+ define :gets, /VALUE (?<key>(\w)+) (?<flags>[0-9]+) (?<bytes>[0-9]+) (?<cas_id>[0-9]+)/
9
+
10
+ define :end, /END/
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-memcached
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Francisco Bongiovanni
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-enum
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: concurrent-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.1.5
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.5
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '12.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '12.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: minitest
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.11'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.11'
75
+ description: A simple memcached implementation for Moove-It code challenge
76
+ email: Frantss.Bongiovanni@gmail.com
77
+ executables:
78
+ - memcached-client.rb
79
+ - memcached-server.rb
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - bin/memcached-client.rb
84
+ - bin/memcached-server.rb
85
+ - lib/ruby-memcached.rb
86
+ - lib/ruby-memcached/Client.rb
87
+ - lib/ruby-memcached/Constants.rb
88
+ - lib/ruby-memcached/Item.rb
89
+ - lib/ruby-memcached/Memcached.rb
90
+ - lib/ruby-memcached/Server.rb
91
+ - lib/ruby-memcached/constants/Commands.rb
92
+ - lib/ruby-memcached/constants/CommandsRegex.rb
93
+ - lib/ruby-memcached/constants/Errors.rb
94
+ - lib/ruby-memcached/constants/Responses.rb
95
+ - lib/ruby-memcached/constants/ResponsesRegex.rb
96
+ homepage: https://rubygems.org/gems/ruby-memcached
97
+ licenses:
98
+ - MIT
99
+ metadata:
100
+ github_uri: https://github.com/Frantss/memcached-ruby
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubygems_version: 3.0.3
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Simple ruby memcached implementation
120
+ test_files: []