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.
@@ -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
+