gioext-sinatra-memcache 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.
- data/README.textile +71 -0
- data/Rakefile +10 -0
- data/lib/sinatra/memcache.rb +145 -0
- data/spec/fixture.rb +49 -0
- data/spec/sinatra-memcache_spec.rb +73 -0
- metadata +76 -0
data/README.textile
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
h1. Sinatra-MemCache
|
|
2
|
+
|
|
3
|
+
h2. Dependencies
|
|
4
|
+
|
|
5
|
+
memcache-client
|
|
6
|
+
|
|
7
|
+
zlib
|
|
8
|
+
|
|
9
|
+
h2. Install
|
|
10
|
+
|
|
11
|
+
<pre>
|
|
12
|
+
sudo gem install gioext-sinatra-memcache
|
|
13
|
+
</pre>
|
|
14
|
+
|
|
15
|
+
h2. Example
|
|
16
|
+
|
|
17
|
+
<pre>
|
|
18
|
+
require 'rubygems'
|
|
19
|
+
require 'sinatra'
|
|
20
|
+
require 'sinatra/memcache'
|
|
21
|
+
|
|
22
|
+
# cache
|
|
23
|
+
get '/cache1' do
|
|
24
|
+
cache 'cache1' do
|
|
25
|
+
sleep(5)
|
|
26
|
+
'Hello Cache1'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# args
|
|
31
|
+
get '/cache2' do
|
|
32
|
+
cache 'cache2', :expiry => 10, :compress => true do
|
|
33
|
+
sleep(3)
|
|
34
|
+
'Hello Cache2'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# cache object
|
|
39
|
+
get '/obj' do
|
|
40
|
+
hash = cache 'obj' do
|
|
41
|
+
sleep(2)
|
|
42
|
+
{ :a => 'Hello Object' }
|
|
43
|
+
end
|
|
44
|
+
hash[:a]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# expire
|
|
48
|
+
get '/expire' do
|
|
49
|
+
expire 'cache1'
|
|
50
|
+
expire /^cache/
|
|
51
|
+
expire //
|
|
52
|
+
'Hello Expire'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# default options
|
|
56
|
+
set :cache_server, "localhost:11211"
|
|
57
|
+
set :cache_namespace, "sinatra-memcache"
|
|
58
|
+
set :cache_enable, true
|
|
59
|
+
set :cache_logging, true
|
|
60
|
+
set :cache_default_expiry, 3600
|
|
61
|
+
set :cache_default_compress, false
|
|
62
|
+
</pre>
|
|
63
|
+
|
|
64
|
+
h2. License
|
|
65
|
+
|
|
66
|
+
Copyright (c) 2009 Kazuki UCHIDA
|
|
67
|
+
|
|
68
|
+
Licensed under the MIT License:
|
|
69
|
+
|
|
70
|
+
- http://www.opensource.org/licenses/mit-license.php
|
|
71
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'spec/rake/spectask'
|
|
3
|
+
|
|
4
|
+
task :default => :spec
|
|
5
|
+
|
|
6
|
+
desc "Run all specs in spec directory"
|
|
7
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
|
8
|
+
t.spec_opts = ['--color', '--format specdoc']
|
|
9
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
|
10
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
require 'memcache'
|
|
2
|
+
require 'zlib'
|
|
3
|
+
#require 'rubygems'
|
|
4
|
+
#require 'sinatra/base'
|
|
5
|
+
|
|
6
|
+
class MemCache
|
|
7
|
+
def all_keys
|
|
8
|
+
raise MemCacheError, "No active servers" unless active?
|
|
9
|
+
keys = []
|
|
10
|
+
|
|
11
|
+
@servers.each do |server|
|
|
12
|
+
sock = server.socket
|
|
13
|
+
raise MemCacheError, "No connection to server" if sock.nil?
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
sock.write "stats items\r\n"
|
|
17
|
+
slabs = {}
|
|
18
|
+
while line = sock.gets
|
|
19
|
+
break if line == "END\r\n"
|
|
20
|
+
slabs[$1] = $2 if line =~ /^STAT items:(\d+):number (\d+)/
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
slabs.each do |k, v|
|
|
24
|
+
sock.write "stats cachedump #{k} #{v}\r\n"
|
|
25
|
+
while line = sock.gets
|
|
26
|
+
break if line == "END\r\n"
|
|
27
|
+
prefix = @namespace.empty? ? '' : "#{@namespace}:"
|
|
28
|
+
r = Regexp.new("^ITEM #{prefix}([^\s]+)")
|
|
29
|
+
keys << $1 if line =~ r
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
rescue SocketError, SystemCallError, IOError => err
|
|
33
|
+
server.close
|
|
34
|
+
raise MemCacheError, err.message
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
keys
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module Sinatra
|
|
43
|
+
module MemCache
|
|
44
|
+
module Helpers
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
#
|
|
48
|
+
#
|
|
49
|
+
def cache(key, params = {}, &block)
|
|
50
|
+
return block.call unless options.cache_enable
|
|
51
|
+
|
|
52
|
+
opts = {
|
|
53
|
+
:expiry => options.cache_default_expiry,
|
|
54
|
+
:compress => options.cache_default_compress
|
|
55
|
+
}.merge(params)
|
|
56
|
+
|
|
57
|
+
value = get(key, opts)
|
|
58
|
+
return value unless block_given?
|
|
59
|
+
|
|
60
|
+
if value
|
|
61
|
+
log "Get: #{key}"
|
|
62
|
+
value
|
|
63
|
+
else
|
|
64
|
+
log "Set: #{key}"
|
|
65
|
+
set(key, block.call, opts)
|
|
66
|
+
end
|
|
67
|
+
rescue => e
|
|
68
|
+
throw e if development?
|
|
69
|
+
block.call
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
#
|
|
74
|
+
#
|
|
75
|
+
def expire(p)
|
|
76
|
+
return unless options.cache_enable
|
|
77
|
+
|
|
78
|
+
case p
|
|
79
|
+
when String
|
|
80
|
+
expire_key(p)
|
|
81
|
+
when Regexp
|
|
82
|
+
expire_regexp(p)
|
|
83
|
+
end
|
|
84
|
+
true
|
|
85
|
+
rescue => e
|
|
86
|
+
throw e if development?
|
|
87
|
+
false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def client
|
|
94
|
+
options.cache_client ||= ::MemCache.new options.cache_server,
|
|
95
|
+
:namespace => options.cache_namespace
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def log(msg)
|
|
99
|
+
puts "[sinatra-memcache] #{msg}" if options.cache_logging
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def get(key, opts)
|
|
103
|
+
v = client[key, true]
|
|
104
|
+
return v unless v
|
|
105
|
+
|
|
106
|
+
v = Zlib::Inflate.inflate(v) if opts[:compress]
|
|
107
|
+
Marshal.load(v)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def set(key, value, opts)
|
|
111
|
+
v = Marshal.dump(value)
|
|
112
|
+
v = Zlib::Deflate.deflate(v) if opts[:compress]
|
|
113
|
+
client.set(key, v, opts[:expiry], true)
|
|
114
|
+
value
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def expire_key(key)
|
|
118
|
+
client.delete(key)
|
|
119
|
+
log "Expire: #{key}"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def expire_regexp(re)
|
|
123
|
+
keys = client.all_keys
|
|
124
|
+
keys.each do |key|
|
|
125
|
+
expire_key(key) if key =~ re
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.registered(app)
|
|
131
|
+
app.helpers MemCache::Helpers
|
|
132
|
+
|
|
133
|
+
app.set :cache_client, nil
|
|
134
|
+
app.set :cache_server, "localhost:11211"
|
|
135
|
+
app.set :cache_namespace, "sinatra-memcache"
|
|
136
|
+
app.set :cache_enable, true
|
|
137
|
+
app.set :cache_logging, true
|
|
138
|
+
app.set :cache_default_expiry, 3600
|
|
139
|
+
app.set :cache_default_compress, false
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
register MemCache
|
|
144
|
+
|
|
145
|
+
end
|
data/spec/fixture.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'sinatra'
|
|
3
|
+
require File.dirname(__FILE__) + '/../lib/sinatra/memcache'
|
|
4
|
+
|
|
5
|
+
get '/' do
|
|
6
|
+
"Hello World"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
get '/cache' do
|
|
10
|
+
cache "cache" do
|
|
11
|
+
"Hello World"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
get '/cache2' do
|
|
16
|
+
cache "cache2", :expiry => 1 do
|
|
17
|
+
"Hello World"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
get '/read' do
|
|
22
|
+
cache 'cache'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
get '/compress' do
|
|
26
|
+
cache "compress", :compress => true do
|
|
27
|
+
"Hello Compress"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
get '/object' do
|
|
32
|
+
hash = cache "object" do
|
|
33
|
+
{ :a => 'hello a', :b => 'hello b' }
|
|
34
|
+
end
|
|
35
|
+
hash[:a] + ' ' + hash[:b]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
get '/expire' do
|
|
39
|
+
expire "cache"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
get '/expire_re' do
|
|
43
|
+
expire //
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
configure do
|
|
47
|
+
set :cache_namespace, "test"
|
|
48
|
+
set :cache_logging, false
|
|
49
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/fixture'
|
|
2
|
+
require 'rack/test'
|
|
3
|
+
|
|
4
|
+
include Rack::Test::Methods
|
|
5
|
+
def app
|
|
6
|
+
Sinatra::Application
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe 'Sinatra-MemCache' do
|
|
10
|
+
before do
|
|
11
|
+
@client = MemCache.new 'localhost:11211', :namespace => "test"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "indexのレスポンスが正しいこと" do
|
|
15
|
+
get '/'
|
|
16
|
+
last_response.ok?.should be_true
|
|
17
|
+
last_response.body.should == "Hello World"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "cacheしたときのレスポンスが正しいこと" do
|
|
21
|
+
get '/cache'
|
|
22
|
+
last_response.ok?.should be_true
|
|
23
|
+
last_response.body.should == "Hello World"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "cacheした内容が正しいこと" do
|
|
27
|
+
get '/cache'
|
|
28
|
+
Marshal.load(@client['cache', true]).should == "Hello World"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "ブロック無しで読み取りのみできること" do
|
|
32
|
+
get '/cache'
|
|
33
|
+
get '/read'
|
|
34
|
+
last_response.ok?.should be_true
|
|
35
|
+
last_response.body.should == "Hello World"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "cacheした内容がexpireされること" do
|
|
39
|
+
get '/cache'
|
|
40
|
+
get '/expire'
|
|
41
|
+
@client['cache'].should be_nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "cacheが有効時間後にexpireされること" do
|
|
45
|
+
get '/cache2'
|
|
46
|
+
sleep(1)
|
|
47
|
+
@client['cache2'].should be_nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "compressが有効であること" do
|
|
51
|
+
get '/compress'
|
|
52
|
+
last_response.ok?.should be_true
|
|
53
|
+
last_response.body.should == "Hello Compress"
|
|
54
|
+
@client['compress', true].should == Zlib::Deflate.deflate(Marshal.dump('Hello Compress'))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "オブジェクトがcacheされること" do
|
|
58
|
+
get '/object'
|
|
59
|
+
last_response.ok?.should be_true
|
|
60
|
+
last_response.body.should == "hello a hello b"
|
|
61
|
+
Marshal.load(@client['object', true]).should == { :a => 'hello a', :b => 'hello b' }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "全てのcacheがexpireされること" do
|
|
65
|
+
get '/cache'
|
|
66
|
+
get '/cache2'
|
|
67
|
+
get '/compress'
|
|
68
|
+
get '/expire_re'
|
|
69
|
+
@client['cache'].should be_nil
|
|
70
|
+
@client['cache2'].should be_nil
|
|
71
|
+
@client['compress'].should be_nil
|
|
72
|
+
end
|
|
73
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: gioext-sinatra-memcache
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- gioext
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-06-24 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: sinatra
|
|
17
|
+
type: :runtime
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "0"
|
|
24
|
+
version:
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: memcache-client
|
|
27
|
+
type: :runtime
|
|
28
|
+
version_requirement:
|
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: "0"
|
|
34
|
+
version:
|
|
35
|
+
description:
|
|
36
|
+
email: gioext@gmail.com
|
|
37
|
+
executables: []
|
|
38
|
+
|
|
39
|
+
extensions: []
|
|
40
|
+
|
|
41
|
+
extra_rdoc_files: []
|
|
42
|
+
|
|
43
|
+
files:
|
|
44
|
+
- Rakefile
|
|
45
|
+
- README.textile
|
|
46
|
+
- lib/sinatra/memcache.rb
|
|
47
|
+
- spec/sinatra-memcache_spec.rb
|
|
48
|
+
- spec/fixture.rb
|
|
49
|
+
has_rdoc: "false"
|
|
50
|
+
homepage: http://github.com/gioext/sinatra-memcache
|
|
51
|
+
post_install_message:
|
|
52
|
+
rdoc_options: []
|
|
53
|
+
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: "0"
|
|
61
|
+
version:
|
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: "0"
|
|
67
|
+
version:
|
|
68
|
+
requirements: []
|
|
69
|
+
|
|
70
|
+
rubyforge_project:
|
|
71
|
+
rubygems_version: 1.2.0
|
|
72
|
+
signing_key:
|
|
73
|
+
specification_version: 2
|
|
74
|
+
summary: Cache extension on Sinatra
|
|
75
|
+
test_files: []
|
|
76
|
+
|