hanami-router 2.2.0.rc1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6dbd5cec52e1e7a0d2ac82066294bf3846b58b4c8bacd3555d6f0f1a3e6cb873
4
- data.tar.gz: e96f0ff6c694e0964325d012f18c055a892af912e5f6dd3ba35f0bec13173fa0
3
+ metadata.gz: 5bba2b56b3f4ddbedc47b2d21189f7e88ce172505dabbdca6c6d6266aa6c7fa2
4
+ data.tar.gz: d601d610fb2cacbef79ca4770ab1e63869a5469ac46671c823e106086c0e58d0
5
5
  SHA512:
6
- metadata.gz: 8dc08ace41fd84808b9706c2a4d07de0c45f3c206eb858020e8fa7970005e6eeefb721a8654bd86379d8389c71d813b9406ffb4c47eecde4c97558baf6eff3e2
7
- data.tar.gz: e28b53acd76af8d279ca365cfa8c9901ce5fc5d789736eef5cd7925e9ecb89845e58caaa9548ebefe2050b792a7704880c84bb2b27adf27c0c6df288b5bd3969
6
+ metadata.gz: 88b44cc6c09c227aaf45352a49344a48530c4095fa1ac2f53ed0bf38e7901876805121c1090d24759420c8ad0029fbc9aba43d383adb93635161ce3cfb8fe321
7
+ data.tar.gz: 319831eb561257e58afbc2479447e92862b452424a44c1efffc8f534d4bfc40f2549e70d0849ef4e303182f7d8ec620ad8a6d55a25f9e3994a20215c3dd89bf8
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Rack compatible HTTP router for Ruby
4
4
 
5
+ ## v2.2.0 - 2024-11-05
6
+
7
+ ### Changed
8
+
9
+ - [Damian C. Rossney, Kyle Plump] Scopes with a dynamic segment (e.g. `scope ":locale" do`) and containing a `root` route will no longer match the root route for requests with a trailing slash. This makes the behavior consistent with scopes using static strings. (#273)
10
+
11
+ ### Fixed
12
+
13
+ - [Damian C. Rossney, Kyle Plump] Support paths with different variable names in same path location (#273)
14
+
5
15
  ## v2.2.0.rc1 - 2024-10-29
6
16
 
7
17
  ## v2.2.0.beta2 - 2024-09-25
@@ -37,7 +37,7 @@ module Hanami
37
37
  # @api private
38
38
  # @since 2.0.0
39
39
  def call(routes, **csv_opts)
40
- ::CSV.generate(**DEFAULT_OPTIONS.merge(csv_opts)) do |csv|
40
+ ::CSV.generate(**DEFAULT_OPTIONS, **csv_opts) do |csv|
41
41
  csv << HEADERS if csv.write_headers?
42
42
  routes.reduce(csv) do |acc, route|
43
43
  route.head? ? acc : acc << row(route)
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mustermann/rails"
4
+
5
+ module Hanami
6
+ class Router
7
+ class Leaf
8
+ # Trie Leaf
9
+ #
10
+ # @api private
11
+ # @since 2.2.0
12
+ attr_reader :to, :params
13
+
14
+ # @api private
15
+ # @since 2.2.0
16
+ def initialize(route, to, constraints)
17
+ @route = route
18
+ @to = to
19
+ @constraints = constraints
20
+ @params = nil
21
+ end
22
+
23
+ # @api private
24
+ # @since 2.2.0
25
+ def match(path)
26
+ match = matcher.match(path)
27
+
28
+ @params = match.named_captures if match
29
+
30
+ match
31
+ end
32
+
33
+ private
34
+
35
+ # @api private
36
+ # @since 2.2.0
37
+ def matcher
38
+ @matcher ||= Mustermann.new(@route, type: :rails, version: "5.0", capture: @constraints)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "hanami/router/segment"
3
+ require "hanami/router/leaf"
4
4
 
5
5
  module Hanami
6
6
  class Router
@@ -18,15 +18,14 @@ module Hanami
18
18
  def initialize
19
19
  @variable = nil
20
20
  @fixed = nil
21
- @to = nil
21
+ @leaves = nil
22
22
  end
23
23
 
24
24
  # @api private
25
25
  # @since 2.0.0
26
- def put(segment, constraints)
26
+ def put(segment)
27
27
  if variable?(segment)
28
- @variable ||= {}
29
- @variable[segment_for(segment, constraints)] ||= self.class.new
28
+ @variable ||= self.class.new
30
29
  else
31
30
  @fixed ||= {}
32
31
  @fixed[segment] ||= self.class.new
@@ -35,36 +34,21 @@ module Hanami
35
34
 
36
35
  # @api private
37
36
  # @since 2.0.0
38
- #
39
- def get(segment) # rubocop:disable Metrics/PerceivedComplexity
40
- return unless @variable || @fixed
41
-
42
- found = nil
43
- captured = nil
44
-
45
- found = @fixed&.fetch(segment, nil)
46
- return [found, nil] if found
47
-
48
- @variable&.each do |matcher, node|
49
- break if found
50
-
51
- captured = matcher.match(segment)
52
- found = node if captured
53
- end
54
-
55
- [found, captured&.named_captures]
37
+ def get(segment)
38
+ @fixed&.fetch(segment, nil) || @variable
56
39
  end
57
40
 
58
41
  # @api private
59
42
  # @since 2.0.0
60
- def leaf?
61
- @to
43
+ def leaf!(route, to, constraints)
44
+ @leaves ||= []
45
+ @leaves << Leaf.new(route, to, constraints)
62
46
  end
63
47
 
64
48
  # @api private
65
- # @since 2.0.0
66
- def leaf!(to)
67
- @to = to
49
+ # @since 2.2.0
50
+ def match(path)
51
+ @leaves&.find { |leaf| leaf.match(path) }
68
52
  end
69
53
 
70
54
  private
@@ -74,18 +58,6 @@ module Hanami
74
58
  def variable?(segment)
75
59
  Router::ROUTE_VARIABLE_MATCHER.match?(segment)
76
60
  end
77
-
78
- # @api private
79
- # @since 2.0.0
80
- def segment_for(segment, constraints)
81
- Segment.fabricate(segment, **constraints)
82
- end
83
-
84
- # @api private
85
- # @since 2.0.0
86
- def fixed?(matcher)
87
- matcher.names.empty?
88
- end
89
61
  end
90
62
  end
91
63
  end
@@ -21,33 +21,26 @@ module Hanami
21
21
 
22
22
  # @api private
23
23
  # @since 2.0.0
24
- def add(path, to, constraints)
24
+ def add(route, to, constraints)
25
+ segments = segments_from(route)
25
26
  node = @root
26
- for_each_segment(path) do |segment|
27
- node = node.put(segment, constraints)
27
+
28
+ segments.each do |segment|
29
+ node = node.put(segment)
28
30
  end
29
31
 
30
- node.leaf!(to)
32
+ node.leaf!(route, to, constraints)
31
33
  end
32
34
 
33
35
  # @api private
34
36
  # @since 2.0.0
35
37
  def find(path)
38
+ segments = segments_from(path)
36
39
  node = @root
37
- params = {}
38
-
39
- for_each_segment(path) do |segment|
40
- break unless node
41
40
 
42
- child, captures = node.get(segment)
43
- params.merge!(captures) if captures
44
-
45
- node = child
46
- end
41
+ return unless segments.all? { |segment| node = node.get(segment) }
47
42
 
48
- return [node.to, params] if node&.leaf?
49
-
50
- nil
43
+ node.match(path)&.then { |found| [found.to, found.params] }
51
44
  end
52
45
 
53
46
  private
@@ -58,10 +51,11 @@ module Hanami
58
51
  private_constant :SEGMENT_SEPARATOR
59
52
 
60
53
  # @api private
61
- # @since 2.0.0
62
- def for_each_segment(path, &blk)
54
+ # @since 2.2.0
55
+ def segments_from(path)
63
56
  _, *segments = path.split(SEGMENT_SEPARATOR)
64
- segments.each(&blk)
57
+
58
+ segments
65
59
  end
66
60
  end
67
61
  end
@@ -8,6 +8,6 @@ module Hanami
8
8
  #
9
9
  # @since 0.1.0
10
10
  # @api public
11
- VERSION = "2.2.0.rc1"
11
+ VERSION = "2.2.0"
12
12
  end
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-router
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0.rc1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-29 00:00:00.000000000 Z
11
+ date: 2024-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -171,6 +171,7 @@ files:
171
171
  - lib/hanami/router/formatter/human_friendly.rb
172
172
  - lib/hanami/router/globbed_path.rb
173
173
  - lib/hanami/router/inspector.rb
174
+ - lib/hanami/router/leaf.rb
174
175
  - lib/hanami/router/mounted_path.rb
175
176
  - lib/hanami/router/node.rb
176
177
  - lib/hanami/router/params.rb