lapsoss 0.2.0 → 0.3.1

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +153 -733
  3. data/lib/lapsoss/adapters/appsignal_adapter.rb +22 -22
  4. data/lib/lapsoss/adapters/base.rb +0 -3
  5. data/lib/lapsoss/adapters/insight_hub_adapter.rb +108 -104
  6. data/lib/lapsoss/adapters/logger_adapter.rb +1 -1
  7. data/lib/lapsoss/adapters/rollbar_adapter.rb +108 -68
  8. data/lib/lapsoss/adapters/sentry_adapter.rb +24 -24
  9. data/lib/lapsoss/backtrace_frame.rb +37 -206
  10. data/lib/lapsoss/backtrace_frame_factory.rb +228 -0
  11. data/lib/lapsoss/backtrace_processor.rb +27 -23
  12. data/lib/lapsoss/client.rb +2 -4
  13. data/lib/lapsoss/configuration.rb +28 -32
  14. data/lib/lapsoss/current.rb +10 -2
  15. data/lib/lapsoss/event.rb +28 -5
  16. data/lib/lapsoss/exception_backtrace_frame.rb +39 -0
  17. data/lib/lapsoss/exclusion_configuration.rb +30 -0
  18. data/lib/lapsoss/exclusion_filter.rb +0 -273
  19. data/lib/lapsoss/exclusion_presets.rb +249 -0
  20. data/lib/lapsoss/fingerprinter.rb +28 -28
  21. data/lib/lapsoss/http_client.rb +8 -8
  22. data/lib/lapsoss/merged_scope.rb +63 -0
  23. data/lib/lapsoss/middleware/base.rb +15 -0
  24. data/lib/lapsoss/middleware/conditional_filter.rb +18 -0
  25. data/lib/lapsoss/middleware/event_enricher.rb +19 -0
  26. data/lib/lapsoss/middleware/event_transformer.rb +19 -0
  27. data/lib/lapsoss/middleware/exception_filter.rb +43 -0
  28. data/lib/lapsoss/middleware/metrics_collector.rb +44 -0
  29. data/lib/lapsoss/middleware/rate_limiter.rb +31 -0
  30. data/lib/lapsoss/middleware/release_tracker.rb +117 -0
  31. data/lib/lapsoss/middleware/sample_filter.rb +23 -0
  32. data/lib/lapsoss/middleware/sampling_middleware.rb +18 -0
  33. data/lib/lapsoss/middleware/user_context_enhancer.rb +46 -0
  34. data/lib/lapsoss/pipeline.rb +0 -68
  35. data/lib/lapsoss/pipeline_builder.rb +69 -0
  36. data/lib/lapsoss/rails_error_subscriber.rb +42 -0
  37. data/lib/lapsoss/rails_middleware.rb +78 -0
  38. data/lib/lapsoss/railtie.rb +22 -50
  39. data/lib/lapsoss/registry.rb +18 -5
  40. data/lib/lapsoss/release_providers.rb +110 -0
  41. data/lib/lapsoss/release_tracker.rb +159 -232
  42. data/lib/lapsoss/sampling/adaptive_sampler.rb +46 -0
  43. data/lib/lapsoss/sampling/base.rb +11 -0
  44. data/lib/lapsoss/sampling/composite_sampler.rb +26 -0
  45. data/lib/lapsoss/sampling/consistent_hash_sampler.rb +30 -0
  46. data/lib/lapsoss/sampling/exception_type_sampler.rb +44 -0
  47. data/lib/lapsoss/sampling/health_based_sampler.rb +19 -0
  48. data/lib/lapsoss/sampling/rate_limiter.rb +32 -0
  49. data/lib/lapsoss/sampling/sampling_factory.rb +69 -0
  50. data/lib/lapsoss/sampling/time_based_sampler.rb +44 -0
  51. data/lib/lapsoss/sampling/uniform_sampler.rb +15 -0
  52. data/lib/lapsoss/sampling/user_based_sampler.rb +42 -0
  53. data/lib/lapsoss/scope.rb +12 -48
  54. data/lib/lapsoss/scrubber.rb +7 -7
  55. data/lib/lapsoss/user_context.rb +30 -203
  56. data/lib/lapsoss/user_context_integrations.rb +39 -0
  57. data/lib/lapsoss/user_context_middleware.rb +50 -0
  58. data/lib/lapsoss/user_context_provider.rb +93 -0
  59. data/lib/lapsoss/utils.rb +13 -0
  60. data/lib/lapsoss/validators.rb +15 -15
  61. data/lib/lapsoss/version.rb +1 -1
  62. data/lib/lapsoss.rb +3 -3
  63. metadata +60 -7
  64. data/lib/lapsoss/middleware.rb +0 -345
  65. data/lib/lapsoss/sampling.rb +0 -328
@@ -35,9 +35,9 @@ module Lapsoss
35
35
  # Apply privacy filtering
36
36
  processed[key] = if @privacy_mode && sensitive_field?(key_sym)
37
37
  apply_privacy_filter(key_sym, value)
38
- else
38
+ else
39
39
  transform_field(key_sym, value)
40
- end
40
+ end
41
41
  end
42
42
 
43
43
  processed
@@ -68,18 +68,18 @@ module Lapsoss
68
68
  segments = {}
69
69
 
70
70
  # Check for common user segments
71
- segments[:internal] = !(user_data[:internal] || user_data['internal']).nil?
72
- segments[:premium] = !(user_data[:premium] || user_data['premium']).nil?
73
- segments[:beta] = !(user_data[:beta] || user_data['beta']).nil?
74
- segments[:admin] = !(user_data[:admin] || user_data['admin']).nil?
71
+ segments[:internal] = !(user_data[:internal] || user_data["internal"]).nil?
72
+ segments[:premium] = !(user_data[:premium] || user_data["premium"]).nil?
73
+ segments[:beta] = !(user_data[:beta] || user_data["beta"]).nil?
74
+ segments[:admin] = !(user_data[:admin] || user_data["admin"]).nil?
75
75
 
76
76
  # Check role-based segments
77
- if role = user_data[:role] || user_data['role']
77
+ if role = user_data[:role] || user_data["role"]
78
78
  segments[:role] = role.to_s.downcase
79
79
  end
80
80
 
81
81
  # Check plan-based segments
82
- if plan = user_data[:plan] || user_data['plan']
82
+ if plan = user_data[:plan] || user_data["plan"]
83
83
  segments[:plan] = plan.to_s.downcase
84
84
  end
85
85
 
@@ -95,14 +95,14 @@ module Lapsoss
95
95
  key_sym = key.to_sym
96
96
 
97
97
  sanitized[key] = if sensitive_field?(key_sym)
98
- '[REDACTED]'
99
- elsif value.is_a?(Hash)
98
+ "[REDACTED]"
99
+ elsif value.is_a?(Hash)
100
100
  sanitize_for_logging(value)
101
- elsif value.is_a?(Array)
101
+ elsif value.is_a?(Array)
102
102
  value.map { |v| v.is_a?(Hash) ? sanitize_for_logging(v) : v }
103
- else
103
+ else
104
104
  value
105
- end
105
+ end
106
106
  end
107
107
 
108
108
  sanitized
@@ -123,7 +123,7 @@ module Lapsoss
123
123
  when :ip_address, :last_login_ip
124
124
  mask_ip(value)
125
125
  else
126
- '[FILTERED]'
126
+ "[FILTERED]"
127
127
  end
128
128
  end
129
129
 
@@ -136,212 +136,39 @@ module Lapsoss
136
136
  end
137
137
 
138
138
  def mask_email(email)
139
- return '[INVALID_EMAIL]' unless email.is_a?(String) && email.include?('@')
139
+ return "[INVALID_EMAIL]" unless email.is_a?(String) && email.include?("@")
140
140
 
141
- local, domain = email.split('@', 2)
142
- masked_local = local.length > 2 ? "#{local[0]}***#{local[-1]}" : '***'
141
+ local, domain = email.split("@", 2)
142
+ masked_local = local.length > 2 ? "#{local[0]}***#{local[-1]}" : "***"
143
143
  "#{masked_local}@#{domain}"
144
144
  end
145
145
 
146
146
  def mask_phone(phone)
147
- return '[INVALID_PHONE]' unless phone.is_a?(String)
147
+ return "[INVALID_PHONE]" unless phone.is_a?(String)
148
148
 
149
149
  # Remove all non-digits
150
- digits = phone.gsub(/\D/, '')
151
- return '[INVALID_PHONE]' if digits.length < 4
150
+ digits = phone.gsub(/\D/, "")
151
+ return "[INVALID_PHONE]" if digits.length < 4
152
152
 
153
153
  # Show last 4 digits
154
- ('*' * (digits.length - 4)) + digits[-4..]
154
+ ("*" * (digits.length - 4)) + digits[-4..]
155
155
  end
156
156
 
157
157
  def mask_ip(ip)
158
- return '[INVALID_IP]' unless ip.is_a?(String)
158
+ return "[INVALID_IP]" unless ip.is_a?(String)
159
159
 
160
- if ip.include?(':')
160
+ if ip.include?(":")
161
161
  # IPv6 - mask last 4 groups
162
- parts = ip.split(':')
163
- parts[-4..-1] = ['****'] * 4 if parts.length >= 4
164
- parts.join(':')
162
+ parts = ip.split(":")
163
+ parts[-4..-1] = [ "****" ] * 4 if parts.length >= 4
164
+ parts.join(":")
165
165
  else
166
166
  # IPv4 - mask last octet
167
- parts = ip.split('.')
168
- return '[INVALID_IP]' if parts.length != 4
169
-
170
- parts[-1] = '***'
171
- parts.join('.')
172
- end
173
- end
174
- end
175
-
176
- # User context provider that integrates with various authentication systems
177
- class UserContextProvider
178
- def initialize(providers: {})
179
- @providers = providers
180
- end
181
-
182
- def get_user_context(event, hint = {})
183
- context = {}
184
-
185
- # Try each provider in order
186
- @providers.each do |name, provider|
187
- if provider_context = provider.call(event, hint)
188
- context.merge!(provider_context)
189
- end
190
- rescue StandardError => e
191
- # Log provider error but don't fail
192
- warn "User context provider #{name} failed: #{e.message}"
193
- end
194
-
195
- context
196
- end
197
-
198
- # Built-in providers for common authentication systems
199
- def self.devise_provider
200
- lambda do |_event, hint|
201
- return {} unless defined?(Devise) && defined?(Warden)
202
-
203
- # Try to get user from Warden (used by Devise)
204
- if request = hint[:request]
205
- user = request.env['warden']&.user
206
- return {} unless user
207
-
208
- {
209
- id: user.id,
210
- email: user.email,
211
- username: user.respond_to?(:username) ? user.username : nil,
212
- created_at: user.created_at,
213
- role: user.respond_to?(:role) ? user.role : nil
214
- }.compact
215
- end
216
-
217
- {}
218
- end
219
- end
220
-
221
- def self.omniauth_provider
222
- lambda do |_event, hint|
223
- return {} unless defined?(OmniAuth)
224
-
225
- if (request = hint[:request]) && (auth_info = request.env['omniauth.auth'])
226
- {
227
- provider: auth_info['provider'],
228
- uid: auth_info['uid'],
229
- name: auth_info.dig('info', 'name'),
230
- email: auth_info.dig('info', 'email'),
231
- username: auth_info.dig('info', 'nickname')
232
- }.compact
233
- end
234
-
235
- {}
236
- end
237
- end
238
-
239
- def self.session_provider
240
- lambda do |_event, hint|
241
- return {} unless hint[:request]
242
-
243
- request = hint[:request]
244
- session = begin
245
- request.session
246
- rescue StandardError
247
- {}
248
- end
249
-
250
- {
251
- session_id: session[:session_id] || session['session_id'],
252
- user_id: session[:user_id] || session['user_id'],
253
- csrf_token: session[:_csrf_token] || session['_csrf_token']
254
- }.compact
255
- end
256
- end
257
-
258
- def self.thread_local_provider
259
- lambda do |_event, _hint|
260
- # Get user from thread-local storage
261
- Thread.current[:current_user] || {}
262
- end
263
- end
264
- end
265
-
266
- # Integration with popular authentication gems
267
- module UserContextIntegrations
268
- def self.setup_devise_integration
269
- return unless defined?(Devise)
270
-
271
- # Add middleware to capture user context
272
- Rails.application.config.middleware.use(UserContextMiddleware) if defined?(Rails)
273
- end
274
-
275
- def self.setup_clearance_integration
276
- return unless defined?(Clearance)
277
-
278
- # Clearance integration
279
- return unless defined?(Rails)
280
-
281
- Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
282
- middleware.user_provider = lambda do |request|
283
- request.env[:clearance].current_user if request.env[:clearance]
284
- end
285
- end
286
- end
287
-
288
- def self.setup_authlogic_integration
289
- return unless defined?(Authlogic)
290
-
291
- # Authlogic integration
292
- return unless defined?(Rails)
293
-
294
- Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
295
- middleware.user_provider = lambda do |_request|
296
- UserSession.find&.user if defined?(UserSession)
297
- end
298
- end
299
- end
300
- end
301
-
302
- # Middleware to automatically capture user context
303
- class UserContextMiddleware
304
- def initialize(app, user_provider: nil)
305
- @app = app
306
- @user_provider = user_provider
307
- end
308
-
309
- def call(env)
310
- request = Rack::Request.new(env)
311
-
312
- # Capture user context
313
- user_context = extract_user_context(request)
314
-
315
- # Store in thread-local for access during request processing
316
- Thread.current[:lapsoss_user_context] = user_context
317
-
318
- @app.call(env)
319
- ensure
320
- Thread.current[:lapsoss_user_context] = nil
321
- end
322
-
323
- private
324
-
325
- def extract_user_context(request)
326
- if @user_provider
327
- user = @user_provider.call(request)
328
- return {} unless user
167
+ parts = ip.split(".")
168
+ return "[INVALID_IP]" if parts.length != 4
329
169
 
330
- context = {
331
- id: user.id,
332
- email: user.email,
333
- username: user.respond_to?(:username) ? user.username : nil
334
- }
335
-
336
- # Add role information if available
337
- context[:role] = user.role if user.respond_to?(:role)
338
-
339
- # Add plan information if available
340
- context[:plan] = user.plan if user.respond_to?(:plan)
341
-
342
- context.compact
343
- else
344
- {}
170
+ parts[-1] = "***"
171
+ parts.join(".")
345
172
  end
346
173
  end
347
174
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lapsoss
4
+ # Integration with popular authentication gems
5
+ module UserContextIntegrations
6
+ def self.setup_devise_integration
7
+ return unless defined?(Devise)
8
+
9
+ # Add middleware to capture user context
10
+ Rails.application.config.middleware.use(UserContextMiddleware) if defined?(Rails)
11
+ end
12
+
13
+ def self.setup_clearance_integration
14
+ return unless defined?(Clearance)
15
+
16
+ # Clearance integration
17
+ return unless defined?(Rails)
18
+
19
+ Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
20
+ middleware.user_provider = lambda do |request|
21
+ request.env[:clearance].current_user if request.env[:clearance]
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.setup_authlogic_integration
27
+ return unless defined?(Authlogic)
28
+
29
+ # Authlogic integration
30
+ return unless defined?(Rails)
31
+
32
+ Rails.application.config.middleware.use(UserContextMiddleware) do |middleware|
33
+ middleware.user_provider = lambda do |_request|
34
+ UserSession.find&.user if defined?(UserSession)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lapsoss
4
+ # Middleware to automatically capture user context
5
+ class UserContextMiddleware
6
+ def initialize(app, user_provider: nil)
7
+ @app = app
8
+ @user_provider = user_provider
9
+ end
10
+
11
+ def call(env)
12
+ request = Rack::Request.new(env)
13
+
14
+ # Capture user context
15
+ user_context = extract_user_context(request)
16
+
17
+ # Store in thread-local for access during request processing
18
+ Thread.current[:lapsoss_user_context] = user_context
19
+
20
+ @app.call(env)
21
+ ensure
22
+ Thread.current[:lapsoss_user_context] = nil
23
+ end
24
+
25
+ private
26
+
27
+ def extract_user_context(request)
28
+ if @user_provider
29
+ user = @user_provider.call(request)
30
+ return {} unless user
31
+
32
+ context = {
33
+ id: user.id,
34
+ email: user.email,
35
+ username: user.respond_to?(:username) ? user.username : nil
36
+ }
37
+
38
+ # Add role information if available
39
+ context[:role] = user.role if user.respond_to?(:role)
40
+
41
+ # Add plan information if available
42
+ context[:plan] = user.plan if user.respond_to?(:plan)
43
+
44
+ context.compact
45
+ else
46
+ {}
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lapsoss
4
+ # User context provider that integrates with various authentication systems
5
+ class UserContextProvider
6
+ def initialize(providers: {})
7
+ @providers = providers
8
+ end
9
+
10
+ def get_user_context(event, hint = {})
11
+ context = {}
12
+
13
+ # Try each provider in order
14
+ @providers.each do |name, provider|
15
+ if provider_context = provider.call(event, hint)
16
+ context.merge!(provider_context)
17
+ end
18
+ rescue StandardError => e
19
+ # Log provider error but don't fail
20
+ warn "User context provider #{name} failed: #{e.message}"
21
+ end
22
+
23
+ context
24
+ end
25
+
26
+ # Built-in providers for common authentication systems
27
+ def self.devise_provider
28
+ lambda do |_event, hint|
29
+ return {} unless defined?(Devise) && defined?(Warden)
30
+
31
+ # Try to get user from Warden (used by Devise)
32
+ if request = hint[:request]
33
+ user = request.env["warden"]&.user
34
+ return {} unless user
35
+
36
+ {
37
+ id: user.id,
38
+ email: user.email,
39
+ username: user.respond_to?(:username) ? user.username : nil,
40
+ created_at: user.created_at,
41
+ role: user.respond_to?(:role) ? user.role : nil
42
+ }.compact
43
+ end
44
+
45
+ {}
46
+ end
47
+ end
48
+
49
+ def self.omniauth_provider
50
+ lambda do |_event, hint|
51
+ return {} unless defined?(OmniAuth)
52
+
53
+ if (request = hint[:request]) && (auth_info = request.env["omniauth.auth"])
54
+ {
55
+ provider: auth_info["provider"],
56
+ uid: auth_info["uid"],
57
+ name: auth_info.dig("info", "name"),
58
+ email: auth_info.dig("info", "email"),
59
+ username: auth_info.dig("info", "nickname")
60
+ }.compact
61
+ end
62
+
63
+ {}
64
+ end
65
+ end
66
+
67
+ def self.session_provider
68
+ lambda do |_event, hint|
69
+ return {} unless hint[:request]
70
+
71
+ request = hint[:request]
72
+ session = begin
73
+ request.session
74
+ rescue StandardError
75
+ {}
76
+ end
77
+
78
+ {
79
+ session_id: session[:session_id] || session["session_id"],
80
+ user_id: session[:user_id] || session["user_id"],
81
+ csrf_token: session[:_csrf_token] || session["_csrf_token"]
82
+ }.compact
83
+ end
84
+ end
85
+
86
+ def self.thread_local_provider
87
+ lambda do |_event, _hint|
88
+ # Get user from thread-local storage
89
+ Thread.current[:current_user] || {}
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lapsoss
4
+ module Utils
5
+ module_function
6
+
7
+ def current_time
8
+ if Time.respond_to?(:zone) && Time.zone
9
+ end
10
+ Time.zone.now
11
+ end
12
+ end
13
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'uri'
3
+ require "uri"
4
4
 
5
5
  module Lapsoss
6
6
  module Validators
@@ -17,7 +17,7 @@ module Lapsoss
17
17
  def validate_type!(value, types, name)
18
18
  types = Array(types)
19
19
  unless types.any? { |type| value.is_a?(type) }
20
- type_names = types.map(&:name).join(' or ')
20
+ type_names = types.map(&:name).join(" or ")
21
21
  raise ValidationError, "#{name} must be a #{type_names}, got #{value.class} (#{value.inspect})"
22
22
  end
23
23
  end
@@ -29,7 +29,7 @@ module Lapsoss
29
29
  end
30
30
 
31
31
  def validate_numeric_range!(value, range, name)
32
- validate_type!(value, [Numeric], name)
32
+ validate_type!(value, [ Numeric ], name)
33
33
  unless range.cover?(value)
34
34
  raise ValidationError, "#{name} must be between #{range.min} and #{range.max}, got #{value}"
35
35
  end
@@ -38,7 +38,7 @@ module Lapsoss
38
38
  def validate_url!(value, name)
39
39
  return if value.nil?
40
40
 
41
- validate_type!(value, [String], name)
41
+ validate_type!(value, [ String ], name)
42
42
 
43
43
  begin
44
44
  uri = URI.parse(value)
@@ -49,10 +49,10 @@ module Lapsoss
49
49
  end
50
50
  end
51
51
 
52
- def validate_dsn!(dsn_string, name = 'DSN')
52
+ def validate_dsn!(dsn_string, name = "DSN")
53
53
  return if dsn_string.nil?
54
54
 
55
- validate_type!(dsn_string, [String], name)
55
+ validate_type!(dsn_string, [ String ], name)
56
56
 
57
57
  begin
58
58
  uri = URI.parse(dsn_string)
@@ -66,7 +66,7 @@ module Lapsoss
66
66
  raise ValidationError, "#{name} must use http or https scheme" unless %w[http https].include?(uri.scheme)
67
67
 
68
68
  # Extract project ID from path
69
- path_parts = uri.path&.split('/') || []
69
+ path_parts = uri.path&.split("/") || []
70
70
  project_id = path_parts.last
71
71
  validate_presence!(project_id, "#{name} project ID")
72
72
 
@@ -81,7 +81,7 @@ module Lapsoss
81
81
 
82
82
  def validate_api_key!(value, name, format: nil)
83
83
  validate_presence!(value, name)
84
- validate_type!(value, [String], name)
84
+ validate_type!(value, [ String ], name)
85
85
 
86
86
  case format
87
87
  when :uuid
@@ -95,10 +95,10 @@ module Lapsoss
95
95
  end
96
96
  end
97
97
 
98
- def validate_environment!(value, name = 'environment')
98
+ def validate_environment!(value, name = "environment")
99
99
  return if value.nil?
100
100
 
101
- validate_type!(value, [String, Symbol], name)
101
+ validate_type!(value, [ String, Symbol ], name)
102
102
 
103
103
  env_string = value.to_s
104
104
  unless env_string.match?(/\A[a-z0-9_-]+\z/i)
@@ -106,23 +106,23 @@ module Lapsoss
106
106
  end
107
107
  end
108
108
 
109
- def validate_sample_rate!(value, name = 'sample_rate')
109
+ def validate_sample_rate!(value, name = "sample_rate")
110
110
  return if value.nil?
111
111
 
112
112
  validate_numeric_range!(value, 0.0..1.0, name)
113
113
  end
114
114
 
115
- def validate_timeout!(value, name = 'timeout')
115
+ def validate_timeout!(value, name = "timeout")
116
116
  return if value.nil?
117
117
 
118
- validate_type!(value, [Numeric], name)
118
+ validate_type!(value, [ Numeric ], name)
119
119
  raise ValidationError, "#{name} must be positive, got #{value}" if value <= 0
120
120
  end
121
121
 
122
- def validate_retries!(value, name = 'max_retries')
122
+ def validate_retries!(value, name = "max_retries")
123
123
  return if value.nil?
124
124
 
125
- validate_type!(value, [Integer], name)
125
+ validate_type!(value, [ Integer ], name)
126
126
  validate_numeric_range!(value, 0..10, name)
127
127
  end
128
128
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lapsoss
4
- VERSION = '0.2.0'
4
+ VERSION = "0.3.1"
5
5
  end
data/lib/lapsoss.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'zeitwerk'
4
- require 'active_support/core_ext/module/delegation'
3
+ require "zeitwerk"
4
+ require "active_support/core_ext/module/delegation"
5
5
 
6
6
  loader = Zeitwerk::Loader.for_gem
7
7
  loader.do_not_eager_load("#{__dir__}/lapsoss/adapters")
8
8
  loader.setup
9
9
 
10
- require_relative 'lapsoss/railtie' if defined?(Rails)
10
+ require_relative "lapsoss/railtie" if defined?(Rails::Railtie)
11
11
 
12
12
  module Lapsoss
13
13
  class Error < StandardError; end