aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb')
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb210
1 files changed, 210 insertions, 0 deletions
diff --git a/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb
new file mode 100644
index 0000000000..47bbab3784
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/generatable_regexp.rb
@@ -0,0 +1,210 @@
+require 'rack/mount/utils'
+
+module Rack::Mount
+ class GeneratableRegexp < Regexp #:nodoc:
+ class DynamicSegment #:nodoc:
+ attr_reader :name, :requirement
+
+ def initialize(name, requirement)
+ @name, @requirement = name.to_sym, requirement
+ freeze
+ end
+
+ def ==(obj)
+ @name == obj.name && @requirement == obj.requirement
+ end
+
+ def =~(str)
+ @requirement =~ str
+ end
+
+ def to_hash
+ { @name => @requirement }
+ end
+
+ def inspect
+ "/(?<#{@name}>#{@requirement.source})/"
+ end
+ end
+
+ module InstanceMethods
+ def self.extended(obj)
+ obj.segments
+ end
+
+ def defaults=(defaults)
+ @required_captures = nil
+ @required_params = nil
+ @required_defaults = nil
+ @defaults = defaults
+ end
+
+ def defaults
+ @defaults ||= {}
+ end
+
+ def generatable?
+ segments.any?
+ end
+
+ def generate(params = {}, recall = {}, options = {})
+ return nil unless generatable?
+
+ merged = recall.merge(params)
+ return nil unless required_params.all? { |p| merged.include?(p) }
+ return nil unless required_defaults.all? { |k, v| merged[k] == v }
+
+ generate_from_segments(segments, params, merged, options)
+ end
+
+ def segments
+ @segments ||= begin
+ defaults
+ segments = []
+ catch(:halt) do
+ expression = Utils.parse_regexp(self)
+ segments = parse_segments(expression)
+ end
+ segments
+ end
+ end
+
+ def captures
+ segments.flatten.find_all { |s| s.is_a?(DynamicSegment) }
+ end
+
+ def required_captures
+ @required_captures ||= segments.find_all { |s|
+ s.is_a?(DynamicSegment) && !@defaults.include?(s.name)
+ }.freeze
+ end
+
+ def required_params
+ @required_params ||= required_captures.map { |s| s.name }.freeze
+ end
+
+ def required_defaults
+ @required_defaults ||= begin
+ required_defaults = @defaults.dup
+ captures.inject({}) { |h, s| h.merge!(s.to_hash) }.keys.each { |name|
+ required_defaults.delete(name)
+ }
+ required_defaults
+ end
+ end
+
+ def freeze
+ segments
+ captures
+ required_captures
+ required_params
+ required_defaults
+ super
+ end
+
+ private
+ def parse_segments(segments)
+ s = []
+ segments.each_with_index do |part, index|
+ case part
+ when Regin::Anchor
+ # ignore
+ when Regin::Character
+ throw :halt unless part.literal?
+
+ if s.last.is_a?(String)
+ s.last << part.value.dup
+ else
+ s << part.value.dup
+ end
+ when Regin::Group
+ if part.name
+ s << DynamicSegment.new(part.name, part.expression.to_regexp(true))
+ else
+ s << parse_segments(part.expression)
+ end
+ when Regin::Expression
+ return parse_segments(part)
+ else
+ throw :halt
+ end
+ end
+
+ s
+ end
+
+ EMPTY_STRING = ''.freeze
+
+ def generate_from_segments(segments, params, merged, options, optional = false)
+ if optional
+ return EMPTY_STRING if segments.all? { |s| s.is_a?(String) }
+ return EMPTY_STRING unless segments.flatten.any? { |s|
+ params.has_key?(s.name) if s.is_a?(DynamicSegment)
+ }
+ return EMPTY_STRING if segments.any? { |segment|
+ if segment.is_a?(DynamicSegment)
+ value = merged[segment.name] || @defaults[segment.name]
+ value = parameterize(segment.name, value, options)
+
+ merged_value = parameterize(segment.name, merged[segment.name], options)
+ default_value = parameterize(segment.name, @defaults[segment.name], options)
+
+ if value.nil? || segment !~ value
+ true
+ elsif merged_value == default_value
+ # Nasty control flow
+ return :clear_remaining_segments
+ else
+ false
+ end
+ end
+ }
+ end
+
+ generated = segments.map do |segment|
+ case segment
+ when String
+ segment
+ when DynamicSegment
+ value = params[segment.name] || merged[segment.name] || @defaults[segment.name]
+ value = parameterize(segment.name, value, options)
+ if value && segment =~ value.to_s
+ value
+ else
+ return
+ end
+ when Array
+ value = generate_from_segments(segment, params, merged, options, true)
+ if value == :clear_remaining_segments
+ segment.each { |s| params.delete(s.name) if s.is_a?(DynamicSegment) }
+ EMPTY_STRING
+ elsif value.nil?
+ EMPTY_STRING
+ else
+ value
+ end
+ end
+ end
+
+ # Delete any used items from the params
+ segments.each { |s| params.delete(s.name) if s.is_a?(DynamicSegment) }
+
+ generated.join
+ end
+
+ def parameterize(name, value, options)
+ if block = options[:parameterize]
+ block.call(name, value)
+ else
+ value
+ end
+ end
+ end
+ include InstanceMethods
+
+ def initialize(regexp)
+ super
+ segments
+ end
+ end
+end