fix(Tree): allows insert paths with shared keys unordered

When adding new nodes into the tree, the lookup mechanism failed
to detect same named parameter was already added to it, raising
an exception.

Example:

    tree = Radix::Tree(Symbol).new
    tree.add "/members/:id/edit", :member_edit
    tree.add "/members/export",   :members_export
    tree.add "/members/:id/videos", :member_videos # Exception

This fix ensures that comparison is done key by key, even if they
are inserted into the tree in a different order.

Closes #9
This commit is contained in:
Luis Lavena 2016-11-05 13:42:20 -03:00
parent e55d144413
commit d7c0779ac9
3 changed files with 39 additions and 2 deletions

View file

@ -5,6 +5,8 @@ This project aims to comply with [Semantic Versioning](http://semver.org/),
so please check *Changed* and *Removed* notes before upgrading.
## [Unreleased]
### Fixed
- Do not force adding paths with shared named parameter in an specific order (@jwoertink)
## [0.3.1] - 2016-07-29
### Added

View file

@ -233,6 +233,30 @@ module Radix
tree.root.children[0].children[0].key.should eq("/:subcategory")
end
it "does allow same named parameter in different order of insertion" do
tree = Tree(Symbol).new
tree.add "/members/:id/edit", :member_edit
tree.add "/members/export", :members_export
tree.add "/members/:id/videos", :member_videos
# /members/
# +-export (:members_export)
# \-:id/
# +-videos (:members_videos)
# \-edit (:members_edit)
tree.root.key.should eq("/members/")
tree.root.children.size.should eq(2)
# first level children nodes
tree.root.children[0].key.should eq("export")
tree.root.children[1].key.should eq(":id/")
# inner children
nodes = tree.root.children[1].children
nodes[0].key.should eq("videos")
nodes[1].key.should eq("edit")
end
it "does not allow different named parameters sharing same level" do
tree = Tree(Symbol).new
tree.add "/", :root

View file

@ -374,7 +374,18 @@ module Radix
count
end
# :nodoc:
# Internal: Compares *path* against *key* for differences until the
# following criteria is met:
#
# - End of *path* or *key* is reached.
# - A separator (`/`) is found.
# - A character between *path* or *key* differs
#
# ```
# _same_key?("foo", "bar") # => false (mismatch at 1st character)
# _same_key?("foo/bar", "foo/baz") # => true (only `foo` is compared)
# _same_key?("zipcode", "zip") # => false (`zip` is shorter)
# ```
private def _same_key?(path, key)
path_reader = Char::Reader.new(path)
key_reader = Char::Reader.new(key)
@ -392,7 +403,7 @@ module Radix
key_reader.next_char
end
(!key_reader.has_next? && !different) &&
(!different) &&
(path_reader.current_char == '/' || !path_reader.has_next?)
end