gioext-sinatra-memcache 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -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
@@ -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
+