aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/vendor/rack-mount-0.6.6.pre/rack/mount/route.rb
blob: 680c40f14727efedba55a78c56e82bf3a48a81c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'rack/mount/generatable_regexp'
require 'rack/mount/regexp_with_named_groups'
require 'rack/mount/utils'

module Rack::Mount
  # Route is an internal class used to wrap a single route attributes.
  #
  # Plugins should not depend on any method on this class or instantiate
  # new Route objects. Instead use the factory method, RouteSet#add_route
  # to create new routes and add them to the set.
  class Route
    # Valid rack application to call if conditions are met
    attr_reader :app

    # A hash of conditions to match against. Conditions may be expressed
    # as strings or regexps to match against.
    attr_reader :conditions

    # A hash of values that always gets merged into the parameters hash
    attr_reader :defaults

    # Symbol identifier for the route used with named route generations
    attr_reader :name

    attr_reader :named_captures

    def initialize(app, conditions, defaults, name)
      unless app.respond_to?(:call)
        raise ArgumentError, 'app must be a valid rack application' \
          ' and respond to call'
      end
      @app = app

      @name = name ? name.to_sym : nil
      @defaults = (defaults || {}).freeze

      @conditions = {}

      conditions.each do |method, pattern|
        next unless method && pattern

        pattern = Regexp.compile("\\A#{Regexp.escape(pattern)}\\Z") if pattern.is_a?(String)

        if pattern.is_a?(Regexp)
          pattern = Utils.normalize_extended_expression(pattern)
          pattern = RegexpWithNamedGroups.new(pattern)
          pattern.extend(GeneratableRegexp::InstanceMethods)
          pattern.defaults = @defaults
        end

        @conditions[method] = pattern.freeze
      end

      @named_captures = {}
      @conditions.map { |method, condition|
        next unless condition.respond_to?(:named_captures)
        @named_captures[method] = condition.named_captures.inject({}) { |named_captures, (k, v)|
          named_captures[k.to_sym] = v.last - 1
          named_captures
        }.freeze
      }
      @named_captures.freeze

      @has_significant_params = @conditions.any? { |method, condition|
        (condition.respond_to?(:required_params) && condition.required_params.any?) ||
          (condition.respond_to?(:required_defaults) && condition.required_defaults.any?)
      }

      if @conditions.has_key?(:path_info) &&
          !Utils.regexp_anchored?(@conditions[:path_info])
        @prefix = true
        @app = Prefix.new(@app)
      else
        @prefix = false
      end

      @conditions.freeze
    end

    def prefix?
      @prefix
    end


    def generation_keys
      @conditions.inject({}) { |keys, (method, condition)|
        if condition.respond_to?(:required_defaults)
          keys.merge!(condition.required_defaults)
        else
          keys
        end
      }
    end

    def significant_params?
      @has_significant_params
    end

    def generate(method, params = {}, recall = {}, options = {})
      if method.nil?
        result = @conditions.inject({}) { |h, (m, condition)|
          if condition.respond_to?(:generate)
            h[m] = condition.generate(params, recall, options)
          end
          h
        }
        return nil if result.values.compact.empty?
      else
        if condition = @conditions[method]
          if condition.respond_to?(:generate)
            result = condition.generate(params, recall, options)
          end
        end
      end

      if result
        @defaults.each do |key, value|
          params.delete(key) if params[key] == value
        end
      end

      result
    end


    def inspect #:nodoc:
      "#<#{self.class.name} @app=#{@app.inspect} @conditions=#{@conditions.inspect} @defaults=#{@defaults.inspect} @name=#{@name.inspect}>"
    end
  end
end