Skip to content

Commit

Permalink
Merge pull request #46451 from jonathanhefner/parameter_filter-reinte…
Browse files Browse the repository at this point in the history
…grate-compiled_filter

Reintegrate `AS::ParameterFilter::CompiledFilter`
  • Loading branch information
jonathanhefner committed Nov 10, 2022
2 parents 7ceb703 + fd8b751 commit fbad90f
Showing 1 changed file with 53 additions and 67 deletions.
120 changes: 53 additions & 67 deletions activesupport/lib/active_support/parameter_filter.rb
Expand Up @@ -40,97 +40,83 @@ class ParameterFilter
#
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to <tt>"[FILTERED]"</tt>.
def initialize(filters = [], mask: FILTERED)
@filters = filters
@mask = mask
compile_filters!(filters)
end

# Mask value of +params+ if key matches one of filters.
def filter(params)
compiled_filter.call(params)
@no_filters ? params.dup : call(params)
end

# Returns filtered value for given key. For +Proc+ filters, third block argument is not populated.
def filter_param(key, value)
@filters.empty? ? value : compiled_filter.value_for_key(key, value)
@no_filters ? value : value_for_key(key, value)
end

private
def compiled_filter
@compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
end

class CompiledFilter # :nodoc:
def self.compile(filters, mask:)
return lambda { |params| params.dup } if filters.empty?

strings, regexps, blocks, deep_regexps, deep_strings = [], [], [], nil, nil

filters.each do |item|
case item
when Proc
blocks << item
when Regexp
if item.to_s.include?("\\.")
(deep_regexps ||= []) << item
else
regexps << item
end
def compile_filters!(filters)
@no_filters = filters.empty?
return if @no_filters

@regexps, strings = [], []
@deep_regexps, deep_strings = nil, nil
@blocks = nil

filters.each do |item|
case item
when Proc
(@blocks ||= []) << item
when Regexp
if item.to_s.include?("\\.")
(@deep_regexps ||= []) << item
else
s = Regexp.escape(item.to_s)
if s.include?("\\.")
(deep_strings ||= []) << s
else
strings << s
end
@regexps << item
end
else
s = Regexp.escape(item.to_s)
if s.include?("\\.")
(deep_strings ||= []) << s
else
strings << s
end
end

regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
(deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings&.any?

new regexps, deep_regexps, blocks, mask: mask
end

attr_reader :regexps, :deep_regexps, :blocks

def initialize(regexps, deep_regexps, blocks, mask:)
@regexps = regexps
@deep_regexps = deep_regexps&.any? ? deep_regexps : nil
@blocks = blocks
@mask = mask
end

def call(params, full_parent_key = nil, original_params = params)
filtered_params = params.class.new
@regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
(@deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings
end

params.each do |key, value|
filtered_params[key] = value_for_key(key, value, full_parent_key, original_params)
end
def call(params, full_parent_key = nil, original_params = params)
filtered_params = params.class.new

filtered_params
params.each do |key, value|
filtered_params[key] = value_for_key(key, value, full_parent_key, original_params)
end

def value_for_key(key, value, full_parent_key = nil, original_params = nil)
if deep_regexps
full_key = full_parent_key ? "#{full_parent_key}.#{key}" : key.to_s
end
filtered_params
end

if regexps.any? { |r| r.match?(key.to_s) }
value = @mask
elsif deep_regexps&.any? { |r| r.match?(full_key) }
value = @mask
elsif value.is_a?(Hash)
value = call(value, full_key, original_params)
elsif value.is_a?(Array)
value = value.map { |v| value_for_key(key, v, full_parent_key, original_params) }
elsif blocks.any?
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
end
def value_for_key(key, value, full_parent_key = nil, original_params = nil)
if @deep_regexps
full_key = full_parent_key ? "#{full_parent_key}.#{key}" : key.to_s
end

value
if @regexps.any? { |r| r.match?(key.to_s) }
value = @mask
elsif @deep_regexps&.any? { |r| r.match?(full_key) }
value = @mask
elsif value.is_a?(Hash)
value = call(value, full_key, original_params)
elsif value.is_a?(Array)
value = value.map { |v| value_for_key(key, v, full_parent_key, original_params) }
elsif @blocks
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
@blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
end

value
end
end
end

0 comments on commit fbad90f

Please sign in to comment.