Class: ActionController::Routing::Route

Inherits:
Object
  • Object
show all
Defined in:
lib/action_controller/routing/route.rb

Overview

:nodoc:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRoute

Returns a new instance of Route.



6
7
8
9
10
11
# File 'lib/action_controller/routing/route.rb', line 6

def initialize
  @segments = []
  @requirements = {}
  @conditions = {}
  @optimise = true
end

Instance Attribute Details

#conditionsObject

Returns the value of attribute conditions.



4
5
6
# File 'lib/action_controller/routing/route.rb', line 4

def conditions
  @conditions
end

#optimiseObject

Returns the value of attribute optimise.



4
5
6
# File 'lib/action_controller/routing/route.rb', line 4

def optimise
  @optimise
end

#requirementsObject

Returns the value of attribute requirements.



4
5
6
# File 'lib/action_controller/routing/route.rb', line 4

def requirements
  @requirements
end

#segmentsObject

Returns the value of attribute segments.



4
5
6
# File 'lib/action_controller/routing/route.rb', line 4

def segments
  @segments
end

Instance Method Details

#append_query_string(path, hash, query_keys = nil) ⇒ Object

Generate the query string with any extra keys in the hash and append it to the given path, returning the new path.



132
133
134
135
136
# File 'lib/action_controller/routing/route.rb', line 132

def append_query_string(path, hash, query_keys=nil)
  return nil unless path
  query_keys ||= extra_keys(hash)
  "#{path}#{build_query_string(hash, query_keys)}"
end

#build_query_string(hash, only_keys = nil) ⇒ Object

Build a query string from the keys of the given hash. If only_keys is given (as an array), only the keys indicated will be used to build the query string. The query string will correctly build array parameter values.



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/action_controller/routing/route.rb', line 152

def build_query_string(hash, only_keys = nil)
  elements = []

  (only_keys || hash.keys).each do |key|
    if value = hash[key]
      elements << value.to_query(key)
    end
  end

  elements.empty? ? '' : "?#{elements.sort * '&'}"
end

#defaultsObject

Return a hash of key/value pairs representing the keys in the route that have defaults, or which are specified by non-regexp requirements.



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/action_controller/routing/route.rb', line 198

def defaults
  @defaults ||= returning({}) do |hash|
    segments.each do |segment|
      next unless segment.respond_to? :default
      hash[segment.key] = segment.default unless segment.default.nil?
    end
    requirements.each do |key,req|
      next if Regexp === req || req.nil?
      hash[key] = req
    end
  end
end

#extra_keys(hash, recall = {}) ⇒ Object

Determine which keys in the given hash are “extra”. Extra keys are those that were not used to generate a particular route. The extra keys also do not include those recalled from the prior request, nor do they include any keys that were implied in the route (like a :controller that is required, but not explicitly used in the text of the route.)



144
145
146
# File 'lib/action_controller/routing/route.rb', line 144

def extra_keys(hash, recall={})
  (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
end

#generate(options, hash, expire_on = {}) ⇒ Object

Write the real generation implementation and then resend the message.



120
121
122
123
# File 'lib/action_controller/routing/route.rb', line 120

def generate(options, hash, expire_on = {})
  write_generation
  generate options, hash, expire_on
end

#generate_extras(options, hash, expire_on = {}) ⇒ Object



125
126
127
128
# File 'lib/action_controller/routing/route.rb', line 125

def generate_extras(options, hash, expire_on = {})
  write_generation
  generate_extras options, hash, expire_on
end

#generation_extractionObject

Build several lines of code that extract values from the options hash. If any of the values are missing or rejected then a return will be executed.



54
55
56
57
58
# File 'lib/action_controller/routing/route.rb', line 54

def generation_extraction
  segments.collect do |segment|
    segment.extraction_code
  end.compact * "\n"
end

#generation_requirementsObject

Produce a condition expression that will check the requirements of this route upon generation.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/action_controller/routing/route.rb', line 62

def generation_requirements
  requirement_conditions = requirements.collect do |key, req|
    if req.is_a? Regexp
      value_regexp = Regexp.new "\\A#{req.to_s}\\Z"
      "hash[:#{key}] && #{value_regexp.inspect} =~ options[:#{key}]"
    else
      "hash[:#{key}] == #{req.inspect}"
    end
  end
  requirement_conditions * ' && ' unless requirement_conditions.empty?
end

#generation_structureObject



74
75
76
# File 'lib/action_controller/routing/route.rb', line 74

def generation_structure
  segments.last.string_structure segments[0..-2]
end

#matches_controller_and_action?(controller, action) ⇒ Boolean

Returns:

  • (Boolean)


211
212
213
214
215
216
217
218
219
220
# File 'lib/action_controller/routing/route.rb', line 211

def matches_controller_and_action?(controller, action)
  unless defined? @matching_prepared
    @controller_requirement = requirement_for(:controller)
    @action_requirement = requirement_for(:action)
    @matching_prepared = true
  end

  (@controller_requirement.nil? || @controller_requirement === controller) &&
  (@action_requirement.nil? || @action_requirement === action)
end

#optimise?Boolean

Indicates whether the routes should be optimised with the string interpolation version of the named routes methods.

Returns:

  • (Boolean)


15
16
17
# File 'lib/action_controller/routing/route.rb', line 15

def optimise?
  @optimise && ActionController::Base::optimise_named_routes
end

#parameter_shellObject

A route’s parameter shell contains parameter values that are not in the route’s path, but should be placed in the recognized hash.

For example, +=> ‘pages’, :action => ‘show’ is the shell for the route:

map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/


177
178
179
180
181
182
183
# File 'lib/action_controller/routing/route.rb', line 177

def parameter_shell
  @parameter_shell ||= returning({}) do |shell|
    requirements.each do |key, requirement|
      shell[key] = requirement unless requirement.is_a? Regexp
    end
  end
end

#recognition_conditionsObject

Plugins may override this method to add other conditions, like checks on host, subdomain, and so forth. Note that changes here only affect route recognition, not generation.



93
94
95
96
97
# File 'lib/action_controller/routing/route.rb', line 93

def recognition_conditions
  result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
  result << "conditions[:method] === env[:method]" if conditions[:method]
  result
end

#recognition_extractionObject

Write the code to extract the parameters from a matched route.



109
110
111
112
113
114
115
116
117
# File 'lib/action_controller/routing/route.rb', line 109

def recognition_extraction
  next_capture = 1
  extraction = segments.collect do |segment|
    x = segment.match_extraction(next_capture)
    next_capture += Regexp.new(segment.regexp_chunk).number_of_captures
    x
  end
  extraction.compact
end

#recognition_pattern(wrap = true) ⇒ Object

Build the regular expression pattern that will match this route.



100
101
102
103
104
105
106
# File 'lib/action_controller/routing/route.rb', line 100

def recognition_pattern(wrap = true)
  pattern = ''
  segments.reverse_each do |segment|
    pattern = segment.build_pattern pattern
  end
  wrap ? ("\\A" + pattern + "\\Z") : pattern
end

#recognize(path, environment = {}) ⇒ Object

Write the real recognition implementation and then resend the message.



165
166
167
168
# File 'lib/action_controller/routing/route.rb', line 165

def recognize(path, environment={})
  write_recognition
  recognize path, environment
end

#segment_keysObject



19
20
21
22
23
# File 'lib/action_controller/routing/route.rb', line 19

def segment_keys
  segments.collect do |segment|
    segment.key if segment.respond_to? :key
  end.compact
end

#significant_keysObject

Return an array containing all the keys that are used in this route. This includes keys that appear inside the path, and keys that have requirements placed upon them.



188
189
190
191
192
193
194
# File 'lib/action_controller/routing/route.rb', line 188

def significant_keys
  @significant_keys ||= returning [] do |sk|
    segments.each { |segment| sk << segment.key if segment.respond_to? :key }
    sk.concat requirements.keys
    sk.uniq!
  end
end

#to_sObject



222
223
224
225
226
227
# File 'lib/action_controller/routing/route.rb', line 222

def to_s
  @to_s ||= begin
    segs = segments.inject("") { |str,s| str << s.to_s }
    "%-6s %-40s %s" % [(conditions[:method] || :any).to_s.upcase, segs, requirements.inspect]
  end
end

#write_generationObject

Write and compile a generate method for this Route.



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
# File 'lib/action_controller/routing/route.rb', line 26

def write_generation
  # Build the main body of the generation
  body = "expired = false\n#{generation_extraction}\n#{generation_structure}"

  # If we have conditions that must be tested first, nest the body inside an if
  body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements
  args = "options, hash, expire_on = {}"

  # Nest the body inside of a def block, and then compile it.
  raw_method = method_decl = "def generate_raw(#{args})\npath = begin\n#{body}\nend\n[path, hash]\nend"
  instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"

  # expire_on.keys == recall.keys; in other words, the keys in the expire_on hash
  # are the same as the keys that were recalled from the previous request. Thus,
  # we can use the expire_on.keys to determine which keys ought to be used to build
  # the query string. (Never use keys from the recalled request when building the
  # query string.)

  method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
  instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"

  method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
  instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
  raw_method
end

#write_recognitionObject

Write and compile a recognize method for this Route.



79
80
81
82
83
84
85
86
87
88
# File 'lib/action_controller/routing/route.rb', line 79

def write_recognition
  # Create an if structure to extract the params from a match if it occurs.
  body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams"
  body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend"

  # Build the method declaration and compile it
  method_decl = "def recognize(path, env={})\n#{body}\nend"
  instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
  method_decl
end