aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb')
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb159
1 files changed, 159 insertions, 0 deletions
diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb
new file mode 100644
index 0000000000..8a8c551302
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/analysis/splitting.rb
@@ -0,0 +1,159 @@
+require 'rack/mount/utils'
+
+module Rack::Mount
+ module Analysis
+ class Splitting < Frequency
+ NULL = "\0".freeze
+
+ class Key < Struct.new(:method, :index, :separators)
+ def self.split(value, separator_pattern)
+ keys = value.split(separator_pattern)
+ keys.shift if keys[0] == ''
+ keys << NULL
+ keys
+ end
+
+ def call(cache, obj)
+ (cache[method] ||= self.class.split(obj.send(method), separators))[index]
+ end
+
+ def call_source(cache, obj)
+ "(#{cache}[:#{method}] ||= Analysis::Splitting::Key.split(#{obj}.#{method}, #{separators.inspect}))[#{index}]"
+ end
+
+ def inspect
+ "#{method}[#{index}]"
+ end
+ end
+
+ def clear
+ @boundaries = {}
+ super
+ end
+
+ def <<(key)
+ super
+ key.each_pair do |k, v|
+ analyze_capture_boundaries(v, @boundaries[k] ||= Histogram.new)
+ end
+ end
+
+ def separators(key)
+ (@boundaries[key].keys_in_upper_quartile + ['/']).uniq
+ end
+
+ def process_key(requirements, method, requirement)
+ separators = separators(method)
+ if requirement.is_a?(Regexp) && separators.any?
+ generate_split_keys(requirement, separators).each_with_index do |value, index|
+ requirements[Key.new(method, index, Regexp.union(*separators))] = value
+ end
+ else
+ super
+ end
+ end
+
+ private
+ def analyze_capture_boundaries(regexp, boundaries) #:nodoc:
+ return boundaries unless regexp.is_a?(Regexp)
+
+ parts = Utils.parse_regexp(regexp)
+ parts.each_with_index do |part, index|
+ if part.is_a?(Regin::Group)
+ if index > 0
+ previous = parts[index-1]
+ if previous.is_a?(Regin::Character) && previous.literal?
+ boundaries << previous.to_s
+ end
+ end
+
+ if inside = part.expression[0]
+ if inside.is_a?(Regin::Character) && inside.literal?
+ boundaries << inside.to_s
+ end
+ end
+
+ if index < parts.length
+ following = parts[index+1]
+ if following.is_a?(Regin::Character) && following.literal?
+ boundaries << following.to_s
+ end
+ end
+ end
+ end
+
+ boundaries
+ end
+
+ def generate_split_keys(regexp, separators) #:nodoc:
+ segments = []
+ buf = nil
+ parts = Utils.parse_regexp(regexp)
+ parts.each_with_index do |part, index|
+ case part
+ when Regin::Anchor
+ if part.value == '$' || part.value == '\Z'
+ segments << join_buffer(buf, regexp) if buf
+ segments << NULL
+ buf = nil
+ break
+ end
+ when Regin::CharacterClass
+ break if separators.any? { |s| part.include?(s) }
+ buf = nil
+ segments << part.to_regexp(true)
+ when Regin::Character
+ if separators.any? { |s| part.include?(s) }
+ segments << join_buffer(buf, regexp) if buf
+ peek = parts[index+1]
+ if peek.is_a?(Regin::Character) && separators.include?(peek.value)
+ segments << ''
+ end
+ buf = nil
+ else
+ buf ||= Regin::Expression.new([])
+ buf += [part]
+ end
+ when Regin::Group
+ if part.quantifier == '?'
+ value = part.expression.first
+ if separators.any? { |s| value.include?(s) }
+ segments << join_buffer(buf, regexp) if buf
+ buf = nil
+ end
+ break
+ elsif part.quantifier == nil
+ break if separators.any? { |s| part.include?(s) }
+ buf = nil
+ segments << part.to_regexp(true)
+ else
+ break
+ end
+ else
+ break
+ end
+
+ if index + 1 == parts.size
+ segments << join_buffer(buf, regexp) if buf
+ buf = nil
+ break
+ end
+ end
+
+ while segments.length > 0 && (segments.last.nil? || segments.last == '')
+ segments.pop
+ end
+
+ segments
+ end
+
+ def join_buffer(parts, regexp)
+ if parts.literal?
+ parts.to_s
+ else
+ parts.to_regexp(true)
+ end
+ end
+ end
+ end
+end