Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions spec/lucky/action_route_params_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,54 @@ describe "Automatically generated param helpers" do
typeof(action.leftover).should eq String?
end
end

describe "Glob route URL building" do
it "builds URL with unnamed glob param using .with" do
TestGlobAction.with(glob: "some/path").path.should eq "/test_complex_posts_glob/some/path"
end

it "builds URL with named glob param using .with" do
TestNamedGlobAction.with(leftover: "some/path").path.should eq "/test_complex_posts_named_glob/some/path"
end

it "builds URL without glob param" do
TestGlobAction.with.path.should eq "/test_complex_posts_glob"
TestNamedGlobAction.with.path.should eq "/test_complex_posts_named_glob"
end

it "builds URL with nil glob param" do
TestGlobAction.with(glob: nil).path.should eq "/test_complex_posts_glob"
TestNamedGlobAction.with(leftover: nil).path.should eq "/test_complex_posts_named_glob"
end

it "URL-encodes special characters in glob segments" do
TestGlobAction.with(glob: "path with spaces/and more").path.should eq "/test_complex_posts_glob/path+with+spaces/and+more"
end

it "normalizes consecutive slashes in glob value" do
TestGlobAction.with(glob: "a//b").path.should eq "/test_complex_posts_glob/a/b"
end

it "strips leading slashes from glob value" do
TestGlobAction.with(glob: "/leading/slash").path.should eq "/test_complex_posts_glob/leading/slash"
end

it "builds URL with glob using .route" do
TestNamedGlobAction.route(leftover: "some/path").path.should eq "/test_complex_posts_named_glob/some/path"
end

it "builds path_without_query_params with glob" do
TestNamedGlobAction.path_without_query_params(leftover: "some/path").should eq "/test_complex_posts_named_glob/some/path"
end

it "builds url_without_query_params with glob" do
Lucky::RouteHelper.temp_config(base_uri: "example.com") do
TestNamedGlobAction.url_without_query_params(leftover: "some/path").should eq "example.com/test_complex_posts_named_glob/some/path"
end
end

it "returns correct RouteHelper with glob" do
route_helper = TestGlobAction.with(glob: "a/b/c")
route_helper.should eq Lucky::RouteHelper.new(:get, "/test_complex_posts_glob/a/b/c")
end
end
56 changes: 56 additions & 0 deletions src/lucky/routable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ module Lucky::Routable
end
{% end %}

# Extract glob param name for use in URL building methods
{% glob_param_name = nil %}
{% if glob_param %}
{% if glob_param.starts_with?("*:") %}
{% glob_param_name = glob_param.gsub(/\*:/, "") %}
{% elsif glob_param == "*" %}
{% glob_param_name = "glob" %}
{% end %}
{% end %}

def self.path(*args, **named_args) : String
route(*args, **named_args).path
end
Expand All @@ -240,6 +250,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }} = nil,
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }} = nil,
{% end %}
subdomain : String? = nil
) : String
path = path_from_parts(
Expand All @@ -249,6 +262,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
)
Lucky::RouteHelper.new({{ method }}, path, subdomain).url
end
Expand All @@ -260,6 +276,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }} = nil,
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }} = nil,
{% end %}
subdomain : String? = nil
) : String
path = path_from_parts(
Expand All @@ -269,6 +288,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
)
Lucky::RouteHelper.new({{ method }}, path, subdomain).path
end
Expand Down Expand Up @@ -300,6 +322,11 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }} = nil,
{% end %}

# glob param is optional
{% if glob_param_name %}
{{ glob_param_name.id }} = nil,
{% end %}
anchor : String? = nil,
subdomain : String? = nil
) : Lucky::RouteHelper
Expand All @@ -312,6 +339,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
)

query_params = URI::Params.build do |builder|
Expand Down Expand Up @@ -363,6 +393,11 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }} = nil,
{% end %}

# glob param is optional
{% if glob_param_name %}
{{ glob_param_name.id }} = nil,
{% end %}
anchor : String? = nil,
subdomain : String? = nil
) : Lucky::RouteHelper
Expand All @@ -383,6 +418,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
) : Nil
{% for part in path_parts %}
{% if part.starts_with?("?:") %}
Expand All @@ -393,11 +431,23 @@ module Lucky::Routable
{% elsif part.starts_with?(':') %}
io << '/'
URI.encode_www_form({{ part.gsub(/:/, "").id }}.to_param, io)
{% elsif part.starts_with?("*") %}
# glob param handled separately below
{% else %}
io << '/'
URI.encode_www_form({{ part }}, io)
{% end %}
{% end %}
{% if glob_param_name %}
if _glob_value = {{ glob_param_name.id }}
_glob_value.to_param.split('/').each do |segment|
unless segment.empty?
io << '/'
URI.encode_www_form(segment, io)
end
end
end
{% end %}
end

private def self.path_from_parts(
Expand All @@ -407,6 +457,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
) : String
path = String.build do |io|
path_from_parts(
Expand All @@ -417,6 +470,9 @@ module Lucky::Routable
{% for param in optional_path_params %}
{{ param.gsub(/^\?:/, "").id }},
{% end %}
{% if glob_param_name %}
{{ glob_param_name.id }},
{% end %}
)
end

Expand Down