From d7c0779ac939efc2672c8f79df8d3897aa845c75 Mon Sep 17 00:00:00 2001 From: Luis Lavena Date: Sat, 5 Nov 2016 13:42:20 -0300 Subject: [PATCH] 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 --- CHANGELOG.md | 2 ++ spec/radix/tree_spec.cr | 24 ++++++++++++++++++++++++ src/radix/tree.cr | 15 +++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b23832c..45d2372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/spec/radix/tree_spec.cr b/spec/radix/tree_spec.cr index 4e5f942..a01085a 100644 --- a/spec/radix/tree_spec.cr +++ b/spec/radix/tree_spec.cr @@ -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 diff --git a/src/radix/tree.cr b/src/radix/tree.cr index 5a0c736..5436c15 100644 --- a/src/radix/tree.cr +++ b/src/radix/tree.cr @@ -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