pecorino 0.7.1 → 0.7.3
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 +4 -4
- data/.github/workflows/ci.yml +42 -19
- data/.gitignore +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +12 -1
- data/README.md +31 -10
- data/Rakefile +13 -1
- data/gemfiles/Gemfile_ruby27_rails7 +19 -0
- data/gemfiles/Gemfile_ruby30_rails8 +15 -0
- data/lib/pecorino/adapters/base_adapter.rb +1 -1
- data/lib/pecorino/cached_throttle.rb +6 -2
- data/lib/pecorino/throttle.rb +12 -11
- data/lib/pecorino/version.rb +1 -1
- data/lib/pecorino.rb +2 -2
- data/pecorino.gemspec +1 -14
- data/rbi/pecorino.rbi +909 -0
- data/rbi/pecorino.rbs +791 -0
- data/test/adapters/adapter_test_methods.rb +259 -0
- data/test/adapters/memory_adapter_test.rb +12 -0
- data/test/adapters/postgres_adapter_test.rb +69 -0
- data/test/adapters/redis_adapter_test.rb +27 -0
- data/test/adapters/sqlite_adapter_test.rb +46 -0
- data/test/block_test.rb +23 -0
- data/test/cached_throttle_test.rb +100 -0
- data/test/leaky_bucket_test.rb +161 -0
- data/test/pecorino_test.rb +9 -0
- data/test/test_helper.rb +12 -0
- data/test/throttle_test.rb +119 -0
- metadata +19 -138
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class LeakyBucketTest < ActiveSupport::TestCase
|
6
|
+
def memory_adapter
|
7
|
+
@adapter ||= Pecorino::Adapters::MemoryAdapter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# This test is performed multiple times since time is involved, and there can be fluctuations
|
11
|
+
# between the iterations
|
12
|
+
8.times do |n|
|
13
|
+
test "on iteration #{n} accepts a certain number of tokens and returns the new bucket level" do
|
14
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
15
|
+
assert_in_delta bucket.state.level, 0, 0.0001
|
16
|
+
|
17
|
+
state = bucket.fillup(20)
|
18
|
+
assert_predicate state, :full?
|
19
|
+
assert_in_delta state.level, 15.0, 0.0001
|
20
|
+
|
21
|
+
sleep 0.2
|
22
|
+
assert_in_delta bucket.state.level, 14.77, 0.1
|
23
|
+
|
24
|
+
sleep 0.3
|
25
|
+
assert_in_delta bucket.state.level, 14.4, 0.1
|
26
|
+
assert_in_delta bucket.fillup(-3).level, 11.4, 0.1
|
27
|
+
|
28
|
+
assert_in_delta bucket.fillup(-300).level, 0, 0.1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
test "exposes the parameters via reader methods" do
|
33
|
+
bucket = Pecorino::LeakyBucket.new(key: "some-bk", leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
34
|
+
assert_equal bucket.key, "some-bk"
|
35
|
+
assert_equal bucket.leak_rate, 1.1
|
36
|
+
assert_equal bucket.capacity, 15.0
|
37
|
+
end
|
38
|
+
|
39
|
+
test "translates over_time into an appropriate leak_rate at instantiation" do
|
40
|
+
throttle = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 10, capacity: 20, adapter: memory_adapter)
|
41
|
+
assert_in_delta 2.0, throttle.leak_rate, 0.01
|
42
|
+
end
|
43
|
+
|
44
|
+
test "tells whether it is able to accept a value which will bring it to capacity" do
|
45
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 1, capacity: 3, adapter: memory_adapter)
|
46
|
+
assert bucket.able_to_accept?(3)
|
47
|
+
end
|
48
|
+
|
49
|
+
test "allows either of leak_rate or over_time to be used" do
|
50
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
51
|
+
bucket.fillup(20)
|
52
|
+
sleep 0.2
|
53
|
+
assert_in_delta bucket.state.level, 14.77, 0.1
|
54
|
+
|
55
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 13.6, capacity: 15, adapter: memory_adapter)
|
56
|
+
bucket.fillup(20)
|
57
|
+
sleep 0.2
|
58
|
+
assert_in_delta bucket.state.level, 14.77, 0.1
|
59
|
+
|
60
|
+
assert_raises(ArgumentError) do
|
61
|
+
Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 13.6, leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
62
|
+
end
|
63
|
+
|
64
|
+
assert_raises(ArgumentError) do
|
65
|
+
Pecorino::LeakyBucket.new(key: Random.uuid, capacity: 15, adapter: memory_adapter)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
test "does not allow a bucket to be created with a negative value" do
|
70
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
71
|
+
assert_in_delta bucket.state.level, 0, 0.0001
|
72
|
+
|
73
|
+
state = bucket.fillup(-10)
|
74
|
+
assert_in_delta state.level, 0, 0.1
|
75
|
+
end
|
76
|
+
|
77
|
+
test "allows check for the bucket leaking out" do
|
78
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 1.1, capacity: 15, adapter: memory_adapter)
|
79
|
+
assert_in_delta bucket.state.level, 0, 0.0001
|
80
|
+
|
81
|
+
state = bucket.fillup(10)
|
82
|
+
refute_predicate state, :full?
|
83
|
+
|
84
|
+
refute bucket.able_to_accept?(6)
|
85
|
+
assert bucket.able_to_accept?(4)
|
86
|
+
assert_in_delta bucket.state.level, 10.0, 0.1
|
87
|
+
end
|
88
|
+
|
89
|
+
test "allows the bucket to leak out completely" do
|
90
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, leak_rate: 2, capacity: 1, adapter: memory_adapter)
|
91
|
+
assert_predicate bucket.fillup(1), :full?
|
92
|
+
|
93
|
+
sleep(0.25)
|
94
|
+
assert_in_delta bucket.state.level, 0.5, 0.1
|
95
|
+
|
96
|
+
sleep(0.25)
|
97
|
+
assert_in_delta bucket.state.level, 0, 0.1
|
98
|
+
end
|
99
|
+
|
100
|
+
test "with conditional fillup, allows a freshly created bucket to be filled to capacity with one call" do
|
101
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
102
|
+
assert bucket.fillup_conditionally(1.0).accepted?
|
103
|
+
end
|
104
|
+
|
105
|
+
test "with conditional fillup, refuses a fillup that would overflow" do
|
106
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
107
|
+
refute bucket.fillup_conditionally(1.1).accepted?
|
108
|
+
end
|
109
|
+
|
110
|
+
test "with conditional fillup, allows an existing bucket to be filled to capacity on the second call (INSERT vs. UPDATE)" do
|
111
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
112
|
+
bucket.fillup(0.0) # Ensure the bucket row gets created
|
113
|
+
assert bucket.fillup_conditionally(1.0).accepted?
|
114
|
+
end
|
115
|
+
|
116
|
+
test "with conditional fillup, allows an existing bucket to be filled to capacity in a sequence of calls" do
|
117
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
118
|
+
assert bucket.fillup_conditionally(0.5).accepted?
|
119
|
+
assert bucket.fillup_conditionally(0.5).accepted?
|
120
|
+
refute bucket.fillup_conditionally(0.1).accepted?
|
121
|
+
end
|
122
|
+
|
123
|
+
test "with conditional fillup, allows an existing bucket to be filled close to capacity in a sequence of calls" do
|
124
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
125
|
+
assert bucket.fillup_conditionally(0.5).accepted?
|
126
|
+
assert bucket.fillup_conditionally(0.4).accepted?
|
127
|
+
refute bucket.fillup_conditionally(0.2).accepted?
|
128
|
+
end
|
129
|
+
|
130
|
+
test "allows conditional fillup" do
|
131
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 1.0, capacity: 1.0, adapter: memory_adapter)
|
132
|
+
|
133
|
+
counter = 0
|
134
|
+
try_fillup = ->(fillup_by, should_have_reached_level, should_have_accepted) {
|
135
|
+
counter += 1
|
136
|
+
state = bucket.fillup_conditionally(fillup_by)
|
137
|
+
assert_equal should_have_accepted, state.accepted?, "Update #{counter} did_accept should be #{should_have_accepted}"
|
138
|
+
assert_in_delta should_have_reached_level, state.level, 0.1
|
139
|
+
}
|
140
|
+
|
141
|
+
try_fillup.call(1.1, 0.0, false) # Oversized fillup must be refused outright
|
142
|
+
try_fillup.call(0.3, 0.3, true)
|
143
|
+
try_fillup.call(0.3, 0.6, true)
|
144
|
+
try_fillup.call(0.3, 0.9, true)
|
145
|
+
try_fillup.call(0.3, 0.9, false) # Would take the bucket to 1.2, so must be rejected
|
146
|
+
|
147
|
+
sleep(0.2) # Leak out 0.2 tokens
|
148
|
+
|
149
|
+
try_fillup.call(0.3, 1.0, true)
|
150
|
+
try_fillup.call(-2, 0.0, true) # A negative fillup is permitted since it will never take the bucket above capacity
|
151
|
+
try_fillup.call(1.0, 1.0, true) # Filling up in one step should be permitted
|
152
|
+
end
|
153
|
+
|
154
|
+
test "allows conditional fillup even if the bucket leaks out to 0 between calls" do
|
155
|
+
bucket = Pecorino::LeakyBucket.new(key: Random.uuid, over_time: 0.5, capacity: 30, adapter: memory_adapter)
|
156
|
+
assert bucket.fillup_conditionally(29.6).accepted?
|
157
|
+
refute bucket.fillup_conditionally(1).accepted?
|
158
|
+
sleep 0.6 # Spend enough time to allow the bucket to leak out completely
|
159
|
+
assert bucket.fillup_conditionally(1).accepted?, "Once the bucket has leaked out to 0 the fillup should be accepted again"
|
160
|
+
end
|
161
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "pecorino"
|
5
|
+
|
6
|
+
require "minitest/autorun"
|
7
|
+
require "active_support"
|
8
|
+
require "active_support/test_case"
|
9
|
+
require "active_record"
|
10
|
+
|
11
|
+
class ActiveSupport::TestCase
|
12
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class ThrottleTest < ActiveSupport::TestCase
|
6
|
+
def memory_adapter
|
7
|
+
@adapter ||= Pecorino::Adapters::MemoryAdapter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
test "request! installs a block and then removes it and communicates the block using exceptions" do
|
11
|
+
throttle = Pecorino::Throttle.new(key: Random.uuid, over_time: 1.0, capacity: 30, adapter: memory_adapter)
|
12
|
+
|
13
|
+
state_after_first_request = throttle.request!
|
14
|
+
assert_kind_of Pecorino::Throttle::State, state_after_first_request
|
15
|
+
|
16
|
+
# It must be possible to make exactly 30 requests without getting throttled, even if the
|
17
|
+
# bucket does not leak out at all between the calls
|
18
|
+
29.times do
|
19
|
+
throttle.request!
|
20
|
+
end
|
21
|
+
|
22
|
+
# The 31st request must always fail, as it won't fit into the bucket anymore (even if some
|
23
|
+
# tokens have leaked out by this point)
|
24
|
+
err = assert_raises Pecorino::Throttle::Throttled do
|
25
|
+
throttle.request!
|
26
|
+
end
|
27
|
+
assert_equal throttle, err.throttle
|
28
|
+
assert_in_delta err.retry_after, 1, 0.1
|
29
|
+
assert_kind_of Pecorino::Throttle::State, err.state
|
30
|
+
|
31
|
+
# Sleep until the block gets released - the block gets for block_for, which is the time it takes the bucket
|
32
|
+
# to leak out to 0
|
33
|
+
sleep 1.1
|
34
|
+
assert_nothing_raised do
|
35
|
+
throttle.request!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
test "allows the block_for parameter to be omitted" do
|
40
|
+
assert_nothing_raised do
|
41
|
+
Pecorino::Throttle.new(key: Random.uuid, over_time: 1, capacity: 30, adapter: memory_adapter)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
test "still throttles using request() without raising exceptions" do
|
46
|
+
throttle = Pecorino::Throttle.new(key: Random.uuid, leak_rate: 30, capacity: 30, block_for: 3, adapter: memory_adapter)
|
47
|
+
|
48
|
+
20.times do
|
49
|
+
state = throttle.request
|
50
|
+
refute_predicate state, :blocked?
|
51
|
+
end
|
52
|
+
|
53
|
+
20.times do
|
54
|
+
throttle.request
|
55
|
+
end
|
56
|
+
|
57
|
+
state = throttle.request
|
58
|
+
assert_predicate state, :blocked?
|
59
|
+
|
60
|
+
assert_in_delta state.blocked_until - Time.now, 3, 0.5
|
61
|
+
sleep 0.5
|
62
|
+
|
63
|
+
# Ensure we are still throttled
|
64
|
+
state = throttle.request
|
65
|
+
assert_predicate state, :blocked?
|
66
|
+
assert_in_delta state.blocked_until - Time.now, 2.5, 0.5
|
67
|
+
assert_kind_of Time, state.blocked_until
|
68
|
+
|
69
|
+
sleep(3.05)
|
70
|
+
state = throttle.request
|
71
|
+
refute_predicate state, :blocked?
|
72
|
+
end
|
73
|
+
|
74
|
+
test "able_to_accept? returns the prediction whether the throttle will accept" do
|
75
|
+
throttle = Pecorino::Throttle.new(key: Random.uuid, leak_rate: 30, capacity: 30, block_for: 2, adapter: memory_adapter)
|
76
|
+
|
77
|
+
assert throttle.able_to_accept?
|
78
|
+
assert throttle.able_to_accept?(29)
|
79
|
+
refute throttle.able_to_accept?(31)
|
80
|
+
|
81
|
+
# Depending on timing either the 30th or the 31st request may start to throttle
|
82
|
+
assert_raises Pecorino::Throttle::Throttled do
|
83
|
+
loop { throttle.request! }
|
84
|
+
end
|
85
|
+
refute throttle.able_to_accept?
|
86
|
+
|
87
|
+
sleep 2.5
|
88
|
+
assert throttle.able_to_accept?
|
89
|
+
end
|
90
|
+
|
91
|
+
test "starts to throttle sooner with a higher fillup rate" do
|
92
|
+
throttle = Pecorino::Throttle.new(key: Random.uuid, leak_rate: 30, capacity: 30, block_for: 3, adapter: memory_adapter)
|
93
|
+
|
94
|
+
15.times do
|
95
|
+
throttle.request!(2)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Depending on timing either the 31st or the 30th request may start to throttle
|
99
|
+
err = assert_raises Pecorino::Throttle::Throttled do
|
100
|
+
loop { throttle.request! }
|
101
|
+
end
|
102
|
+
|
103
|
+
assert_in_delta err.retry_after, 3, 0.5
|
104
|
+
end
|
105
|
+
|
106
|
+
test "throttled() calls the block just once" do
|
107
|
+
throttle = Pecorino::Throttle.new(key: Random.uuid, over_time: 60, capacity: 1, adapter: memory_adapter)
|
108
|
+
|
109
|
+
counter = 0
|
110
|
+
|
111
|
+
10.times do
|
112
|
+
throttle.throttled do
|
113
|
+
counter += 1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
assert_equal 1, counter
|
118
|
+
end
|
119
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pecorino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date: 2025-
|
10
|
+
date: 2025-04-01 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activerecord
|
@@ -24,138 +23,6 @@ dependencies:
|
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '7'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: pg
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sqlite3
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: activesupport
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '7'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '7'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rake
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '13.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '13.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: minitest
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '5.0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '5.0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: standard
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: magic_frozen_string_literal
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: minitest-fail-fast
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: redis
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '5'
|
146
|
-
- - "<"
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version: '6'
|
149
|
-
type: :development
|
150
|
-
prerelease: false
|
151
|
-
version_requirements: !ruby/object:Gem::Requirement
|
152
|
-
requirements:
|
153
|
-
- - "~>"
|
154
|
-
- !ruby/object:Gem::Version
|
155
|
-
version: '5'
|
156
|
-
- - "<"
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '6'
|
159
26
|
description: Pecorino allows you to define throttles and rate meters for your metered
|
160
27
|
resources, all through your standard DB
|
161
28
|
email:
|
@@ -167,12 +34,15 @@ files:
|
|
167
34
|
- ".github/workflows/ci.yml"
|
168
35
|
- ".gitignore"
|
169
36
|
- ".standard.yml"
|
37
|
+
- ".yardopts"
|
170
38
|
- CHANGELOG.md
|
171
39
|
- CODE_OF_CONDUCT.md
|
172
40
|
- Gemfile
|
173
41
|
- LICENSE.txt
|
174
42
|
- README.md
|
175
43
|
- Rakefile
|
44
|
+
- gemfiles/Gemfile_ruby27_rails7
|
45
|
+
- gemfiles/Gemfile_ruby30_rails8
|
176
46
|
- lib/pecorino.rb
|
177
47
|
- lib/pecorino/adapters/base_adapter.rb
|
178
48
|
- lib/pecorino/adapters/memory_adapter.rb
|
@@ -189,6 +59,19 @@ files:
|
|
189
59
|
- lib/pecorino/throttle.rb
|
190
60
|
- lib/pecorino/version.rb
|
191
61
|
- pecorino.gemspec
|
62
|
+
- rbi/pecorino.rbi
|
63
|
+
- rbi/pecorino.rbs
|
64
|
+
- test/adapters/adapter_test_methods.rb
|
65
|
+
- test/adapters/memory_adapter_test.rb
|
66
|
+
- test/adapters/postgres_adapter_test.rb
|
67
|
+
- test/adapters/redis_adapter_test.rb
|
68
|
+
- test/adapters/sqlite_adapter_test.rb
|
69
|
+
- test/block_test.rb
|
70
|
+
- test/cached_throttle_test.rb
|
71
|
+
- test/leaky_bucket_test.rb
|
72
|
+
- test/pecorino_test.rb
|
73
|
+
- test/test_helper.rb
|
74
|
+
- test/throttle_test.rb
|
192
75
|
homepage: https://github.com/cheddar-me/pecorino
|
193
76
|
licenses:
|
194
77
|
- MIT
|
@@ -196,7 +79,6 @@ metadata:
|
|
196
79
|
homepage_uri: https://github.com/cheddar-me/pecorino
|
197
80
|
source_code_uri: https://github.com/cheddar-me/pecorino
|
198
81
|
changelog_uri: https://github.com/cheddar-me/pecorino/CHANGELOG.md
|
199
|
-
post_install_message:
|
200
82
|
rdoc_options: []
|
201
83
|
require_paths:
|
202
84
|
- lib
|
@@ -211,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
93
|
- !ruby/object:Gem::Version
|
212
94
|
version: '0'
|
213
95
|
requirements: []
|
214
|
-
rubygems_version: 3.
|
215
|
-
signing_key:
|
96
|
+
rubygems_version: 3.6.2
|
216
97
|
specification_version: 4
|
217
98
|
summary: Database-based rate limiter using leaky buckets
|
218
99
|
test_files: []
|