rotary 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e616099ac3f3a34ce265d1f42e771ac374552d0f
4
+ data.tar.gz: 408de669b529a19ad5364aa69c5b11629f2ead6f
5
+ SHA512:
6
+ metadata.gz: c7eb3a202628eea15bf889da875abe9f92d1299f52cdfbef4bb9f0b875faae1bca35af467d3a1f28f1911aa6e5c6a99af2238579d920e79d2a19bc939edee104
7
+ data.tar.gz: f083d93aca69e5ccded0991225f1b32ccaffbae3e6067790effeca63af4e5809d5cf24a605b28b1ab7eff7fe4dffd05b4ed29e35795906f52e72ab4327088618
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Denis Redozubov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH << File.expand_path('./lib')
2
+ require "rotary"
3
+
4
+ task :build do
5
+ system "gem build rotary.gemspec"
6
+ end
7
+
8
+ task :release => :build do
9
+ system "gem push rotary-#{Rotary::VERSION}"
10
+ end
11
+
12
+ task :console do
13
+ require 'pry'
14
+ require 'rotary'
15
+ ARGV.clear
16
+ Pry.start
17
+ end
18
+ task :c => :console
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new do |t|
23
+ t.libs << "lib"
24
+ t.libs << "spec"
25
+ t.test_files = FileList['spec/**/*_spec.rb']
26
+ t.verbose = true
27
+ end
28
+ task :spec => :test
29
+ task :default => :test
@@ -0,0 +1 @@
1
+ Rotary::Serializer::Marshal = Marshal
@@ -0,0 +1,15 @@
1
+ # Needed for testing. Acts as example.
2
+ module Rotary
3
+ module Serializer
4
+ module String
5
+ def self.dump(value)
6
+ value.to_s
7
+ end
8
+
9
+ def self.load(value)
10
+ value
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,38 @@
1
+ require 'rotary/serializer/string'
2
+ require 'rotary/serializer/marshal'
3
+
4
+ module Rotary::Serializer
5
+
6
+ class Error < Exception
7
+ end
8
+
9
+ class << self
10
+ def load_serializer(serializer)
11
+ case serializer
12
+ when Symbol
13
+ load_const(serializer)
14
+ else
15
+ unless valid?(serializer)
16
+ raise Rotary::Serializer::Error,
17
+ "#{serializer}:#{serializer.class} doesn't respond to either '.load' or '.dump'"
18
+ end
19
+ serializer
20
+ end
21
+ end
22
+
23
+ def load_const(serializer)
24
+ const_get("Rotary::Serializer::#{serializer.capitalize}")
25
+ rescue NameError
26
+ raise_wrong_serializer!(serializer)
27
+ end
28
+
29
+ def valid?(serializer)
30
+ serializer.respond_to?(:dump) && serializer.respond_to?(:load)
31
+ end
32
+
33
+ def raise_wrong_serializer!(serializer)
34
+ raise Rotary::Serializer::Error, "Wrong serializer #{serializer} of class #{serializer.class}"
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,26 @@
1
+ module Rotary
2
+ module Storage
3
+ class Memory
4
+ def initialize(*)
5
+ clear
6
+ end
7
+
8
+ def push(session)
9
+ @storage.unshift(session)
10
+ self
11
+ end
12
+
13
+ def pop
14
+ @storage.pop
15
+ end
16
+
17
+ def size
18
+ @storage.size
19
+ end
20
+
21
+ def clear
22
+ @storage = []
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ require 'digest/sha1'
2
+ require 'redis'
3
+
4
+ module Rotary
5
+ module Storage
6
+ class Redis
7
+
8
+ class Retry < Exception
9
+ end
10
+
11
+ def self.default_connection
12
+ ::Redis.new
13
+ end
14
+
15
+ def initialize(connection:, ttl:, serializer:, prefix: 'rotary')
16
+ @redis = connection
17
+ @prefix = "#{prefix}::"
18
+ @ttl = ttl # in seconds
19
+ @serializer = serializer
20
+ @pool_list = "#{@prefix}pool"
21
+ end
22
+
23
+ def push(obj)
24
+ serialized = @serializer.dump(obj)
25
+ # TODO: make lpush + set/expire transactional somehow
26
+ @redis.lpush(@pool_list, serialized)
27
+ if @ttl
28
+ key = ttl_key(serialized)
29
+ @redis.multi do
30
+ @redis.set(key, 1)
31
+ @redis.expire(key, @ttl)
32
+ end
33
+ end
34
+ self
35
+ end
36
+
37
+ def pop
38
+ serialized = @redis.rpop(@pool_list)
39
+ obj = serialized ? @serializer.load(serialized) : nil
40
+ return obj unless @ttl
41
+ # TTL-only logic below
42
+ key = ttl_key(serialized)
43
+ raise Retry unless @redis.get(key)
44
+ @redis.del(key)
45
+ obj
46
+ rescue Retry
47
+ retry
48
+ end
49
+
50
+ def size
51
+ @redis.llen(@pool_list)
52
+ end
53
+
54
+ def clear
55
+ @redis.del(@pool_list)
56
+ end
57
+
58
+ protected
59
+
60
+ def ttl_key(obj)
61
+ "#{@prefix}#{Digest::SHA1.hexdigest(obj)}"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,17 @@
1
+ require 'rotary/storage/memory'
2
+ require 'rotary/storage/redis'
3
+
4
+ module Rotary
5
+ module Storage
6
+
7
+ class Error < Exception
8
+ end
9
+
10
+ def self.load_storage(storage)
11
+ const_get("Rotary::Storage::#{storage.capitalize}")
12
+ rescue NameError
13
+ raise Rotary::Storage::Error,
14
+ "Wrong storage #{storage} of class #{storage.class}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module Rotary
2
+ VERSION = '0.1.0'
3
+ end
4
+
data/lib/rotary.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'rotary/version'
2
+ require 'rotary/storage'
3
+ require 'rotary/serializer'
4
+
5
+ module Rotary
6
+ SERIALIZER = :marshal
7
+ STORAGE = :redis
8
+ LIMIT = 100
9
+ PREFIX = 'rotary'
10
+ TTL = nil # must be nil or seconds
11
+
12
+ class OverflowError < Exception; end
13
+
14
+ def self.pool(**options)
15
+ Pool.new(**options)
16
+ end
17
+
18
+ class Pool
19
+ def initialize(
20
+ storage: STORAGE,
21
+ connection: nil,
22
+ serializer: SERIALIZER,
23
+ limit: LIMIT,
24
+ ttl: TTL,
25
+ prefix: PREFIX,
26
+ on_overflow: ->(obj) { raise OverflowError },
27
+ create: create
28
+ )
29
+ @limit = limit
30
+ storage_options = connection ? { connection: connection } : {}
31
+ @create_obj = create
32
+ @on_overflow = on_overflow
33
+ storage = Rotary::Storage.load_storage(storage)
34
+ @serializer = Rotary::Serializer.load_serializer(serializer)
35
+ @storage = storage.new(
36
+ connection: connection || storage.default_connection,
37
+ ttl: ttl,
38
+ serializer: @serializer,
39
+ prefix: prefix
40
+ )
41
+ end
42
+
43
+ def get
44
+ @storage.pop || @create_obj.call
45
+ end
46
+
47
+ # block should return object, because object could've been mutated
48
+ def with
49
+ object = get
50
+ object = yield(object)
51
+ set(object)
52
+ end
53
+
54
+ def size
55
+ @storage.size
56
+ end
57
+
58
+ def clear
59
+ @storage.clear
60
+ end
61
+
62
+ def set(obj)
63
+ return @on_overflow.call(obj) if @limit && @storage.size >= @limit
64
+ @storage.push(obj)
65
+ end
66
+
67
+ end
68
+ end
69
+
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rotary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Redozubov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 10.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '10.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 10.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: pry
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.9'
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: 0.9.12.6
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.9'
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: 0.9.12.6
53
+ - !ruby/object:Gem::Dependency
54
+ name: turn
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.9'
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.9.7
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.9'
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: 0.9.7
73
+ - !ruby/object:Gem::Dependency
74
+ name: redis
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.0'
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.7
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: 3.0.7
93
+ description: |2
94
+ Generic pool with pluggable backends for external storage. This way pool can be used by multiple application servers. It can be used to store sessions for external services.
95
+ email: denis.redozubov@gmail.com
96
+ executables: []
97
+ extensions: []
98
+ extra_rdoc_files: []
99
+ files:
100
+ - LICENSE
101
+ - README.md
102
+ - Rakefile
103
+ - lib/rotary.rb
104
+ - lib/rotary/serializer.rb
105
+ - lib/rotary/serializer/marshal.rb
106
+ - lib/rotary/serializer/string.rb
107
+ - lib/rotary/storage.rb
108
+ - lib/rotary/storage/memory.rb
109
+ - lib/rotary/storage/redis.rb
110
+ - lib/rotary/version.rb
111
+ homepage: http://github.com/dredozubov/rotary
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.2.2
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Generic pool with pluggable backends.
135
+ test_files: []