rails_rate_limit 0.1.2 → 0.2.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
2
  SHA256:
3
- metadata.gz: cf52b273c158732c58a654255744cbc096ddab47348f16684211435074dfd9b9
4
- data.tar.gz: 239cf6c9e06d1300d057c28a2bdcd065de265799d58c369e061e9787e504879b
3
+ metadata.gz: f84a9dd27c84c9d0519657dcdc6a03da54339a00951fba0e4dfe847e210bc416
4
+ data.tar.gz: 68ed631f37784ac86f12e261cd28e99caf879f4b604604f5c0717b9e9a071062
5
5
  SHA512:
6
- metadata.gz: 17198b2b17fe32b8dea0d56d99a02157cc4e0f50e103006b6faea197d38b2206c9810243cdf06a1c0e3c95807bd63d00feea07a426f358f026d60c7c57a5e37b
7
- data.tar.gz: b1b66ee43016fd1db38083833228c779507dd586573cd9d47a3d69bd0a5cac45e6c478308a9e399d370fe5618b9182c657c55e8b09ff0e4ca465a6dbe25a2e6e
6
+ metadata.gz: 0d5822c1423345099c7d42a21ca11951720de2f9be00e7858fdf9ffee69b3e970454ed878e57e36c75ee74e49c213a0de1a079f2a476c52c95cdaabefdc34138
7
+ data.tar.gz: 736ce16dddb1b5e238e88570cd67cbce3895f2bb51a61a10a5d635112d4fe3d3489a33bf01735ddc67ebf350a669f668c3ce1952324a8ba5145649c0806cc379
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Rails Rate Limit
1
+ # **Rails Rate Limit**
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rails_rate_limit.svg)](https://badge.fury.io/rb/rails_rate_limit)
4
4
  [![Build Status](https://github.com/kasvit/rails_rate_limit/workflows/Ruby/badge.svg)](https://github.com/kasvit/rails_rate_limit/actions)
@@ -99,23 +99,33 @@ end
99
99
 
100
100
  ### Rate Limiting Methods
101
101
 
102
- You can limit any instance method in your classes (class methods are not supported yet):
102
+ You can limit both instance and class methods in your classes:
103
103
 
104
104
  ```ruby
105
105
  class ApiClient
106
- include RailsRateLimit::Klass # include this module
106
+ include RailsRateLimit::Klass
107
107
 
108
+ # Instance method
108
109
  def make_request
109
110
  # Your API call logic here
110
111
  end
111
112
 
112
- # IMPORTANT: set_rate_limit must be called AFTER method definition
113
- # Basic usage
113
+ # Class method
114
+ def self.bulk_request
115
+ # Your API call logic here
116
+ end
117
+
118
+ # Rate limit for instance method
114
119
  set_rate_limit :make_request,
115
120
  limit: 100,
116
121
  period: 1.minute
117
122
 
118
- # Advanced usage with all options
123
+ # Rate limit for class method
124
+ set_rate_limit :bulk_request,
125
+ limit: 10,
126
+ period: 1.hour
127
+
128
+ # Advanced usage with all options (instance method)
119
129
  set_rate_limit :another_method,
120
130
  limit: 10, # Maximum calls allowed
121
131
  period: 1.hour, # Time window for the limit
@@ -128,21 +138,26 @@ class ApiClient
128
138
  nil # Method will return nil
129
139
  }
130
140
 
131
- # Example with default handler that raises error
132
- set_rate_limit :risky_method,
133
- limit: 5,
134
- period: 1.minute
135
- # Without on_exceeded option it will use default handler
136
- # that raises RailsRateLimit::RateLimitExceeded
137
-
138
- # Example with custom error handling
139
- def safe_request
140
- risky_method
141
- rescue RailsRateLimit::RateLimitExceeded => e
142
- # Handle the error
143
- Rails.logger.warn("Rate limit exceeded: #{e.message}")
144
- nil # or any other fallback value
145
- end
141
+ # Advanced usage with all options (class method)
142
+ set_rate_limit :another_class_method,
143
+ limit: 5, # Maximum calls allowed
144
+ period: 1.day, # Time window for the limit
145
+ by: -> { "global:#{name}" }, # Method call identifier
146
+ store: :redis, # Override default store
147
+ on_exceeded: -> { # Custom error handler
148
+ log_exceeded_event
149
+ "Rate limit exceeded" # Return custom message
150
+ }
151
+
152
+ # Direct rate limit setting
153
+ # You can also set rate limits directly if you have both instance and class methods with the same name
154
+ set_instance_rate_limit :process, # For instance method
155
+ limit: 10,
156
+ period: 1.hour
157
+
158
+ set_class_rate_limit :process, # For class method
159
+ limit: 5,
160
+ period: 1.hour
146
161
  end
147
162
  ```
148
163
 
@@ -153,7 +168,8 @@ For both controllers and methods:
153
168
  - `period`: (Required) Time period for the limit (in seconds or ActiveSupport::Duration)
154
169
  - `by`: (Optional) Lambda/Proc to generate unique identifier
155
170
  - Default for controllers: `"#{controller.class.name}:#{controller.request.remote_ip}"`
156
- - Default for methods: `"#{self.class.name}##{method_name}:#{respond_to?(:id) ? 'id='+id.to_s : 'object_id='+object_id.to_s}"`
171
+ - Default for instance methods: `"#{self.class.name}##{method_name}:#{respond_to?(:id) ? 'id='+id.to_s : 'object_id='+object_id.to_s}"`
172
+ - Default for class methods: `"#{class.name}.#{method_name}"`
157
173
  - `store`: (Optional) Override default storage backend (`:redis`, `:memcached`, `:memory`)
158
174
  - `on_exceeded`: (Optional) Custom handler for rate limit exceeded
159
175
 
@@ -8,6 +8,18 @@ module RailsRateLimit
8
8
  def set_rate_limit(method_name, limit:, period:, by: nil, store: nil, on_exceeded: nil)
9
9
  Validations.validate_options!(limit: limit, period: period, by: by, store: store)
10
10
 
11
+ if method_defined?(method_name) || private_method_defined?(method_name)
12
+ set_instance_rate_limit(method_name, limit: limit, period: period, by: by, store: store,
13
+ on_exceeded: on_exceeded)
14
+ elsif singleton_class.method_defined?(method_name) || singleton_class.private_method_defined?(method_name)
15
+ set_class_rate_limit(method_name, limit: limit, period: period, by: by, store: store,
16
+ on_exceeded: on_exceeded)
17
+ else
18
+ raise ArgumentError, "Method #{method_name} is not defined"
19
+ end
20
+ end
21
+
22
+ def set_instance_rate_limit(method_name, limit:, period:, by:, store:, on_exceeded:)
11
23
  original_method = instance_method(method_name)
12
24
 
13
25
  define_method(method_name) do |*args, &block|
@@ -30,6 +42,30 @@ module RailsRateLimit
30
42
  end
31
43
  end
32
44
  end
45
+
46
+ def set_class_rate_limit(method_name, limit:, period:, by:, store:, on_exceeded:)
47
+ original_method = singleton_class.instance_method(method_name)
48
+
49
+ singleton_class.define_method(method_name) do |*args, &block|
50
+ limiter = RateLimiter.new(
51
+ context: self,
52
+ by: by || lambda {
53
+ "#{name}.#{method_name}"
54
+ },
55
+ limit: limit,
56
+ period: period.to_i,
57
+ store: store
58
+ )
59
+
60
+ begin
61
+ limiter.perform!
62
+ original_method.bind(self).call(*args, &block)
63
+ rescue RailsRateLimit::RateLimitExceeded
64
+ handler = on_exceeded.nil? ? RailsRateLimit.configuration.handle_klass_exceeded : on_exceeded
65
+ instance_exec(&handler)
66
+ end
67
+ end
68
+ end
33
69
  end
34
70
  end
35
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsRateLimit
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_rate_limit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasvit