rack-redic 1.3.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bf92c89449d8d8709de10c6764860f6bf170e5d0
4
- data.tar.gz: bf999b9c9675ad376c52ae1eb6df3042f6c4d7a1
2
+ SHA256:
3
+ metadata.gz: b5d2082c913c7e03778bf029522eaf82c69321d279d2faba665d6fb72f6d60ad
4
+ data.tar.gz: e3ee0c189726c401312cb2fccf54dd7c491d1788ef0baf4c74e2649715bc0f3d
5
5
  SHA512:
6
- metadata.gz: 245c12a951c0c0c395064a64ab594f2d5e8774979bdcb3feb23fc855666612e50db63eead26aa5df911287a7c1f184918ea1a2cc69ae01f07f52e8fa17c0807b
7
- data.tar.gz: 5a0d6bff6ad7faae40884f75174d43728e87ea4526f73eb0b826ac414a2f05851b4c10f643ee0c53fb1bae5faa6ae6fe58f52f6222c1df731ff33d331b9f8e3a
6
+ metadata.gz: bee20ab72c2041aeb81c944c9635d5c736f5074854ec016d0c695a85979a9ddb5ed78c1940d5993e684c2cc6b6107dd105bdf4c8b794cdb72e199e11d9eb3ce0
7
+ data.tar.gz: fa4455eb28f23b911dd1ce00441d6098f2386373f0fc74162e4b9f4b7e2cf614ca7f08b9391fab8f2cc923159191a9079614d1f225dea85300ec3bc682965c9a
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
3
  /Gemfile.lock
4
+ /gems.locked
4
5
  /_yardoc/
5
6
  /coverage/
6
7
  /doc/
@@ -0,0 +1,55 @@
1
+ # http://rubocop.readthedocs.io
2
+ # https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
3
+ AllCops:
4
+ DisplayCopNames: true
5
+ DisplayStyleGuide: true
6
+ ExtraDetails: true
7
+ TargetRubyVersion: 2.4
8
+
9
+ Layout/AlignParameters:
10
+ EnforcedStyle: with_fixed_indentation
11
+
12
+ Layout/EmptyLineAfterMagicComment:
13
+ Enabled: false
14
+
15
+ Layout/IndentHash:
16
+ EnforcedStyle: consistent
17
+
18
+ Layout/MultilineOperationIndentation:
19
+ EnforcedStyle: indented
20
+
21
+ Layout/SpaceInsideStringInterpolation:
22
+ EnforcedStyle: space
23
+
24
+ Metrics/AbcSize:
25
+ Enabled: false
26
+
27
+ Metrics/BlockLength:
28
+ Enabled: false
29
+
30
+ Metrics/ClassLength:
31
+ Enabled: false
32
+
33
+ Metrics/CyclomaticComplexity:
34
+ Enabled: false
35
+
36
+ Metrics/LineLength:
37
+ Enabled: false
38
+
39
+ Metrics/MethodLength:
40
+ Enabled: false
41
+
42
+ Metrics/ModuleLength:
43
+ Enabled: false
44
+
45
+ Metrics/PerceivedComplexity:
46
+ Enabled: false
47
+
48
+ # Style/Documentation:
49
+ # Enabled: false
50
+
51
+ Style/IfUnlessModifier:
52
+ Enabled: false
53
+
54
+ Style/Next:
55
+ MinBodyLength: 8
data/README.md CHANGED
@@ -13,7 +13,7 @@ Any other options will get passed to `Rack::Session::Abstract::Persisted`.
13
13
 
14
14
  ## Installation
15
15
 
16
- Add this line to your application's Gemfile:
16
+ Add this line to your application's Gemfile or gems.rb file:
17
17
 
18
18
  ```ruby
19
19
  gem 'rack-redic', require: 'rack/session/redic'
data/Rakefile CHANGED
@@ -1,3 +1,2 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
  require 'bundler/gem_tasks'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Load gem dependencies.
@@ -1,11 +1,10 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
  require 'rack/session/abstract/id'
4
3
  require 'redic'
4
+ require 'securerandom'
5
5
 
6
6
  module Rack
7
7
  module Session
8
- #
9
8
  # Rack::Session::Redic provides simple cookie based session management.
10
9
  # Session data is stored in Redis via the Redic gem. The corresponding
11
10
  # session key is maintained in the cookie.
@@ -25,46 +24,64 @@ module Rack
25
24
  # refresh the expiration set in Redis with each request.
26
25
  #
27
26
  # Any other options will get passed to Rack::Session::Abstract::Persisted.
28
- #
29
27
  class Redic < Abstract::Persisted
30
- REDIS_URL = 'REDIS_URL'.freeze
31
-
28
+ # Redis commands.
29
+ DELETE = 'DEL'
30
+ EX = 'EX'
31
+ EXISTS = 'EXISTS'
32
+ GET = 'GET'
33
+ SET = 'SET'
34
+
35
+ # Assorted.
36
+ REDIS_URL = 'REDIS_URL'
37
+ ZERO = 0
38
+
39
+ # Access the storage interface directly. Needed for testing.
40
+ #
41
+ # @return [Redic]
32
42
  attr_reader :storage
33
43
 
34
44
  def initialize(app, options = {})
35
45
  super
36
46
 
47
+ @expires = options[:expire_after]
48
+ @marshaller = options.fetch(:marshaller) { Marshal }
37
49
  @mutex = Mutex.new
38
- @storage = Storage.new(
39
- options[:expire_after],
40
- options.fetch(:marshaller) { Marshal },
41
- options.fetch(:url) { ENV.fetch(REDIS_URL) }
42
- )
50
+ @storage = ::Redic.new(options.fetch(:url) { ENV.fetch(REDIS_URL) })
43
51
  end
44
52
 
45
- # Only accept a generated session ID if it doesn't exist.
53
+ # Generate a session ID that doesn't already exist.
54
+ #
55
+ # Based on Rack::Session::Abstract::Persisted#generate_sid and
56
+ # Rack::Session::Memcache#generate_sid but without the conditional check.
57
+ # We always generate the session ID from SecureRandom#hex.
58
+ #
59
+ # @return [String]
46
60
  def generate_sid
47
61
  loop do
48
- sid = super
49
- break sid unless @storage.exists?(sid)
62
+ session_id = SecureRandom.hex(@sid_length)
63
+ break session_id unless @storage.call(EXISTS, session_id) != ZERO
50
64
  end
51
65
  end
52
66
 
53
67
  # Find the session (or generate a blank one).
54
- def find_session(_req, sid)
68
+ def find_session(_req, session_id)
55
69
  @mutex.synchronize do
56
- unless sid && session = @storage.get(sid)
57
- sid, session = generate_sid, {}
70
+ unless session_id && (session = deserialize(@storage.call(GET, session_id)))
71
+ session_id, session = generate_sid, {} # rubocop:disable Style/ParallelAssignment
58
72
  end
59
73
 
60
- [sid, session]
74
+ [session_id, session]
61
75
  end
62
76
  end
63
77
 
64
78
  # Write the session.
65
79
  def write_session(_req, session_id, new_session, _options)
80
+ arguments = [SET, session_id, serialize(new_session)]
81
+ arguments += [EX, @expires] if @expires
82
+
66
83
  @mutex.synchronize do
67
- @storage.set(session_id, new_session)
84
+ @storage.call(*arguments)
68
85
 
69
86
  session_id
70
87
  end
@@ -73,105 +90,34 @@ module Rack
73
90
  # Kill the session.
74
91
  def delete_session(_req, session_id, options)
75
92
  @mutex.synchronize do
76
- @storage.delete(session_id)
93
+ @storage.call(DELETE, session_id)
77
94
  generate_sid unless options[:drop]
78
95
  end
79
96
  end
80
97
 
81
- # A wrapper around Redic to simplify calls.
82
- class Storage
83
- # Redis commands.
84
- DELETE = 'DEL'.freeze
85
- EX = 'EX'.freeze
86
- EXISTS = 'EXISTS'.freeze
87
- GET = 'GET'.freeze
88
- SET = 'SET'.freeze
89
-
90
- # Assorted.
91
- ZERO = 0
92
-
93
- # @param expires [Integer]
94
- # The number of seconds for Redis to retain keys.
95
- # @param marshaller [#dump, #load]
96
- # The module or class used to marshal objects. It must respond to
97
- # #dump and #load.
98
- # @param url [String]
99
- # The URL to access Redis at.
100
- def initialize(expires, marshaller, url)
101
- @expires = expires
102
- @marshaller = marshaller
103
- @storage = ::Redic.new(url)
104
- end
105
-
106
- # Check for an identifier's existence.
107
- #
108
- # @param id [String]
109
- # The key to check for.
110
- # @return [Boolean]
111
- def exists?(id)
112
- @storage.call(EXISTS, id) != ZERO
113
- end
114
-
115
- # Retrieve an object.
116
- #
117
- # @param id [String]
118
- # The key in Redis to retrieve from.
119
- # @return [Object, nil]
120
- # The object stored at the identifier provided, or nil.
121
- def get(id)
122
- deserialize(@storage.call(GET, id))
123
- end
124
-
125
- # Store an object.
126
- #
127
- # @param id [String]
128
- # The key to use to store the object.
129
- # @param object [Object]
130
- # Any object that can be serialized.
131
- # @return [String]
132
- # See {https://redis.io/commands/set#return-value Redis' docs for more}.
133
- def set(id, object)
134
- arguments = [SET, id, serialize(object)]
135
- arguments += [EX, @expires] if @expires
136
-
137
- @storage.call(*arguments)
138
- end
139
-
140
- # Remove an object.
141
- #
142
- # @param id [String]
143
- # The key to delete.
144
- # @return [Integer]
145
- # The number of keys that were deleted. See
146
- # {https://redis.io/commands/del#return-value Redis' docs for more}.
147
- def delete(id)
148
- @storage.call(DELETE, id)
149
- end
150
-
151
- private
152
-
153
- # Serialize an object using our marshaller.
154
- #
155
- # @param object [Object]
156
- # @return [String]
157
- # The object serialized by the marshaller.
158
- def serialize(object)
159
- @marshaller.dump(object)
160
- end
161
-
162
- # Deserialize a string back into an object.
163
- #
164
- # @param string [String]
165
- # @return [Object, nil]
166
- # Returns the object as loaded by the marshaller, or nil.
167
- def deserialize(string)
168
- @marshaller.load(string) if string
169
-
170
- # In the case that loading fails, return a nil.
171
- rescue
172
- nil
173
- end
98
+ # Serialize an object using our marshaller.
99
+ #
100
+ # @param object [Object]
101
+ # @return [String]
102
+ # The object as serialized by the marshaller.
103
+ def serialize(object)
104
+ @marshaller.dump(object)
105
+ end
106
+ private :serialize
107
+
108
+ # Deserialize a string back into an object.
109
+ #
110
+ # @param string [String]
111
+ # @return [Object, nil]
112
+ # Returns the object as loaded by the marshaller, or nil.
113
+ def deserialize(string)
114
+ @marshaller.load(string) if string
115
+
116
+ # In the case that loading fails, return a nil.
117
+ rescue # rubocop:disable Lint/RescueWithoutErrorClass
118
+ nil
174
119
  end
120
+ private :deserialize
175
121
  end
176
122
  end
177
123
  end
@@ -1,8 +1,7 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
  Gem::Specification.new do |spec|
4
3
  spec.name = 'rack-redic'
5
- spec.version = '1.3.0'
4
+ spec.version = '1.4.0'
6
5
  spec.authors = ['Evan Lecklider']
7
6
  spec.email = ['evan@lecklider.com']
8
7
 
@@ -17,6 +16,5 @@ Gem::Specification.new do |spec|
17
16
  spec.add_dependency 'redic'
18
17
 
19
18
  spec.add_development_dependency 'minitest'
20
- spec.add_development_dependency 'msgpack'
21
- spec.add_development_dependency 'oj'
19
+ spec.add_development_dependency 'rubocop'
22
20
  end
@@ -1,5 +1,5 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
2
+ require_relative 'helper'
3
3
 
4
4
  # Require all test files.
5
5
  Dir.glob('test/*.rb').each(&method(:require))
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # Add our project folder to the root of our load path.
@@ -8,7 +7,7 @@ $LOAD_PATH.unshift File.expand_path('../..', __FILE__)
8
7
  ENV['REDIS_URL'] ||= 'redis://localhost:6379'
9
8
 
10
9
  # Require our core library.
11
- require 'rack/session/redic'
10
+ require 'lib/rack/session/redic'
12
11
 
13
12
  # Kick off the tests.
14
13
  require 'minitest/autorun'
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
  require 'rack/lint'
4
3
  require 'rack/mock'
@@ -9,7 +8,7 @@ describe Rack::Session::Redic do
9
8
  ROOT = '/'
10
9
 
11
10
  session_key = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS[:key]
12
- session_match = /#{session_key}=([0-9a-fA-F]+);/
11
+ session_match = /#{ session_key }=([0-9a-fA-F]+);/
13
12
 
14
13
  incrementor = lambda do |env|
15
14
  env['rack.session']['counter'] ||= 0
@@ -65,8 +64,8 @@ describe Rack::Session::Redic do
65
64
  response = request.get(ROOT)
66
65
  sid = response[Rack::SET_COOKIE][session_match, 1]
67
66
 
68
- assert_equal request.get("/?rack.session=#{sid}").body, '{"counter"=>1}'
69
- assert_equal request.get("/?rack.session=#{sid}").body, '{"counter"=>1}'
67
+ assert_equal request.get("/?rack.session=#{ sid }").body, '{"counter"=>1}'
68
+ assert_equal request.get("/?rack.session=#{ sid }").body, '{"counter"=>1}'
70
69
  end
71
70
 
72
71
  it 'determines session from params' do
@@ -75,8 +74,8 @@ describe Rack::Session::Redic do
75
74
  response = request.get(ROOT)
76
75
  sid = response[Rack::SET_COOKIE][session_match, 1]
77
76
 
78
- assert_equal request.get("/?rack.session=#{sid}").body, '{"counter"=>2}'
79
- assert_equal request.get("/?rack.session=#{sid}").body, '{"counter"=>3}'
77
+ assert_equal request.get("/?rack.session=#{ sid }").body, '{"counter"=>2}'
78
+ assert_equal request.get("/?rack.session=#{ sid }").body, '{"counter"=>3}'
80
79
  end
81
80
 
82
81
  it 'survives nonexistant cookies' do
@@ -88,7 +87,7 @@ describe Rack::Session::Redic do
88
87
  assert_equal response.body, '{"counter"=>1}'
89
88
 
90
89
  cookie = response[Rack::SET_COOKIE][session_match]
91
- refute_match /#{ bad_cookie }/, cookie
90
+ refute_match(/#{ bad_cookie }/, cookie)
92
91
  end
93
92
 
94
93
  it 'maintains freshness' do
@@ -224,10 +223,10 @@ describe Rack::Session::Redic do
224
223
 
225
224
  res0 = request.get(ROOT)
226
225
  session_id = (cookie = res0[Rack::SET_COOKIE])[session_match, 1]
227
- ses0 = redic.storage.get(session_id)
226
+ ses0 = redic.storage.call('GET', session_id)
228
227
 
229
228
  request.get(ROOT, Rack::HTTP_COOKIE => cookie)
230
- ses1 = redic.storage.get(session_id)
229
+ ses1 = redic.storage.call('GET', session_id)
231
230
 
232
231
  refute_equal ses1, ses0
233
232
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-redic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Lecklider
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-12 00:00:00.000000000 Z
11
+ date: 2017-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -53,21 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: msgpack
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: oj
56
+ name: rubocop
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -89,21 +75,18 @@ extra_rdoc_files: []
89
75
  files:
90
76
  - ".editorconfig"
91
77
  - ".gitignore"
78
+ - ".rubocop.yml"
92
79
  - CODE_OF_CONDUCT.md
93
- - Gemfile
94
80
  - LICENSE.txt
95
81
  - Makefile
96
82
  - README.md
97
83
  - Rakefile
84
+ - gems.rb
98
85
  - lib/rack/session/redic.rb
99
86
  - rack-redic.gemspec
100
87
  - test/all.rb
101
88
  - test/helper.rb
102
89
  - test/session_redic_test.rb
103
- - test/storage_msgpack_test.rb
104
- - test/storage_oj_test.rb
105
- - test/storage_test.rb
106
- - test/support/storage_marshaller_interface.rb
107
90
  homepage: https://github.com/evanleck/rack-redic
108
91
  licenses:
109
92
  - MIT
@@ -124,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
107
  version: '0'
125
108
  requirements: []
126
109
  rubyforge_project:
127
- rubygems_version: 2.6.13
110
+ rubygems_version: 2.7.3
128
111
  signing_key:
129
112
  specification_version: 4
130
113
  summary: Rack::Session in Redis via Redic
@@ -132,7 +115,3 @@ test_files:
132
115
  - test/all.rb
133
116
  - test/helper.rb
134
117
  - test/session_redic_test.rb
135
- - test/storage_msgpack_test.rb
136
- - test/storage_oj_test.rb
137
- - test/storage_test.rb
138
- - test/support/storage_marshaller_interface.rb
@@ -1,28 +0,0 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- require 'msgpack'
4
- require_relative 'support/storage_marshaller_interface'
5
-
6
- MessagePack::DefaultFactory.register_type(0x00, Symbol)
7
-
8
- module MessagePackMarshaller
9
- def dump(object)
10
- MessagePack.pack(object)
11
- end
12
- module_function :dump
13
-
14
- def load(string)
15
- MessagePack.unpack(string)
16
- end
17
- module_function :load
18
- end
19
-
20
- describe Rack::Session::Redic::Storage do
21
- describe 'using the MessagePack as the marshaller' do
22
- include StorageMarshallerInterface
23
-
24
- before do
25
- @store = Rack::Session::Redic::Storage.new(nil, MessagePackMarshaller, ENV['REDIS_URL'])
26
- end
27
- end
28
- end
@@ -1,14 +0,0 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- require 'oj'
4
- require_relative 'support/storage_marshaller_interface'
5
-
6
- describe Rack::Session::Redic::Storage do
7
- describe 'using the Oj as the marshaller' do
8
- include StorageMarshallerInterface
9
-
10
- before do
11
- @store = Rack::Session::Redic::Storage.new(nil, Oj, ENV['REDIS_URL'])
12
- end
13
- end
14
- end
@@ -1,13 +0,0 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- require_relative 'support/storage_marshaller_interface'
4
-
5
- describe Rack::Session::Redic::Storage do
6
- describe 'using the default marshaller' do
7
- include StorageMarshallerInterface
8
-
9
- before do
10
- @store = Rack::Session::Redic::Storage.new(nil, Marshal, ENV['REDIS_URL'])
11
- end
12
- end
13
- end
@@ -1,30 +0,0 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
- module StorageMarshallerInterface
4
- def test_returns_nil_for_empty_keys
5
- assert_nil @store.get('not-here')
6
- end
7
-
8
- def test_saves_objects
9
- object = { saved: true }
10
- @store.set('saving', object)
11
-
12
- assert_equal @store.get('saving'), object
13
- end
14
-
15
- def test_existence_of_keys
16
- @store.set('exists', false)
17
-
18
- assert_equal @store.exists?('exists'), true
19
- end
20
-
21
- def test_deletes_objects
22
- object = { deleted: true }
23
- @store.set('deleted', object)
24
-
25
- assert_equal @store.get('deleted'), object
26
- @store.delete('deleted')
27
-
28
- assert_nil @store.get('deleted')
29
- end
30
- end