rack-session-moped 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ vendor/bundler
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ -fs
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-session-moped.gemspec
4
+ gemspec
5
+ gem 'rake'
6
+ gem 'rspec'
7
+ gem 'yard'
8
+ gem 'redcarpet'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 aoyagikouhei
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # Rack::Session::Moped
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rack-session-moped'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rack-session-moped
18
+
19
+ ## Usage
20
+
21
+ Simple (localhost:27017 db:rack, collection:sessions)
22
+
23
+ use Rack::Session::Moped
24
+
25
+ Set Moped Session
26
+
27
+ session = Moped::Session.new(['localhost:27017'])
28
+ use Rack::Sessionn::Moped, {
29
+ session: session
30
+ }
31
+
32
+ Set Config
33
+
34
+ use Rack::Sessionn::Moped, {
35
+ seeds: ['127.0.0.1:27017'],
36
+ db: 'rack_test',
37
+ collection: 'sessions_test'
38
+ }
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create new Pull Request
47
+
48
+ ## License
49
+ [rack-session-mongo](http://github.com/aoyagikouhei/rack-session-moped) is Copyright (c) 2012 [Kouhei Aoyagi](http://github.com/aoyagikouhei)(@[aoyagikouhei](http://twitter.com/aoyagikouhei)) and distributed under the [MIT license](http://www.opensource.org/licenses/mit-license).
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+ require 'yard'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task :default => :spec
8
+
9
+ YARD::Rake::YardocTask.new(:doc)
@@ -0,0 +1,2 @@
1
+ require "rack/session/moped"
2
+ require "rack/session/moped/version"
@@ -0,0 +1,127 @@
1
+ require "rack/session/abstract/id"
2
+ require "moped"
3
+
4
+ module Rack
5
+ module Session
6
+ class Moped < Abstract::ID
7
+ attr_reader :mutex, :pool, :marshal_data
8
+ DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge(
9
+ db: :rack,
10
+ collection: :sessions,
11
+ drop: false,
12
+ seeds: ["localhost:27017"]
13
+ )
14
+
15
+ def initialize(app, options={})
16
+ super
17
+ @mutex = Mutex.new
18
+ session = @default_options[:session] || ::Moped::Session.new(@default_options[:seeds])
19
+ session.use @default_options[:db]
20
+ @pool = session[@default_options[:collection]]
21
+ @pool.indexes.create(expires: -1)
22
+ @pool.indexes.create({sid: 1}, {unique: true})
23
+ @marshal_data = @default_options[:marshal_data].nil? ? true : @default_options[:marshal_data] == true
24
+ @next_expire_period = nil
25
+ @recheck_expire_period = @default_options[:clear_expired_after].nil? ? 1800 : @default_options[:clear_expired_after].to_i
26
+ end
27
+
28
+ def get_session(env, sid)
29
+ @mutex.lock if env['rack.multithread']
30
+ session = find_session(sid) if sid
31
+ unless sid and session
32
+ env['rack.errors'].puts("Session '#{sid}' not found, initializing...") if $VERBOSE and not sid.nil?
33
+ session = {}
34
+ sid = generate_sid
35
+ save_session(sid)
36
+ end
37
+ session.instance_variable_set('@old', {}.merge(session))
38
+ session.instance_variable_set('@sid', sid)
39
+ return [sid, session]
40
+ ensure
41
+ @mutex.unlock if env['rack.multithread']
42
+ end
43
+
44
+ def set_session(env, sid, new_session, options)
45
+ @mutex.lock if env['rack.multithread']
46
+ expires = Time.now + options[:expire_after] if !options[:expire_after].nil?
47
+ session = find_session(sid) || {}
48
+ if options[:renew] or options[:drop]
49
+ delete_session(sid)
50
+ return false if options[:drop]
51
+ sid = generate_sid
52
+ save_session(sid, session, expires)
53
+ end
54
+ old_session = new_session.instance_variable_get('@old') || {}
55
+ session = merge_sessions(sid, old_session, new_session, session)
56
+ save_session(sid, session, expires)
57
+ return sid
58
+ ensure
59
+ @mutex.unlock if env['rack.multithread']
60
+ end
61
+
62
+ def destroy_session(env, sid, options)
63
+ delete_session(sid)
64
+ generate_sid unless options[:drop]
65
+ end
66
+
67
+ private
68
+
69
+ def find_session(sid)
70
+ time = Time.now
71
+ if @recheck_expire_period != -1 && (@next_expire_period.nil? || @next_expire_period < time)
72
+ @next_expire_period = time + @recheck_expire_period
73
+ @pool.find(expires: {'$lte' => time}).remove_all # clean out expired sessions
74
+ end
75
+ session = @pool.find(sid: sid).first
76
+ #if session is expired but hasn't been cleared yet. don't return it.
77
+ if session && session['expires'] != nil && session['expires'] < time
78
+ session = nil
79
+ end
80
+ session ? unpack(session['data']) : false
81
+ end
82
+
83
+ def delete_session(sid)
84
+ @pool.find(sid: sid).remove
85
+ end
86
+
87
+ def save_session(sid, session={}, expires=nil)
88
+ @pool.find(sid: sid).upsert("$set" => {data: pack(session), expires: expires})
89
+ end
90
+
91
+ def merge_sessions(sid, old, new, current=nil)
92
+ current ||= {}
93
+ unless Hash === old and Hash === new
94
+ warn 'Bad old or new sessions provided.'
95
+ return current
96
+ end
97
+ # delete keys that are not in common
98
+ delete = current.keys - (new.keys & current.keys)
99
+ warn "//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete.empty?
100
+ delete.each{|k| current.delete k }
101
+
102
+ update = new.keys.select{|k| !current.has_key?(k) || new[k] != current[k] || new[k].kind_of?(Hash) || new[k].kind_of?(Array) }
103
+ warn "//@#{sid}: updating #{update*','}" if $DEBUG and not update.empty?
104
+ update.each{|k| current[k] = new[k] }
105
+
106
+ current
107
+ end
108
+
109
+ def pack(data)
110
+ if(@marshal_data)
111
+ [Marshal.dump(data)].pack("m*")
112
+ else
113
+ data
114
+ end
115
+ end
116
+
117
+ def unpack(packed)
118
+ return nil unless packed
119
+ if(@marshal_data)
120
+ Marshal.load(packed.unpack("m*").first)
121
+ else
122
+ packed
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,9 @@
1
+ require "rack/session/abstract/id"
2
+
3
+ module Rack
4
+ module Session
5
+ class Moped < Abstract::ID
6
+ VERSION = "0.0.1"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/rack/session/moped/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["aoyagikouhei"]
6
+ gem.email = ["aoyagi.kouhei@gmail.com"]
7
+ gem.description = %q{Rack session store for MongoDB}
8
+ gem.summary = %q{Rack session store for MongoDB}
9
+ gem.homepage = "https://github.com/aoyagikouhei/rack-session-moped"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "rack-session-moped"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Rack::Session::Moped::VERSION
17
+ gem.add_dependency(%q<rack>)
18
+ gem.add_dependency(%q<moped>)
19
+ end
@@ -0,0 +1,260 @@
1
+ require 'spec_helper'
2
+ describe Rack::Session::Moped do
3
+ before(:each) do
4
+ @session_key = Rack::Session::Moped::DEFAULT_OPTIONS[:key]
5
+ @session_match = /#{@session_key}=[0-9a-fA-F]+;/
6
+ @incrementor = lambda do |env|
7
+ env['rack.session']['counter'] ||= 0
8
+ env['rack.session']['counter'] += 1
9
+ Rack::Response.new(env['rack.session'].inspect).to_a
10
+ end
11
+ @drop_session = proc do |env|
12
+ env['rack.session.options'][:drop] = true
13
+ @incrementor.call(env)
14
+ end
15
+ @renew_session = proc do |env|
16
+ env['rack.session.options'][:renew] = true
17
+ @incrementor.call(env)
18
+ end
19
+ @defer_session = proc do |env|
20
+ env['rack.session.options'][:defer] = true
21
+ @incrementor.call(env)
22
+ end
23
+ end
24
+
25
+ it 'should default connection params' do
26
+ mongo = Rack::Session::Moped.new(@incrementor)
27
+ pool = mongo.pool
28
+ pool.database.session.cluster.nodes[0].address.should == 'localhost:27017'
29
+
30
+ pool.should be_kind_of(Moped::Collection)
31
+ pool.database.name.should == :rack
32
+ pool.name.should == :sessions
33
+ end
34
+
35
+ it 'should specify connection params' do
36
+ mongo = Rack::Session::Moped.new(@incrementor,
37
+ seeds: ['127.0.0.1:27017'],
38
+ db: :rack_test,
39
+ collection: :sessions_test)
40
+ pool = mongo.pool
41
+ pool.database.session.cluster.nodes[0].address.should == '127.0.0.1:27017'
42
+
43
+ pool.should be_kind_of(Moped::Collection)
44
+ pool.database.name.should == :rack_test
45
+ pool.name.should == :sessions_test
46
+ end
47
+
48
+ it 'creates a new cookie' do
49
+ pool = Rack::Session::Moped.new(@incrementor)
50
+ res = Rack::MockRequest.new(pool).get('/')
51
+ res['Set-Cookie'].should match(/#{@session_key}=/)
52
+ res.body.should == '{"counter"=>1}'
53
+ end
54
+
55
+ it 'determines session from a cookie' do
56
+ pool = Rack::Session::Moped.new(@incrementor)
57
+ req = Rack::MockRequest.new(pool)
58
+ res = req.get('/')
59
+ cookie = res['Set-Cookie']
60
+ req.get('/', 'HTTP_COOKIE' => cookie).
61
+ body.should == '{"counter"=>2}'
62
+ req.get('/', 'HTTP_COOKIE' => cookie).
63
+ body.should == '{"counter"=>3}'
64
+ end
65
+
66
+ it 'survives nonexistant cookies' do
67
+ bad_cookie = 'rack.session=blarghfasel'
68
+ pool = Rack::Session::Moped.new(@incrementor)
69
+ res = Rack::MockRequest.new(pool).
70
+ get('/', 'HTTP_COOKIE' => bad_cookie)
71
+ res.body.should == '{"counter"=>1}'
72
+ cookie = res['Set-Cookie'][@session_match]
73
+ cookie.should_not match(/#{bad_cookie}/)
74
+ end
75
+
76
+ it 'should maintain freshness' do
77
+ pool = Rack::Session::Moped.new(@incrementor, :expire_after => 3)
78
+ res = Rack::MockRequest.new(pool).get('/')
79
+ res.body.should include('"counter"=>1')
80
+ cookie = res['Set-Cookie']
81
+ res = Rack::MockRequest.new(pool).get('/', 'HTTP_COOKIE' => cookie)
82
+ res['Set-Cookie'].should == cookie
83
+ res.body.should include('"counter"=>2')
84
+ puts 'Sleeping to expire session' if $DEBUG
85
+ sleep 4
86
+ res = Rack::MockRequest.new(pool).get('/', 'HTTP_COOKIE' => cookie)
87
+ res['Set-Cookie'].should_not == cookie
88
+ res.body.should include('"counter"=>1')
89
+ end
90
+
91
+ it 'deletes cookies with :drop option' do
92
+ pool = Rack::Session::Moped.new(@incrementor)
93
+ req = Rack::MockRequest.new(pool)
94
+ drop = Rack::Utils::Context.new(pool, @drop_session)
95
+ dreq = Rack::MockRequest.new(drop)
96
+
97
+ res0 = req.get('/')
98
+ session = (cookie = res0['Set-Cookie'])[@session_match]
99
+ res0.body.should == '{"counter"=>1}'
100
+
101
+ res1 = req.get('/', 'HTTP_COOKIE' => cookie)
102
+ res1['Set-Cookie'].should be_nil
103
+ res1.body.should == '{"counter"=>2}'
104
+
105
+ res2 = dreq.get('/', 'HTTP_COOKIE' => cookie)
106
+ res2['Set-Cookie'].should be_nil
107
+ res2.body.should == '{"counter"=>3}'
108
+
109
+ res3 = req.get('/', 'HTTP_COOKIE' => cookie)
110
+ res3['Set-Cookie'][@session_match].should_not == session
111
+ res3.body.should == '{"counter"=>1}'
112
+ end
113
+
114
+ it 'provides new session id with :renew option' do
115
+ pool = Rack::Session::Moped.new(@incrementor)
116
+ req = Rack::MockRequest.new(pool)
117
+ renew = Rack::Utils::Context.new(pool, @renew_session)
118
+ rreq = Rack::MockRequest.new(renew)
119
+
120
+ res0 = req.get('/')
121
+ session = (cookie = res0['Set-Cookie'])[@session_match]
122
+ res0.body.should == '{"counter"=>1}'
123
+
124
+ res1 = req.get('/', 'HTTP_COOKIE' => cookie)
125
+ res1['Set-Cookie'].should be_nil
126
+ res1.body.should == '{"counter"=>2}'
127
+
128
+ res2 = rreq.get('/', 'HTTP_COOKIE' => cookie)
129
+ new_cookie = res2['Set-Cookie']
130
+ new_session = new_cookie[@session_match]
131
+ new_session.should_not == session
132
+ res2.body.should == '{"counter"=>3}'
133
+
134
+ res3 = req.get('/', 'HTTP_COOKIE' => new_cookie)
135
+ res3['Set-Cookie'].should be_nil
136
+ res3.body.should == '{"counter"=>4}'
137
+ end
138
+
139
+ it 'should default marshal_data to true' do
140
+ pool = Rack::Session::Moped.new(@incrementor)
141
+ pool.marshal_data.should == true
142
+ data = {'test' => true}
143
+ pool.send(:pack, data).should == [Marshal.dump(data)].pack("m*")
144
+ pool.send(:unpack, [Marshal.dump(data)].pack("m*"))['test'] == true
145
+ end
146
+
147
+ it 'should be able to set marshal_data to false' do
148
+ pool = Rack::Session::Moped.new(@incrementor, :marshal_data => false)
149
+ pool.marshal_data.should == false
150
+ data = {'test' => true}
151
+ pool.send(:pack, data).should === data
152
+ pool.send(:unpack, data).should === data
153
+ end
154
+ specify 'omits cookie with :defer option' do
155
+ pool = Rack::Session::Moped.new(@incrementor)
156
+ req = Rack::MockRequest.new(pool)
157
+ defer = Rack::Utils::Context.new(pool, @defer_session)
158
+ dreq = Rack::MockRequest.new(defer)
159
+
160
+ res0 = req.get('/')
161
+ session = (cookie = res0['Set-Cookie'])[@session_match]
162
+ res0.body.should == '{"counter"=>1}'
163
+
164
+ res1 = req.get('/', 'HTTP_COOKIE' => cookie)
165
+ res1['Set-Cookie'].should be_nil
166
+ res1.body.should == '{"counter"=>2}'
167
+
168
+ res2 = dreq.get('/', 'HTTP_COOKIE' => cookie)
169
+ res2['Set-Cookie'].should be_nil
170
+ res2.body.should == '{"counter"=>3}'
171
+
172
+ res3 = req.get('/', 'HTTP_COOKIE' => cookie)
173
+ res3['Set-Cookie'].should be_nil
174
+ res3.body.should == '{"counter"=>4}'
175
+ end
176
+
177
+ # anyone know how to do this better?
178
+ specify 'multithread: should cleanly merge sessions' do
179
+ next unless $DEBUG
180
+ warn 'Running multithread test for Session::Mongo'
181
+ pool = Rack::Session::Moped.new(@incrementor)
182
+ req = Rack::MockRequest.new(pool)
183
+
184
+ res = req.get('/')
185
+ res.body.should == '{"counter"=>1}'
186
+ cookie = res['Set-Cookie']
187
+ sess_id = cookie[/#{pool.key}=([^,;]+)/,1]
188
+
189
+ delta_incrementor = lambda do |env|
190
+ # emulate disconjoinment of threading
191
+ env['rack.session'] = env['rack.session'].dup
192
+ Thread.stop
193
+ env['rack.session'][(Time.now.usec*rand).to_i] = true
194
+ @incrementor.call(env)
195
+ end
196
+ tses = Rack::Utils::Context.new pool, delta_incrementor
197
+ treq = Rack::MockRequest.new(tses)
198
+ tnum = rand(7).to_i+5
199
+ r = Array.new(tnum) do
200
+ Thread.new(treq) do |run|
201
+ run.get('/', 'HTTP_COOKIE' => cookie, 'rack.multithread' => true)
202
+ end
203
+ end.reverse.map{|t| t.run.join.value }
204
+ r.each do |res|
205
+ res['Set-Cookie'].should == cookie
206
+ res.body.should include('"counter"=>2')
207
+ end
208
+
209
+ session = pool.pool.get(sess_id)
210
+ session.size.should == tnum+1 # counter
211
+ session['counter'].should == 2 # meeeh
212
+
213
+ tnum = rand(7).to_i+5
214
+ r = Array.new(tnum) do |i|
215
+ delta_time = proc do |env|
216
+ env['rack.session'][i] = Time.now
217
+ Thread.stop
218
+ env['rack.session'] = env['rack.session'].dup
219
+ env['rack.session'][i] -= Time.now
220
+ @incrementor.call(env)
221
+ end
222
+ app = Rack::Utils::Context.new pool, time_delta
223
+ req = Rack::MockRequest.new app
224
+ Thread.new(req) do |run|
225
+ run.get('/', 'HTTP_COOKIE' => cookie, 'rack.multithread' => true)
226
+ end
227
+ end.reverse.map{|t| t.run.join.value }
228
+ r.each do |res|
229
+ res['Set-Cookie'].should == cookie
230
+ res.body.should include('"counter"=>3')
231
+ end
232
+
233
+ session = pool.pool.get(sess_id)
234
+ session.size.should == tnum+1
235
+ session['counter'].should == 3
236
+
237
+ drop_counter = proc do |env|
238
+ env['rack.session'].delete 'counter'
239
+ env['rack.session']['foo'] = 'bar'
240
+ [200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
241
+ end
242
+ tses = Rack::Utils::Context.new pool, drop_counter
243
+ treq = Rack::MockRequest.new(tses)
244
+ tnum = rand(7).to_i+5
245
+ r = Array.new(tnum) do
246
+ Thread.new(treq) do |run|
247
+ run.get('/', 'HTTP_COOKIE' => cookie, 'rack.multithread' => true)
248
+ end
249
+ end.reverse.map{|t| t.run.join.value }
250
+ r.each do |res|
251
+ res['Set-Cookie'].should == cookie
252
+ res.body.should include('"foo"=>"bar"')
253
+ end
254
+
255
+ session = pool.pool.get(sess_id)
256
+ session.size.should == r.size+1
257
+ session['counter'].should be_nil
258
+ session['foo'].should == 'bar'
259
+ end
260
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'rack/session/moped'
3
+ require 'rack/mock'
4
+ require 'rack/response'
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-session-moped
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - aoyagikouhei
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: moped
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Rack session store for MongoDB
47
+ email:
48
+ - aoyagi.kouhei@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rspec
55
+ - Gemfile
56
+ - LICENSE
57
+ - README.md
58
+ - Rakefile
59
+ - lib/rack-session-moped.rb
60
+ - lib/rack/session/moped.rb
61
+ - lib/rack/session/moped/version.rb
62
+ - rack-session-moped.gemspec
63
+ - spec/rack-session-moped_spec.rb
64
+ - spec/spec_helper.rb
65
+ homepage: https://github.com/aoyagikouhei/rack-session-moped
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ segments:
78
+ - 0
79
+ hash: 2177003043025176967
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ segments:
87
+ - 0
88
+ hash: 2177003043025176967
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.24
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Rack session store for MongoDB
95
+ test_files:
96
+ - spec/rack-session-moped_spec.rb
97
+ - spec/spec_helper.rb
98
+ has_rdoc: