julewire-rails 1.0.1 → 1.1.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/docs/capture-and-filtering.md +4 -3
  4. data/docs/configuration.md +3 -2
  5. data/julewire-rails.gemspec +3 -3
  6. data/lib/julewire/rails/configuration.rb +4 -4
  7. data/lib/julewire/rails/context_body_proxy.rb +8 -3
  8. data/lib/julewire/rails/debug_exception_log_silencer.rb +9 -18
  9. data/lib/julewire/rails/doctor_app.rb +21 -21
  10. data/lib/julewire/rails/lifecycle_hooks.rb +0 -11
  11. data/lib/julewire/rails/log_subscriber_silencer.rb +4 -17
  12. data/lib/julewire/rails/logger.rb +29 -24
  13. data/lib/julewire/rails/logger_outputs.rb +0 -3
  14. data/lib/julewire/rails/output_requirement.rb +2 -2
  15. data/lib/julewire/rails/parameter_filter_plan.rb +13 -37
  16. data/lib/julewire/rails/parameter_filter_processor.rb +13 -45
  17. data/lib/julewire/rails/parameter_filters.rb +21 -0
  18. data/lib/julewire/rails/railtie.rb +42 -28
  19. data/lib/julewire/rails/request_attributes.rb +37 -16
  20. data/lib/julewire/rails/request_completion.rb +21 -20
  21. data/lib/julewire/rails/request_context.rb +29 -7
  22. data/lib/julewire/rails/request_error_ownership.rb +11 -19
  23. data/lib/julewire/rails/request_fields.rb +2 -2
  24. data/lib/julewire/rails/request_lifecycle.rb +7 -13
  25. data/lib/julewire/rails/request_middleware.rb +14 -13
  26. data/lib/julewire/rails/request_summary_timeout_scheduler.rb +0 -9
  27. data/lib/julewire/rails/structured_event_record.rb +11 -39
  28. data/lib/julewire/rails/subscribers/controller_response.rb +9 -14
  29. data/lib/julewire/rails/subscribers/error.rb +11 -15
  30. data/lib/julewire/rails/subscribers/event.rb +6 -8
  31. data/lib/julewire/rails/subscribers/rendered_exception.rb +12 -16
  32. data/lib/julewire/rails/version.rb +1 -1
  33. metadata +9 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f58689c6d6e15c3e4b12887ce1cbc0e744a6335cc733e28b7200b430dff90a5
4
- data.tar.gz: 5558cedae8f43deefe4358e8033d9d41f346f2c8b7b1e559a8521ab48a01f28d
3
+ metadata.gz: '0788f684a45eba2f940fb5a836cb45c7aef84ae6c67d68da62c2e38e4376dcae'
4
+ data.tar.gz: 72559f89728d55e90a231d25d3bc60a37453fcbaec0f0c8c5e21728547e0cb5b
5
5
  SHA512:
6
- metadata.gz: ff52b5a8269c70172251391cb16f375d98c5171055b01f7640cc23f0d4d63b781a22d91a1d9bd593202dbab21124130bea0bbd2347e006d536f0d43c937306fa
7
- data.tar.gz: 5d1e00972c69b1dd7066c0280e4f8d2c8deb1ae3684abc8dc78b701cd04a3d4b6130c8b2c38fce91768dbe832b7434a7c33be4c9d24b3d1cb8e22d934a9cb719
6
+ metadata.gz: 137c77cfabe1a91768ce04b7df57e1c00d44f4ec97103fa21ce5ebc333e48135d034ebaead86dfd9ce945d43aa0a834c0a6f3027d4b63da0c440172c842882d5
7
+ data.tar.gz: 7190bcf29e2aa09995ee3728c9102b25b24ed89ed8d0597c0d51e0de4fe2a1d27c4e8f8e3a20ac7b277a7f9f73c2dc60e8c6faae778c595824a5ead78883288f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 1.1.0 - 2026-07-20
4
+
5
+ - Roll back pushed request tags when request instrumentation fails during
6
+ middleware startup.
7
+ - Harden request logging, filtering, suppression, and error ownership around
8
+ Julewire 1.1 record contracts.
9
+ - Require Julewire 1.1.0 internal gems.
10
+
3
11
  ## 1.0.1 - 2026-06-25
4
12
 
5
13
  - Require julewire 1.0.1 internal gems.
@@ -31,8 +31,8 @@ Captured response summaries include:
31
31
  - `response_body_bytes`
32
32
  - `response_body_truncated`
33
33
 
34
- `*_body_bytes` is the content length when the framework provides it; otherwise
35
- it is the number of bytes observed while capturing.
34
+ `*_body_bytes` is the declared content length or the bytes observed while
35
+ capturing. When both are known, Julewire reports the larger value.
36
36
 
37
37
  Request and response headers use `false`, `true`, or an explicit header list:
38
38
 
@@ -48,7 +48,8 @@ end
48
48
  When header capture is `true`, Julewire omits common sensitive headers such as
49
49
  `authorization`, `cookie`, `set-cookie`, `proxy-authorization`, and
50
50
  `x-api-key`. Use an explicit header list if the application deliberately wants
51
- one of those fields.
51
+ one of those fields. Treat `headers = true` as controlled debugging; production
52
+ configs should prefer explicit allowlists.
52
53
 
53
54
  Captured request summaries can include:
54
55
 
@@ -38,8 +38,9 @@ These defaults are intended for a normal Rails app:
38
38
  | `filter_event_payloads` | `true` | Filter serialized object-event hashes with Rails parameter filters. |
39
39
  | `rendered_exceptions` | `false` | Emit diagnostic rendered-exception point records in addition to summaries. |
40
40
 
41
- Broad header capture (`*.headers = true`) skips common sensitive headers.
42
- Explicit header lists are authoritative.
41
+ Broad header capture (`*.headers = true`) skips common sensitive headers but is
42
+ still a debugging shape. Production configs should prefer explicit header
43
+ lists.
43
44
 
44
45
  `structured_event_prefixes = nil` accepts all structured-event names. Use it
45
46
  only when the app wants Julewire to consider every Rails event.
@@ -35,9 +35,9 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  spec.add_dependency "actionpack", ">= 8.1"
37
37
  spec.add_dependency "actionview", ">= 8.1"
38
- spec.add_dependency "julewire-core", ">= 1.0.1"
39
- spec.add_dependency "julewire-rack", ">= 1.0.1"
40
- spec.add_dependency "julewire-rails_support", ">= 1.0.1"
38
+ spec.add_dependency "julewire-core", ">= 1.1.0"
39
+ spec.add_dependency "julewire-rack", ">= 1.1.0"
40
+ spec.add_dependency "julewire-rails_support", ">= 1.1.0"
41
41
  spec.add_dependency "logger", ">= 1.7"
42
42
  spec.add_dependency "railties", ">= 8.1"
43
43
  spec.add_dependency "zeitwerk", ">= 2.8.1"
@@ -46,14 +46,14 @@ module Julewire
46
46
  private
47
47
 
48
48
  def validate_carry_request_headers(value)
49
- return value unless value == true
49
+ return unless value == true
50
50
 
51
51
  raise Error, "carry_request_headers must be an explicit header list"
52
52
  end
53
53
 
54
54
  def validate_request_summary_timeout(value)
55
- return value if value.nil?
56
- return value if value.is_a?(Numeric) && value.positive?
55
+ return if value.nil?
56
+ return if value.is_a?(Numeric) && value.positive?
57
57
 
58
58
  raise Error, "request_summary_timeout must be nil or a positive Numeric"
59
59
  end
@@ -67,7 +67,7 @@ module Julewire
67
67
 
68
68
  def validate_capture_settings(settings)
69
69
  settings.validate!
70
- settings
70
+ nil
71
71
  end
72
72
  end
73
73
  end
@@ -11,7 +11,7 @@ module Julewire
11
11
  end
12
12
 
13
13
  def each(&block)
14
- return enum_for(:each) unless block_given?
14
+ return enum_for unless block_given?
15
15
 
16
16
  @handle.with_context do
17
17
  @body.each { block.yield(it) }
@@ -31,8 +31,13 @@ module Julewire
31
31
 
32
32
  def closed? = @closed
33
33
 
34
- def respond_to_missing?(method_name, include_private = false)
35
- (method_name != :to_str && @body.respond_to?(method_name, include_private)) || super
34
+ def respond_to_missing?(method_name, _include_private)
35
+ case method_name
36
+ when :to_str
37
+ false
38
+ else
39
+ @body.respond_to?(method_name)
40
+ end
36
41
  end
37
42
 
38
43
  def method_missing(method_name, ...)
@@ -5,9 +5,9 @@ require "action_dispatch/middleware/debug_exceptions"
5
5
  module Julewire
6
6
  module Rails
7
7
  module DebugExceptionLogSilencer
8
- Patch = Module.new do
8
+ module Patch
9
9
  def log_error(request, wrapper)
10
- return if Julewire::Rails::DebugExceptionLogSilencer.suppress?(request, wrapper)
10
+ return if DebugExceptionLogSilencer.suppress?
11
11
 
12
12
  super
13
13
  end
@@ -17,26 +17,11 @@ module Julewire
17
17
  class << self
18
18
  def install!(configuration)
19
19
  @configuration = configuration
20
- return false unless defined?(::ActionDispatch::DebugExceptions)
21
- return true if @installed
22
20
 
23
21
  ::ActionDispatch::DebugExceptions.prepend(Patch)
24
- @installed = true
25
22
  end
26
23
 
27
- def suppress?(_request, _wrapper)
28
- suppress_reported_logs?
29
- rescue StandardError => e
30
- IntegrationHealth.record_failure(
31
- e,
32
- action: :suppress?,
33
- component: :debug_exception_log_silencer
34
- )
35
- end
36
-
37
- private
38
-
39
- def suppress_reported_logs?
24
+ def suppress?
40
25
  configuration = @configuration
41
26
  return false unless configuration
42
27
 
@@ -46,6 +31,12 @@ module Julewire
46
31
  else
47
32
  !configuration.reported_exception_logs
48
33
  end
34
+ rescue StandardError => e
35
+ IntegrationHealth.record_failure(
36
+ e,
37
+ action: :suppress?,
38
+ component: :debug_exception_log_silencer
39
+ )
49
40
  end
50
41
  end
51
42
  end
@@ -67,8 +67,8 @@ module Julewire
67
67
  "Julewire Doctor",
68
68
  [
69
69
  "<p>Status: <strong>#{escape(report.fetch(:status))}</strong></p>",
70
- "<p>Level: <code>#{escape(report.dig(:runtime, :level))}</code></p>",
71
- "<p>Pipeline: <strong>#{escape(report.dig(:pipeline, :status))}</strong></p>",
70
+ "<p>Level: <code>#{escape(report.fetch(:runtime).fetch(:level))}</code></p>",
71
+ "<p>Pipeline: <strong>#{escape(report.fetch(:pipeline).fetch(:status))}</strong></p>",
72
72
  "<h2>Warnings</h2>",
73
73
  warning_items.empty? ? "<p>None</p>" : "<ul>#{warning_items}</ul>",
74
74
  nav_links(request, ["/tail", "Tail"], ["/doctor.json", "JSON"])
@@ -79,14 +79,15 @@ module Julewire
79
79
  def render_tail(request)
80
80
  return page("Julewire Tail", "<p>Tail is not attached.</p>") unless @tail
81
81
 
82
+ table = <<~HTML
83
+ <table><thead><tr><th>Severity</th><th>Event</th><th>Message</th></tr></thead>
84
+ <tbody data-tail-records data-tail-events-path="#{escape(app_path(request, "/tail/events"))}">
85
+ #{tail_rows}
86
+ </tbody></table>
87
+ HTML
82
88
  body = [
83
89
  "<p>#{@tail.health.fetch(:size)} / #{@tail.capacity} records</p>",
84
- [
85
- "<table><thead><tr><th>Severity</th><th>Event</th><th>Message</th></tr></thead>",
86
- %(<tbody data-tail-records data-tail-events-path="#{escape(app_path(request, "/tail/events"))}">),
87
- tail_rows,
88
- "</tbody></table>"
89
- ].join,
90
+ table,
90
91
  tail_nav(request),
91
92
  tail_script
92
93
  ].join
@@ -99,13 +100,11 @@ module Julewire
99
100
 
100
101
  def tail_row(entry)
101
102
  record = entry.record
102
- [
103
- "<tr data-sequence=\"#{entry.sequence}\">",
104
- "<td><code>#{escape(record["severity"])}</code></td>",
105
- "<td><code>#{escape(record["event"])}</code></td>",
106
- "<td>#{escape(record["message"])}</td>",
103
+ "<tr data-sequence=\"#{entry.sequence}\">" \
104
+ "<td><code>#{escape(record["severity"])}</code></td>" \
105
+ "<td><code>#{escape(record["event"])}</code></td>" \
106
+ "<td>#{escape(record["message"])}</td>" \
107
107
  "</tr>"
108
- ].join
109
108
  end
110
109
 
111
110
  def tail_nav(request)
@@ -117,7 +116,7 @@ module Julewire
117
116
  end
118
117
 
119
118
  def tail_entries
120
- @tail ? @tail.entries(limit: TAIL_LIMIT) : []
119
+ @tail.entries(limit: TAIL_LIMIT)
121
120
  end
122
121
 
123
122
  def tail_events(request)
@@ -135,7 +134,7 @@ module Julewire
135
134
  def event_cursor(request)
136
135
  value = request.get_header("HTTP_LAST_EVENT_ID")
137
136
  value = request.params["after"] if value.nil? || value.empty?
138
- Integer(value || 0)
137
+ Integer(value)
139
138
  rescue ArgumentError, TypeError
140
139
  0
141
140
  end
@@ -190,8 +189,9 @@ module Julewire
190
189
  end
191
190
 
192
191
  def app_path(request, path)
193
- base = request.script_name.to_s
194
- base = "" if base == "/"
192
+ base = request.script_name
193
+ return path if base == "/"
194
+
195
195
  "#{base}#{path}"
196
196
  end
197
197
 
@@ -200,7 +200,7 @@ module Julewire
200
200
  end
201
201
 
202
202
  def link_to(request, path, label)
203
- %(<a href="#{escape(app_path(request, path))}">#{escape(label)}</a>)
203
+ %(<a href="#{escape(app_path(request, path))}">#{label}</a>)
204
204
  end
205
205
 
206
206
  def page(title, body)
@@ -209,7 +209,7 @@ module Julewire
209
209
  <html>
210
210
  <head>
211
211
  <meta charset="utf-8">
212
- <title>#{escape(title)}</title>
212
+ <title>#{title}</title>
213
213
  <style>
214
214
  body { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; margin: 2rem; color: #171717; }
215
215
  a { color: #0b5fff; margin-right: 1rem; }
@@ -218,7 +218,7 @@ module Julewire
218
218
  </style>
219
219
  </head>
220
220
  <body>
221
- <h1>#{escape(title)}</h1>
221
+ <h1>#{title}</h1>
222
222
  #{body}
223
223
  </body>
224
224
  </html>
@@ -29,18 +29,8 @@ module Julewire
29
29
  RequestErrorOwnership.clear
30
30
  end
31
31
 
32
- # Private testing seam for isolating process lifecycle hooks.
33
- def reset_for_test!
34
- @mutex.synchronize do
35
- @at_exit_installed = false
36
- @fork_tracker_installed = false
37
- end
38
- end
39
-
40
32
  private
41
33
 
42
- private :reset_for_test!
43
-
44
34
  def install_at_exit!(registrar, configuration)
45
35
  return if @at_exit_installed
46
36
 
@@ -64,7 +54,6 @@ module Julewire
64
54
  action: :install_after_fork,
65
55
  component: :lifecycle_hooks
66
56
  )
67
- nil
68
57
  end
69
58
 
70
59
  def active_support_fork_tracker
@@ -22,7 +22,10 @@ module Julewire
22
22
  class << self
23
23
  def silence!
24
24
  require_log_subscribers
25
- SUBSCRIBERS.each { |class_name, namespace| detach(class_name, namespace) }
25
+ SUBSCRIBERS.each do |class_name, namespace|
26
+ subscriber_class = Julewire::RailsSupport::LogSubscribers.constantize(class_name)
27
+ Julewire::RailsSupport::LogSubscribers.detach(subscriber_class, namespace)
28
+ end
26
29
  end
27
30
 
28
31
  private
@@ -30,22 +33,6 @@ module Julewire
30
33
  def require_log_subscribers
31
34
  LOG_SUBSCRIBER_FILES.each { Core::Integration::Lifecycle.require_optional(it) }
32
35
  end
33
-
34
- def detach(class_name, namespace)
35
- subscriber_class = constantize(class_name)
36
- return if subscriber_class.nil?
37
-
38
- subscriber_class.detach_from(namespace) if subscriber_class.respond_to?(:detach_from)
39
- Julewire::RailsSupport::EventReporter.unsubscribe_log_subscriber(subscriber_class)
40
- end
41
-
42
- def constantize(class_name)
43
- class_name.split("::").reject(&:empty?).inject(Object) do |namespace, constant_name|
44
- break unless namespace.const_defined?(constant_name, false)
45
-
46
- namespace.const_get(constant_name, false)
47
- end
48
- end
49
36
  end
50
37
  end
51
38
  end
@@ -24,13 +24,13 @@ module Julewire
24
24
  return true if severity < level
25
25
  return true if Suppression.active?
26
26
 
27
- message, progname = resolve_message_and_progname(message, progname) { block_given? ? yield : nil }
28
- Core::RuntimeLocator.current.emit_without_level(record_for(severity, message, progname))
27
+ message, progname = resolve_message_and_progname(message, progname) { yield if block_given? }
28
+ Julewire::Core::RuntimeLocator.current.emit_without_level(record_for(severity, message, progname))
29
29
  true
30
30
  end
31
31
 
32
32
  def <<(message)
33
- add(::Logger::UNKNOWN, message)
33
+ add(nil, message)
34
34
  end
35
35
 
36
36
  def debug(progname = nil, &) = add(::Logger::DEBUG, nil, progname, &)
@@ -43,7 +43,7 @@ module Julewire
43
43
 
44
44
  def fatal(progname = nil, &) = add(::Logger::FATAL, nil, progname, &)
45
45
 
46
- def unknown(progname = nil, &) = add(::Logger::UNKNOWN, nil, progname, &)
46
+ def unknown(progname = nil, &) = add(nil, nil, progname, &)
47
47
 
48
48
  def debug? = level <= ::Logger::DEBUG
49
49
 
@@ -104,9 +104,8 @@ module Julewire
104
104
  Julewire.flush
105
105
  end
106
106
 
107
- def initialize_copy(other)
108
- super
109
- @progname = other.progname.is_a?(String) ? other.progname.dup : other.progname
107
+ def initialize_copy(_other)
108
+ @progname = @progname.dup if @progname.is_a?(String)
110
109
  @local_level_key = :"julewire_rails_logger_level_#{object_id}"
111
110
  end
112
111
 
@@ -117,31 +116,41 @@ module Julewire
117
116
  when Integer
118
117
  value
119
118
  when Symbol, String
120
- ::Logger::Severity.const_get(value.to_s.upcase)
119
+ ::Logger::Severity.const_get(value.upcase)
121
120
  else
122
- raise ArgumentError, "invalid log level: #{value.inspect}"
121
+ raise_invalid_level(value)
123
122
  end
124
123
  rescue NameError
124
+ raise_invalid_level(value)
125
+ end
126
+
127
+ def raise_invalid_level(value)
125
128
  raise ArgumentError, "invalid log level: #{value.inspect}"
126
129
  end
127
130
 
128
131
  def resolve_message_and_progname(message, progname)
129
- return [message, progname || self.progname] unless message.nil?
132
+ return [message, progname] unless message.nil?
130
133
 
131
134
  block_message = yield
132
- return [block_message, progname || self.progname] unless block_message.nil?
135
+ return [block_message, progname] unless block_message.nil?
133
136
 
134
- [progname, self.progname]
137
+ [progname]
135
138
  end
136
139
 
137
140
  def record_for(severity, message, progname)
138
141
  record = message.is_a?(Hash) ? structured_message(message) : scalar_message(message)
139
- record[:severity] = Julewire::Core::Records::Severity.severity_symbol(severity) || :unknown
140
- record[:logger] ||= (progname || self.progname).to_s
142
+ record[:severity] = record_severity(severity)
143
+ record[:logger] ||= (progname || @progname).to_s
141
144
  record[:source] ||= @source
142
145
  merge_current_tags(record)
143
146
  end
144
147
 
148
+ def record_severity(value)
149
+ Julewire::Core::Records::Severity.normalize(value)
150
+ rescue ArgumentError
151
+ :unknown
152
+ end
153
+
145
154
  def scalar_message(message)
146
155
  case message
147
156
  when Exception
@@ -156,28 +165,24 @@ module Julewire
156
165
  record = fields.slice(*RECORD_KEYS)
157
166
  payload = fields.except(*RECORD_KEYS)
158
167
 
159
- unless payload.empty?
160
- record[:payload] = Julewire::Core::Fields::FieldSet.merge(payload_hash(record[:payload]), payload)
161
- end
168
+ record[:payload] = Julewire::Core::Fields::FieldSet.merge(payload_hash(record[:payload]), payload)
162
169
  record
163
170
  end
164
171
 
165
172
  def payload_hash(payload)
166
173
  return {} if payload.nil?
167
- return payload if payload.is_a?(Hash)
174
+ return payload if payload.instance_of?(Hash)
168
175
 
169
176
  { Julewire::Core::Fields::FieldSet::VALUE_KEY => payload }
170
177
  end
171
178
 
172
179
  def merge_current_tags(record)
173
- current_tags = formatter.respond_to?(:current_tags) ? formatter.current_tags : nil
180
+ current_tags = formatter.current_tags if formatter.respond_to?(:current_tags)
174
181
  return record if current_tags.nil? || current_tags.empty?
175
182
 
176
- attributes = record[:attributes].is_a?(Hash) ? record[:attributes] : {}
177
- rails = attributes[:rails].is_a?(Hash) ? attributes[:rails] : {}
178
- rails[:tags] = Julewire::Core::Fields::FieldSet.deep_dup(current_tags)
179
- attributes[:rails] = rails
180
- record[:attributes] = attributes
183
+ record[:attributes] = {
184
+ rails: { tags: current_tags }
185
+ }
181
186
  record
182
187
  end
183
188
  end
@@ -7,10 +7,7 @@ module Julewire
7
7
  module LoggerOutputs
8
8
  class << self
9
9
  def install!
10
- return if @installed
11
-
12
10
  ::ActiveSupport::Logger.singleton_class.prepend(Patch)
13
- @installed = true
14
11
  end
15
12
 
16
13
  def julewire_logger?(logger)
@@ -11,7 +11,7 @@ module Julewire
11
11
  return unless settings.logger?
12
12
 
13
13
  mode = normalized_mode(settings.require_output)
14
- return if mode == false || health.dig(:pipeline, :configured)
14
+ return if health.dig(:pipeline, :configured)
15
15
 
16
16
  case mode
17
17
  when :warn
@@ -25,7 +25,7 @@ module Julewire
25
25
 
26
26
  def normalized_mode(value)
27
27
  case value
28
- when false, nil then false
28
+ when false, nil then nil
29
29
  when true, :warn, "warn" then :warn
30
30
  when :raise, "raise" then :raise
31
31
  else
@@ -4,32 +4,31 @@ module Julewire
4
4
  module Rails
5
5
  class ParameterFilterPlan
6
6
  FILTERED = ::ActiveSupport::ParameterFilter::FILTERED
7
- RECORD_CONTAINER_KEYS = Core::Processing::RecordFieldTransform.container_keys
8
- RECORD_SCALAR_KEYS = Core::Processing::RecordFieldTransform.scalar_keys
9
7
  private_constant :FILTERED
10
- private_constant :RECORD_CONTAINER_KEYS
11
- private_constant :RECORD_SCALAR_KEYS
12
-
13
- attr_reader :filtered_field_keys
14
8
 
15
9
  class << self
16
10
  def build(filters)
17
11
  filters = Array(filters)
18
12
  return if filters.any? { it.is_a?(Regexp) || it.is_a?(Proc) }
19
13
 
20
- new(filters)
14
+ simple, deep = partition_filters(filters)
15
+ return unless simple.any? && deep.empty?
16
+
17
+ new(simple)
18
+ end
19
+
20
+ private
21
+
22
+ def partition_filters(filters)
23
+ filters.map { it.to_s.downcase }.partition { !it.include?(".") }
21
24
  end
22
25
  end
26
+ private_class_method :new
23
27
 
24
28
  def initialize(filters)
25
- simple, deep = partition_filters(filters)
26
- @filtered_field_keys = build_filtered_field_keys(simple, deep)
27
- @direct_container_filter = simple.any? && deep.empty?
28
- @simple_pattern = simple_filter_pattern(simple) if @direct_container_filter
29
+ @simple_pattern = simple_filter_pattern(filters)
29
30
  end
30
31
 
31
- def direct_container_filter? = @direct_container_filter
32
-
33
32
  def filter_value(value)
34
33
  return filter_hash(value) if value.is_a?(Hash)
35
34
  return filter_array(value) if value.is_a?(Array)
@@ -39,27 +38,6 @@ module Julewire
39
38
 
40
39
  private
41
40
 
42
- def partition_filters(filters)
43
- filters.map { it.to_s.downcase }.partition { !it.include?(".") }
44
- end
45
-
46
- def build_filtered_field_keys(simple, deep)
47
- (container_filter_keys(simple, deep) + scalar_filter_keys(simple)).uniq.freeze
48
- end
49
-
50
- def container_filter_keys(simple, deep)
51
- return RECORD_CONTAINER_KEYS if simple.any?
52
-
53
- deep.filter_map { it.split(".", 2).first&.to_sym }
54
- end
55
-
56
- def scalar_filter_keys(simple)
57
- RECORD_SCALAR_KEYS.filter do |key|
58
- name = key_name(key)
59
- simple.any? { name.include?(it) }
60
- end
61
- end
62
-
63
41
  def simple_filter_pattern(filters)
64
42
  Regexp.new(filters.map { Regexp.escape(it) }.join("|"), Regexp::IGNORECASE)
65
43
  end
@@ -92,9 +70,7 @@ module Julewire
92
70
  @simple_pattern.match?(key_name(key))
93
71
  end
94
72
 
95
- def key_name(key)
96
- key.is_a?(Symbol) ? key.name : key.to_s
97
- end
73
+ def key_name(key) = key.to_s
98
74
  end
99
75
  end
100
76
  end