Browse files

Prepare Route#generate and Route#recognize early. Also refactor segme…

…nts a bit to try to make immutable.
  • Loading branch information...
1 parent e0513e3 commit a5db1488251304ec93256654859b430148f0c506 @josh josh committed Jul 28, 2008
View
29 actionpack/lib/action_controller/routing/builder.rb
@@ -48,14 +48,10 @@ def segment_for(string)
end
when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true)
when /\A\?(.*?)\?/
- returning segment = StaticSegment.new($1) do
- segment.is_optional = true
- end
+ StaticSegment.new($1, :optional => true)
when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1)
when Regexp.new(separator_pattern) then
- returning segment = DividerSegment.new($&) do
- segment.is_optional = (optional_separators.include? $&)
- end
+ DividerSegment.new($&, :optional => (optional_separators.include? $&))
end
[segment, $~.post_match]
end
@@ -176,29 +172,16 @@ def build(path, options)
defaults, requirements, conditions = divide_route_options(segments, options)
requirements = assign_route_options(segments, defaults, requirements)
- route = Route.new
-
- route.segments = segments
- route.requirements = requirements
- route.conditions = conditions
+ # TODO: Segments should be frozen on initialize
+ segments.each { |segment| segment.freeze }
- if !route.significant_keys.include?(:action) && !route.requirements[:action]
- route.requirements[:action] = "index"
- route.significant_keys << :action
- end
-
- # Routes cannot use the current string interpolation method
- # if there are user-supplied <tt>:requirements</tt> as the interpolation
- # code won't raise RoutingErrors when generating
- if options.key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION
- route.optimise = false
- end
+ route = Route.new(segments, requirements, conditions)
if !route.significant_keys.include?(:controller)
raise ArgumentError, "Illegal route: the :controller must be specified!"
end
- route
+ route.freeze
end
private
View
1 actionpack/lib/action_controller/routing/optimisations.rb
@@ -20,6 +20,7 @@ def generate_optimisation_block(route, kind)
class Optimiser
attr_reader :route, :kind
+
def initialize(route, kind)
@route = route
@kind = kind
View
40 actionpack/lib/action_controller/routing/recognition_optimisation.rb
@@ -67,28 +67,6 @@ def recognize_path(path, environment={})
end
end
- def recognize_optimized(path, env)
- write_recognize_optimized
- recognize_optimized(path, env)
- end
-
- def write_recognize_optimized
- tree = segment_tree(routes)
- body = generate_code(tree)
- instance_eval %{
- def recognize_optimized(path, env)
- segments = to_plain_segments(path)
- index = #{body}
- return nil unless index
- while index < routes.size
- result = routes[index].recognize(path, env) and return result
- index += 1
- end
- nil
- end
- }, __FILE__, __LINE__
- end
-
def segment_tree(routes)
tree = [0]
@@ -151,6 +129,24 @@ def to_plain_segments(str)
segments << nil
segments
end
+
+ private
+ def write_recognize_optimized!
+ tree = segment_tree(routes)
+ body = generate_code(tree)
+ instance_eval %{
+ def recognize_optimized(path, env)
+ segments = to_plain_segments(path)
+ index = #{body}
+ return nil unless index
+ while index < routes.size
+ result = routes[index].recognize(path, env) and return result
+ index += 1
+ end
+ nil
+ end
+ }, __FILE__, __LINE__
+ end
end
end
end
View
300 actionpack/lib/action_controller/routing/route.rb
@@ -3,11 +3,25 @@ module Routing
class Route #:nodoc:
attr_accessor :segments, :requirements, :conditions, :optimise
- def initialize
- @segments = []
- @requirements = {}
- @conditions = {}
- @optimise = true
+ def initialize(segments = [], requirements = {}, conditions = {})
+ @segments = segments
+ @requirements = requirements
+ @conditions = conditions
+
+ if !significant_keys.include?(:action) && !requirements[:action]
+ @requirements[:action] = "index"
+ @significant_keys << :action
+ end
+
+ # Routes cannot use the current string interpolation method
+ # if there are user-supplied <tt>:requirements</tt> as the interpolation
+ # code won't raise RoutingErrors when generating
+ has_requirements = @segments.detect { |segment| segment.respond_to?(:regexp) && segment.regexp }
+ if has_requirements || @requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION
+ @optimise = false
+ else
+ @optimise = true
+ end
end
# Indicates whether the routes should be optimised with the string interpolation
@@ -22,129 +36,6 @@ def segment_keys
end.compact
end
- # Write and compile a +generate+ method for this Route.
- 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
-
- # 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.
- def generation_extraction
- segments.collect do |segment|
- segment.extraction_code
- end.compact * "\n"
- end
-
- # Produce a condition expression that will check the requirements of this route
- # upon generation.
- 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
-
- def generation_structure
- segments.last.string_structure segments[0..-2]
- end
-
- # Write and compile a +recognize+ method for this Route.
- 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
-
- # 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.
- def recognition_conditions
- result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
- result << "conditions[:method] === env[:method]" if conditions[:method]
- result
- end
-
- # Build the regular expression pattern that will match this route.
- def recognition_pattern(wrap = true)
- pattern = ''
- segments.reverse_each do |segment|
- pattern = segment.build_pattern pattern
- end
- wrap ? ("\\A" + pattern + "\\Z") : pattern
- end
-
- # Write the code to extract the parameters from a matched route.
- 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
-
- # Write the real generation implementation and then resend the message.
- def generate(options, hash, expire_on = {})
- write_generation
- generate options, hash, expire_on
- end
-
- def generate_extras(options, hash, expire_on = {})
- write_generation
- generate_extras options, hash, expire_on
- end
-
- # Generate the query string with any extra keys in the hash and append
- # it to the given path, returning the new path.
- 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
-
- # 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
- # <tt>:controller</tt> that is required, but not explicitly used in the
- # text of the route.)
- def extra_keys(hash, recall={})
- (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
- end
-
# 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
@@ -161,12 +52,6 @@ def build_query_string(hash, only_keys = nil)
elements.empty? ? '' : "?#{elements.sort * '&'}"
end
- # Write the real recognition implementation and then resend the message.
- def recognize(path, environment={})
- write_recognition
- recognize path, environment
- end
-
# A route's parameter shell contains parameter values that are not in the
# route's path, but should be placed in the recognized hash.
#
@@ -186,7 +71,7 @@ def parameter_shell
# includes keys that appear inside the path, and keys that have requirements
# placed upon them.
def significant_keys
- @significant_keys ||= returning [] do |sk|
+ @significant_keys ||= returning([]) do |sk|
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
sk.concat requirements.keys
sk.uniq!
@@ -209,12 +94,7 @@ def defaults
end
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
-
+ prepare_matching!
(@controller_requirement.nil? || @controller_requirement === controller) &&
(@action_requirement.nil? || @action_requirement === action)
end
@@ -226,14 +106,150 @@ def to_s
end
end
- protected
+ # TODO: Route should be prepared and frozen on initialize
+ def freeze
+ unless frozen?
+ write_generation!
+ write_recognition!
+ prepare_matching!
+
+ parameter_shell
+ significant_keys
+ defaults
+ to_s
+ end
+
+ super
+ end
+
+ private
def requirement_for(key)
return requirements[key] if requirements.key? key
segments.each do |segment|
return segment.regexp if segment.respond_to?(:key) && segment.key == key
end
nil
end
+
+ # Write and compile a +generate+ method for this Route.
+ 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
+
+ # 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.
+ def generation_extraction
+ segments.collect do |segment|
+ segment.extraction_code
+ end.compact * "\n"
+ end
+
+ # Produce a condition expression that will check the requirements of this route
+ # upon generation.
+ 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
+
+ def generation_structure
+ segments.last.string_structure segments[0..-2]
+ end
+
+ # Write and compile a +recognize+ method for this Route.
+ 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
+
+ # 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.
+ def recognition_conditions
+ result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
+ result << "conditions[:method] === env[:method]" if conditions[:method]
+ result
+ end
+
+ # Build the regular expression pattern that will match this route.
+ def recognition_pattern(wrap = true)
+ pattern = ''
+ segments.reverse_each do |segment|
+ pattern = segment.build_pattern pattern
+ end
+ wrap ? ("\\A" + pattern + "\\Z") : pattern
+ end
+
+ # Write the code to extract the parameters from a matched route.
+ 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
+
+ # Generate the query string with any extra keys in the hash and append
+ # it to the given path, returning the new path.
+ 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
+
+ # 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
+ # <tt>:controller</tt> that is required, but not explicitly used in the
+ # text of the route.)
+ def extra_keys(hash, recall = {})
+ (hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
+ end
+
+ def prepare_matching!
+ unless defined? @matching_prepared
+ @controller_requirement = requirement_for(:controller)
+ @action_requirement = requirement_for(:action)
+ @matching_prepared = true
+ end
+ end
end
end
end
View
3 actionpack/lib/action_controller/routing/route_set.rb
@@ -194,6 +194,8 @@ def #{selector}(*args)
def initialize
self.routes = []
self.named_routes = NamedRouteCollection.new
+
+ write_recognize_optimized!
end
# Subclasses and plugins may override this method to specify a different
@@ -231,7 +233,6 @@ def load!
Routing.use_controllers! nil # Clear the controller cache so we may discover new ones
clear!
load_routes!
- install_helpers
end
# reload! will always force a reload whereas load checks the timestamp first
View
29 actionpack/lib/action_controller/routing/segments.rb
@@ -4,11 +4,12 @@ class Segment #:nodoc:
RESERVED_PCHAR = ':@&=+$,;'
UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze
+ # TODO: Convert :is_optional accessor to read only
attr_accessor :is_optional
alias_method :optional?, :is_optional
def initialize
- self.is_optional = false
+ @is_optional = false
end
def extraction_code
@@ -63,12 +64,14 @@ def optionality_implied?
end
class StaticSegment < Segment #:nodoc:
- attr_accessor :value, :raw
+ attr_reader :value, :raw
alias_method :raw?, :raw
- def initialize(value = nil)
+ def initialize(value = nil, options = {})
super()
- self.value = value
+ @value = value
+ @raw = options[:raw] if options.key?(:raw)
+ @is_optional = options[:optional] if options.key?(:optional)
end
def interpolation_chunk
@@ -97,10 +100,8 @@ def to_s
end
class DividerSegment < StaticSegment #:nodoc:
- def initialize(value = nil)
- super(value)
- self.raw = true
- self.is_optional = true
+ def initialize(value = nil, options = {})
+ super(value, {:raw => true, :optional => true}.merge(options))
end
def optionality_implied?
@@ -109,13 +110,17 @@ def optionality_implied?
end
class DynamicSegment < Segment #:nodoc:
- attr_accessor :key, :default, :regexp
+ attr_reader :key
+
+ # TODO: Convert these accessors to read only
+ attr_accessor :default, :regexp
def initialize(key = nil, options = {})
super()
- self.key = key
- self.default = options[:default] if options.key? :default
- self.is_optional = true if options[:optional] || options.key?(:default)
+ @key = key
+ @default = options[:default] if options.key?(:default)
+ @regexp = options[:regexp] if options.key?(:regexp)
+ @is_optional = true if options[:optional] || options.key?(:default)
end
def to_s
View
151 actionpack/test/controller/routing_test.rb
@@ -67,66 +67,56 @@ def s.interpolation_statement(array) 'hello' end
end
def test_interpolation_statement
- s = ROUTING::StaticSegment.new
- s.value = "Hello"
+ s = ROUTING::StaticSegment.new("Hello")
assert_equal "Hello", eval(s.interpolation_statement([]))
assert_equal "HelloHello", eval(s.interpolation_statement([s]))
- s2 = ROUTING::StaticSegment.new
- s2.value = "-"
+ s2 = ROUTING::StaticSegment.new("-")
assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2]))
- s3 = ROUTING::StaticSegment.new
- s3.value = "World"
+ s3 = ROUTING::StaticSegment.new("World")
assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2]))
end
end
class StaticSegmentTest < Test::Unit::TestCase
def test_interpolation_chunk_should_respect_raw
- s = ROUTING::StaticSegment.new
- s.value = 'Hello World'
- assert ! s.raw?
+ s = ROUTING::StaticSegment.new('Hello World')
+ assert !s.raw?
assert_equal 'Hello%20World', s.interpolation_chunk
- s.raw = true
+ s = ROUTING::StaticSegment.new('Hello World', :raw => true)
assert s.raw?
assert_equal 'Hello World', s.interpolation_chunk
end
def test_regexp_chunk_should_escape_specials
- s = ROUTING::StaticSegment.new
-
- s.value = 'Hello*World'
+ s = ROUTING::StaticSegment.new('Hello*World')
assert_equal 'Hello\*World', s.regexp_chunk
- s.value = 'HelloWorld'
+ s = ROUTING::StaticSegment.new('HelloWorld')
assert_equal 'HelloWorld', s.regexp_chunk
end
def test_regexp_chunk_should_add_question_mark_for_optionals
- s = ROUTING::StaticSegment.new
- s.value = "/"
- s.is_optional = true
+ s = ROUTING::StaticSegment.new("/", :optional => true)
assert_equal "/?", s.regexp_chunk
- s.value = "hello"
+ s = ROUTING::StaticSegment.new("hello", :optional => true)
assert_equal "(?:hello)?", s.regexp_chunk
end
end
class DynamicSegmentTest < Test::Unit::TestCase
- def segment
+ def segment(options = {})
unless @segment
- @segment = ROUTING::DynamicSegment.new
- @segment.key = :a
+ @segment = ROUTING::DynamicSegment.new(:a, options)
end
@segment
end
def test_extract_value
- s = ROUTING::DynamicSegment.new
- s.key = :a
+ s = ROUTING::DynamicSegment.new(:a)
hash = {:a => '10', :b => '20'}
assert_equal '10', eval(s.extract_value)
@@ -149,31 +139,31 @@ def test_presence_value_check
end
def test_regexp_value_check_rejects_nil
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
+
a_value = nil
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
end
def test_optional_regexp_value_check_should_accept_nil
- segment.regexp = /\d+/
- segment.is_optional = true
+ segment = segment(:regexp => /\d+/, :optional => true)
+
a_value = nil
assert eval(segment.value_check)
end
def test_regexp_value_check_rejects_no_match
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
a_value = "Hello20World"
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
a_value = "20Hi"
- assert ! eval(segment.value_check)
+ assert !eval(segment.value_check)
end
def test_regexp_value_check_accepts_match
- segment.regexp = /\d+/
-
+ segment = segment(:regexp => /\d+/)
a_value = "30"
assert eval(segment.value_check)
end
@@ -184,14 +174,14 @@ def test_value_check_fails_on_nil
end
def test_optional_value_needs_no_check
- segment.is_optional = true
+ segment = segment(:optional => true)
+
a_value = nil
assert_equal nil, segment.value_check
end
def test_regexp_value_check_should_accept_match_with_default
- segment.regexp = /\d+/
- segment.default = '200'
+ segment = segment(:regexp => /\d+/, :default => '200')
a_value = '100'
assert eval(segment.value_check)
@@ -234,7 +224,7 @@ def test_extraction_code_should_return_on_nil
end
def test_extraction_code_should_return_on_mismatch
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
hash = merged = {:a => 'Hi', :b => '3'}
options = {:b => '3'}
a_value = nil
@@ -292,48 +282,44 @@ def test_value_regexp_should_be_nil_without_regexp
end
def test_value_regexp_should_match_exacly
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
assert_no_match segment.value_regexp, "Hello 10 World"
assert_no_match segment.value_regexp, "Hello 10"
assert_no_match segment.value_regexp, "10 World"
assert_match segment.value_regexp, "10"
end
def test_regexp_chunk_should_return_string
- segment.regexp = /\d+/
+ segment = segment(:regexp => /\d+/)
assert_kind_of String, segment.regexp_chunk
end
def test_build_pattern_non_optional_with_no_captures
# Non optional
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /\d+/ #number_of_captures is 0
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /\d+/)
assert_equal "(\\d+)stuff", a_segment.build_pattern('stuff')
end
def test_build_pattern_non_optional_with_captures
# Non optional
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /(\d+)(.*?)/ #number_of_captures is 2
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /(\d+)(.*?)/)
assert_equal "((\\d+)(.*?))stuff", a_segment.build_pattern('stuff')
end
def test_optionality_implied
- a_segment = ROUTING::DynamicSegment.new
- a_segment.key = :id
+ a_segment = ROUTING::DynamicSegment.new(:id)
assert a_segment.optionality_implied?
- a_segment.key = :action
+ a_segment = ROUTING::DynamicSegment.new(:action)
assert a_segment.optionality_implied?
end
def test_modifiers_must_be_handled_sensibly
- a_segment = ROUTING::DynamicSegment.new
- a_segment.regexp = /david|jamis/i
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/i)
assert_equal "((?i-mx:david|jamis))stuff", a_segment.build_pattern('stuff')
- a_segment.regexp = /david|jamis/x
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/x)
assert_equal "((?x-mi:david|jamis))stuff", a_segment.build_pattern('stuff')
- a_segment.regexp = /david|jamis/
+ a_segment = ROUTING::DynamicSegment.new(nil, :regexp => /david|jamis/)
assert_equal "(david|jamis)stuff", a_segment.build_pattern('stuff')
end
end
@@ -560,7 +546,7 @@ def test_assignment_of_default_options_respects_regexps
action = segments[-4]
assert_equal :action, action.key
- action.regexp = /show|in/ # Use 'in' to check partial matches
+ segments[-4] = ROUTING::DynamicSegment.new(:action, :regexp => /show|in/)
builder.assign_default_route_options(segments)
@@ -661,10 +647,10 @@ def test_possible_controllers_are_reset_on_each_load
ActionController::Routing.controller_paths = []
assert_equal [], ActionController::Routing.possible_controllers
- ActionController::Routing::Routes.load!
ActionController::Routing.controller_paths = [
root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib'
]
+ ActionController::Routing::Routes.load!
assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
ensure
@@ -1374,34 +1360,20 @@ def setup
end
def slash_segment(is_optional = false)
- returning ROUTING::DividerSegment.new('/') do |s|
- s.is_optional = is_optional
- end
+ ROUTING::DividerSegment.new('/', :optional => is_optional)
end
def default_route
unless defined?(@default_route)
- @default_route = ROUTING::Route.new
-
- @default_route.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :controller
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :action
- s.default = 'index'
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
- @default_route.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :id
- s.is_optional = true
-
- @default_route.segments << slash_segment(:optional)
+ segments = []
+ segments << ROUTING::StaticSegment.new('/', :raw => true)
+ segments << ROUTING::DynamicSegment.new(:controller)
+ segments << slash_segment(:optional)
+ segments << ROUTING::DynamicSegment.new(:action, :default => 'index', :optional => true)
+ segments << slash_segment(:optional)
+ segments << ROUTING::DynamicSegment.new(:id, :optional => true)
+ segments << slash_segment(:optional)
+ @default_route = ROUTING::Route.new(segments).freeze
end
@default_route
end
@@ -1489,29 +1461,16 @@ def test_significant_keys_for_default_route
end
def test_significant_keys
- user_url = ROUTING::Route.new
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = 'user'
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
-
- user_url.segments << (s = ROUTING::DynamicSegment.new)
- s.key = :user
-
- user_url.segments << (s = ROUTING::StaticSegment.new)
- s.value = '/'
- s.raw = true
- s.is_optional = true
+ segments = []
+ segments << ROUTING::StaticSegment.new('/', :raw => true)
+ segments << ROUTING::StaticSegment.new('user')
+ segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true)
+ segments << ROUTING::DynamicSegment.new(:user)
+ segments << ROUTING::StaticSegment.new('/', :raw => true, :optional => true)
- user_url.requirements = {:controller => 'users', :action => 'show'}
+ requirements = {:controller => 'users', :action => 'show'}
+ user_url = ROUTING::Route.new(segments, requirements)
keys = user_url.significant_keys.sort_by { |k| k.to_s }
assert_equal [:action, :controller, :user], keys
end
View
4 actionpack/test/controller/test_test.rb
@@ -117,8 +117,8 @@ def setup
@controller = TestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
- ActionController::Routing::Routes.reload
ActionController::Routing.use_controllers! %w(content admin/user test_test/test)
+ ActionController::Routing::Routes.load_routes!
end
def teardown
@@ -412,7 +412,7 @@ def test_assert_routing
def test_assert_routing_with_method
with_routing do |set|
- set.draw { |map| map.resources(:content) }
+ set.draw { |map| map.resources(:content) }
assert_routing({ :method => 'post', :path => 'content' }, { :controller => 'content', :action => 'create' })
end
end

0 comments on commit a5db148

Please sign in to comment.