addressable 2.3.6 → 2.8.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 +5 -5
- data/CHANGELOG.md +76 -0
- data/Gemfile +18 -18
- data/README.md +37 -18
- data/Rakefile +8 -11
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/native.rb +24 -6
- data/lib/addressable/idna/pure.rb +67 -58
- data/lib/addressable/idna.rb +3 -1
- data/lib/addressable/template.rb +126 -33
- data/lib/addressable/uri.rb +416 -211
- data/lib/addressable/version.rb +5 -3
- data/lib/addressable.rb +4 -0
- data/spec/addressable/idna_spec.rb +110 -46
- data/spec/addressable/net_http_compat_spec.rb +4 -2
- data/spec/addressable/security_spec.rb +59 -0
- data/spec/addressable/template_spec.rb +297 -165
- data/spec/addressable/uri_spec.rb +2054 -1329
- data/spec/spec_helper.rb +28 -1
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +22 -16
- data/tasks/git.rake +3 -1
- data/tasks/metrics.rake +2 -0
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +10 -45
- data/tasks/yard.rake +2 -0
- metadata +44 -45
- data/tasks/rubyforge.rake +0 -73
- data/website/index.html +0 -110
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# coding: utf-8
|
2
|
-
# Copyright (C)
|
4
|
+
# Copyright (C) Bob Aman
|
3
5
|
#
|
4
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
7
|
# you may not use this file except in compliance with the License.
|
@@ -16,6 +18,8 @@
|
|
16
18
|
|
17
19
|
require "spec_helper"
|
18
20
|
|
21
|
+
require "bigdecimal"
|
22
|
+
require "timeout"
|
19
23
|
require "addressable/template"
|
20
24
|
|
21
25
|
shared_examples_for 'expands' do |tests|
|
@@ -24,9 +28,9 @@ shared_examples_for 'expands' do |tests|
|
|
24
28
|
it "#{template} to #{exp}" do
|
25
29
|
tmpl = Addressable::Template.new(template).expand(subject)
|
26
30
|
if expansion.is_a?(Array)
|
27
|
-
expansion.any?{|i| i == tmpl.to_str}.
|
31
|
+
expect(expansion.any?{|i| i == tmpl.to_str}).to be true
|
28
32
|
else
|
29
|
-
tmpl.to_str.
|
33
|
+
expect(tmpl.to_str).to eq(expansion)
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -57,33 +61,31 @@ describe "==" do
|
|
57
61
|
let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
|
58
62
|
it 'is equal when the pattern matches' do
|
59
63
|
other_template = Addressable::Template.new('https://www.example.com/{foo}')
|
60
|
-
expect(template).
|
61
|
-
expect(other_template).
|
64
|
+
expect(template).to eq other_template
|
65
|
+
expect(other_template).to eq template
|
62
66
|
end
|
63
67
|
it 'is not equal when the pattern differs' do
|
64
68
|
other_template = Addressable::Template.new('https://www.example.com/{bar}')
|
65
|
-
expect(template).
|
66
|
-
expect(other_template).
|
69
|
+
expect(template).not_to eq other_template
|
70
|
+
expect(other_template).not_to eq template
|
67
71
|
end
|
68
72
|
it 'is not equal to non-templates' do
|
69
73
|
uri = 'https://www.example.com/foo/bar'
|
70
74
|
addressable_template = Addressable::Template.new uri
|
71
75
|
addressable_uri = Addressable::URI.parse uri
|
72
|
-
expect(addressable_template).
|
73
|
-
expect(addressable_uri).
|
76
|
+
expect(addressable_template).not_to eq addressable_uri
|
77
|
+
expect(addressable_uri).not_to eq addressable_template
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
77
81
|
describe "Type conversion" do
|
78
|
-
require "bigdecimal"
|
79
|
-
|
80
82
|
subject {
|
81
83
|
{
|
82
84
|
:var => true,
|
83
85
|
:hello => 1234,
|
84
86
|
:nothing => nil,
|
85
87
|
:sym => :symbolic,
|
86
|
-
:decimal => BigDecimal
|
88
|
+
:decimal => BigDecimal('1')
|
87
89
|
}
|
88
90
|
}
|
89
91
|
|
@@ -92,7 +94,7 @@ describe "Type conversion" do
|
|
92
94
|
'{hello}' => '1234',
|
93
95
|
'{nothing}' => '',
|
94
96
|
'{sym}' => 'symbolic',
|
95
|
-
'{decimal}' => '0.1E1'
|
97
|
+
'{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1'
|
96
98
|
}
|
97
99
|
end
|
98
100
|
|
@@ -699,6 +701,13 @@ describe "Expansion" do
|
|
699
701
|
]
|
700
702
|
}
|
701
703
|
end
|
704
|
+
context "non-string key in match data" do
|
705
|
+
subject {Addressable::Template.new("http://example.com/{one}")}
|
706
|
+
|
707
|
+
it "raises TypeError" do
|
708
|
+
expect { subject.expand(Object.new => "1") }.to raise_error TypeError
|
709
|
+
end
|
710
|
+
end
|
702
711
|
end
|
703
712
|
|
704
713
|
class ExampleTwoProcessor
|
@@ -729,6 +738,21 @@ class DumbProcessor
|
|
729
738
|
end
|
730
739
|
|
731
740
|
describe Addressable::Template do
|
741
|
+
describe 'initialize' do
|
742
|
+
context 'with a non-string' do
|
743
|
+
it 'raises a TypeError' do
|
744
|
+
expect { Addressable::Template.new(nil) }.to raise_error(TypeError)
|
745
|
+
end
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
describe 'freeze' do
|
750
|
+
subject { Addressable::Template.new("http://example.com/{first}/{+second}/") }
|
751
|
+
it 'freezes the template' do
|
752
|
+
expect(subject.freeze).to be_frozen
|
753
|
+
end
|
754
|
+
end
|
755
|
+
|
732
756
|
describe "Matching" do
|
733
757
|
let(:uri){
|
734
758
|
Addressable::URI.parse(
|
@@ -749,7 +773,7 @@ describe Addressable::Template do
|
|
749
773
|
}
|
750
774
|
context "first uri with ExampleTwoProcessor" do
|
751
775
|
subject {
|
752
|
-
|
776
|
+
Addressable::Template.new(
|
753
777
|
"http://example.com/search/{query}/"
|
754
778
|
).match(uri, ExampleTwoProcessor)
|
755
779
|
}
|
@@ -759,7 +783,7 @@ describe Addressable::Template do
|
|
759
783
|
|
760
784
|
context "second uri with ExampleTwoProcessor" do
|
761
785
|
subject {
|
762
|
-
|
786
|
+
Addressable::Template.new(
|
763
787
|
"http://example.com/{first}/{+second}/"
|
764
788
|
).match(uri2, ExampleTwoProcessor)
|
765
789
|
}
|
@@ -769,7 +793,7 @@ describe Addressable::Template do
|
|
769
793
|
|
770
794
|
context "second uri with DumbProcessor" do
|
771
795
|
subject {
|
772
|
-
|
796
|
+
Addressable::Template.new(
|
773
797
|
"http://example.com/{first}/{+second}/"
|
774
798
|
).match(uri2, DumbProcessor)
|
775
799
|
}
|
@@ -779,7 +803,7 @@ describe Addressable::Template do
|
|
779
803
|
|
780
804
|
context "second uri" do
|
781
805
|
subject {
|
782
|
-
|
806
|
+
Addressable::Template.new(
|
783
807
|
"http://example.com/{first}{/second*}/"
|
784
808
|
).match(uri2)
|
785
809
|
}
|
@@ -788,7 +812,7 @@ describe Addressable::Template do
|
|
788
812
|
end
|
789
813
|
context "third uri" do
|
790
814
|
subject {
|
791
|
-
|
815
|
+
Addressable::Template.new(
|
792
816
|
"http://example.com/{;hash*,first}"
|
793
817
|
).match(uri3)
|
794
818
|
}
|
@@ -801,7 +825,7 @@ describe Addressable::Template do
|
|
801
825
|
# Semantically, a separate key is more likely, but both are possible.
|
802
826
|
context "fourth uri" do
|
803
827
|
subject {
|
804
|
-
|
828
|
+
Addressable::Template.new(
|
805
829
|
"http://example.com/{?hash*,first}"
|
806
830
|
).match(uri4)
|
807
831
|
}
|
@@ -811,7 +835,7 @@ describe Addressable::Template do
|
|
811
835
|
end
|
812
836
|
context "fifth uri" do
|
813
837
|
subject {
|
814
|
-
|
838
|
+
Addressable::Template.new(
|
815
839
|
"http://example.com/{path}{?hash*,first}"
|
816
840
|
).match(uri5)
|
817
841
|
}
|
@@ -819,6 +843,22 @@ describe Addressable::Template do
|
|
819
843
|
its(:captures){ should == ["foo", nil, nil] }
|
820
844
|
end
|
821
845
|
end
|
846
|
+
|
847
|
+
describe 'match' do
|
848
|
+
subject { Addressable::Template.new('http://example.com/first/second/') }
|
849
|
+
context 'when the URI is the same as the template' do
|
850
|
+
it 'returns the match data itself with an empty mapping' do
|
851
|
+
uri = Addressable::URI.parse('http://example.com/first/second/')
|
852
|
+
match_data = subject.match(uri)
|
853
|
+
expect(match_data).to be_an Addressable::Template::MatchData
|
854
|
+
expect(match_data.uri).to eq(uri)
|
855
|
+
expect(match_data.template).to eq(subject)
|
856
|
+
expect(match_data.mapping).to be_empty
|
857
|
+
expect(match_data.inspect).to be_an String
|
858
|
+
end
|
859
|
+
end
|
860
|
+
end
|
861
|
+
|
822
862
|
describe "extract" do
|
823
863
|
let(:template) {
|
824
864
|
Addressable::Template.new(
|
@@ -828,24 +868,24 @@ describe Addressable::Template do
|
|
828
868
|
let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
|
829
869
|
let(:uri2){ "http://example.com/a/b/c/#foo" }
|
830
870
|
it "should be able to extract with queries" do
|
831
|
-
template.extract(uri).
|
871
|
+
expect(template.extract(uri)).to eq({
|
832
872
|
"host" => "example.com",
|
833
873
|
"segments" => %w(a b c),
|
834
874
|
"one" => "1",
|
835
875
|
"bogus" => nil,
|
836
876
|
"two" => "2",
|
837
877
|
"fragment" => "foo"
|
838
|
-
}
|
878
|
+
})
|
839
879
|
end
|
840
880
|
it "should be able to extract without queries" do
|
841
|
-
template.extract(uri2).
|
881
|
+
expect(template.extract(uri2)).to eq({
|
842
882
|
"host" => "example.com",
|
843
883
|
"segments" => %w(a b c),
|
844
884
|
"one" => nil,
|
845
885
|
"bogus" => nil,
|
846
886
|
"two" => nil,
|
847
887
|
"fragment" => "foo"
|
848
|
-
}
|
888
|
+
})
|
849
889
|
end
|
850
890
|
|
851
891
|
context "issue #137" do
|
@@ -853,30 +893,30 @@ describe Addressable::Template do
|
|
853
893
|
|
854
894
|
it "can match empty" do
|
855
895
|
data = subject.extract("/path")
|
856
|
-
data["page"].
|
857
|
-
data["per_page"].
|
858
|
-
data.keys.sort.
|
896
|
+
expect(data["page"]).to eq(nil)
|
897
|
+
expect(data["per_page"]).to eq(nil)
|
898
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
859
899
|
end
|
860
900
|
|
861
901
|
it "can match first var" do
|
862
902
|
data = subject.extract("/path?page=1")
|
863
|
-
data["page"].
|
864
|
-
data["per_page"].
|
865
|
-
data.keys.sort.
|
903
|
+
expect(data["page"]).to eq("1")
|
904
|
+
expect(data["per_page"]).to eq(nil)
|
905
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
866
906
|
end
|
867
907
|
|
868
908
|
it "can match second var" do
|
869
909
|
data = subject.extract("/path?per_page=1")
|
870
|
-
data["page"].
|
871
|
-
data["per_page"].
|
872
|
-
data.keys.sort.
|
910
|
+
expect(data["page"]).to eq(nil)
|
911
|
+
expect(data["per_page"]).to eq("1")
|
912
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
873
913
|
end
|
874
914
|
|
875
915
|
it "can match both vars" do
|
876
916
|
data = subject.extract("/path?page=2&per_page=1")
|
877
|
-
data["page"].
|
878
|
-
data["per_page"].
|
879
|
-
data.keys.sort.
|
917
|
+
expect(data["page"]).to eq("2")
|
918
|
+
expect(data["per_page"]).to eq("1")
|
919
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
880
920
|
end
|
881
921
|
end
|
882
922
|
end
|
@@ -887,8 +927,9 @@ describe Addressable::Template do
|
|
887
927
|
Addressable::Template.new("http://example.com/{one}/{two}/")
|
888
928
|
}
|
889
929
|
it "builds a new pattern" do
|
890
|
-
subject.partial_expand(:one => "1").pattern.
|
930
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
891
931
|
"http://example.com/1/{two}/"
|
932
|
+
)
|
892
933
|
end
|
893
934
|
end
|
894
935
|
context "partial_expand query with missing param in middle" do
|
@@ -896,8 +937,49 @@ describe Addressable::Template do
|
|
896
937
|
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
897
938
|
}
|
898
939
|
it "builds a new pattern" do
|
899
|
-
subject.partial_expand(:one => "1", :three => "3").pattern.
|
940
|
+
expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq(
|
900
941
|
"http://example.com/?one=1{&two}&three=3/"
|
942
|
+
)
|
943
|
+
end
|
944
|
+
end
|
945
|
+
context "partial_expand form style query with missing param at beginning" do
|
946
|
+
subject {
|
947
|
+
Addressable::Template.new("http://example.com/{?one,two}/")
|
948
|
+
}
|
949
|
+
it "builds a new pattern" do
|
950
|
+
expect(subject.partial_expand(:two => "2").pattern).to eq(
|
951
|
+
"http://example.com/?two=2{&one}/"
|
952
|
+
)
|
953
|
+
end
|
954
|
+
end
|
955
|
+
context "issue #307 - partial_expand form query with nil params" do
|
956
|
+
subject do
|
957
|
+
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
958
|
+
end
|
959
|
+
it "builds a new pattern with two=nil" do
|
960
|
+
expect(subject.partial_expand(two: nil).pattern).to eq(
|
961
|
+
"http://example.com/{?one}{&three}/"
|
962
|
+
)
|
963
|
+
end
|
964
|
+
it "builds a new pattern with one=nil and two=nil" do
|
965
|
+
expect(subject.partial_expand(one: nil, two: nil).pattern).to eq(
|
966
|
+
"http://example.com/{?three}/"
|
967
|
+
)
|
968
|
+
end
|
969
|
+
it "builds a new pattern with one=1 and two=nil" do
|
970
|
+
expect(subject.partial_expand(one: 1, two: nil).pattern).to eq(
|
971
|
+
"http://example.com/?one=1{&three}/"
|
972
|
+
)
|
973
|
+
end
|
974
|
+
it "builds a new pattern with one=nil and two=2" do
|
975
|
+
expect(subject.partial_expand(one: nil, two: 2).pattern).to eq(
|
976
|
+
"http://example.com/?two=2{&three}/"
|
977
|
+
)
|
978
|
+
end
|
979
|
+
it "builds a new pattern with one=nil" do
|
980
|
+
expect(subject.partial_expand(one: nil).pattern).to eq(
|
981
|
+
"http://example.com/{?two}{&three}/"
|
982
|
+
)
|
901
983
|
end
|
902
984
|
end
|
903
985
|
context "partial_expand with query string" do
|
@@ -905,8 +987,9 @@ describe Addressable::Template do
|
|
905
987
|
Addressable::Template.new("http://example.com/{?two,one}/")
|
906
988
|
}
|
907
989
|
it "builds a new pattern" do
|
908
|
-
subject.partial_expand(:one => "1").pattern.
|
909
|
-
"http://example.com
|
990
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
991
|
+
"http://example.com/?one=1{&two}/"
|
992
|
+
)
|
910
993
|
end
|
911
994
|
end
|
912
995
|
context "partial_expand with path operator" do
|
@@ -914,8 +997,27 @@ describe Addressable::Template do
|
|
914
997
|
Addressable::Template.new("http://example.com{/one,two}/")
|
915
998
|
}
|
916
999
|
it "builds a new pattern" do
|
917
|
-
subject.partial_expand(:one => "1").pattern.
|
1000
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
918
1001
|
"http://example.com/1{/two}/"
|
1002
|
+
)
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
context "partial expand with unicode values" do
|
1006
|
+
subject do
|
1007
|
+
Addressable::Template.new("http://example.com/{resource}/{query}/")
|
1008
|
+
end
|
1009
|
+
it "normalizes unicode by default" do
|
1010
|
+
template = subject.partial_expand("query" => "Cafe\u0301")
|
1011
|
+
expect(template.pattern).to eq(
|
1012
|
+
"http://example.com/{resource}/Caf%C3%A9/"
|
1013
|
+
)
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
it "does not normalize unicode when byte semantics requested" do
|
1017
|
+
template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false)
|
1018
|
+
expect(template.pattern).to eq(
|
1019
|
+
"http://example.com/{resource}/Cafe%CC%81/"
|
1020
|
+
)
|
919
1021
|
end
|
920
1022
|
end
|
921
1023
|
end
|
@@ -925,8 +1027,9 @@ describe Addressable::Template do
|
|
925
1027
|
Addressable::Template.new("http://example.com/{one}/{two}/")
|
926
1028
|
}
|
927
1029
|
it "builds a new pattern" do
|
928
|
-
subject.partial_expand("one" => "1").pattern.
|
1030
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
929
1031
|
"http://example.com/1/{two}/"
|
1032
|
+
)
|
930
1033
|
end
|
931
1034
|
end
|
932
1035
|
context "partial_expand query with missing param in middle" do
|
@@ -934,8 +1037,9 @@ describe Addressable::Template do
|
|
934
1037
|
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
935
1038
|
}
|
936
1039
|
it "builds a new pattern" do
|
937
|
-
subject.partial_expand("one" => "1", "three" => "3").pattern.
|
1040
|
+
expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
|
938
1041
|
"http://example.com/?one=1{&two}&three=3/"
|
1042
|
+
)
|
939
1043
|
end
|
940
1044
|
end
|
941
1045
|
context "partial_expand with query string" do
|
@@ -943,8 +1047,9 @@ describe Addressable::Template do
|
|
943
1047
|
Addressable::Template.new("http://example.com/{?two,one}/")
|
944
1048
|
}
|
945
1049
|
it "builds a new pattern" do
|
946
|
-
subject.partial_expand("one" => "1").pattern.
|
947
|
-
"http://example.com
|
1050
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1051
|
+
"http://example.com/?one=1{&two}/"
|
1052
|
+
)
|
948
1053
|
end
|
949
1054
|
end
|
950
1055
|
context "partial_expand with path operator" do
|
@@ -952,26 +1057,42 @@ describe Addressable::Template do
|
|
952
1057
|
Addressable::Template.new("http://example.com{/one,two}/")
|
953
1058
|
}
|
954
1059
|
it "builds a new pattern" do
|
955
|
-
subject.partial_expand("one" => "1").pattern.
|
1060
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
956
1061
|
"http://example.com/1{/two}/"
|
1062
|
+
)
|
957
1063
|
end
|
958
1064
|
end
|
959
1065
|
end
|
960
1066
|
describe "Expand" do
|
1067
|
+
context "expand with unicode values" do
|
1068
|
+
subject do
|
1069
|
+
Addressable::Template.new("http://example.com/search/{query}/")
|
1070
|
+
end
|
1071
|
+
it "normalizes unicode by default" do
|
1072
|
+
uri = subject.expand("query" => "Cafe\u0301").to_str
|
1073
|
+
expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
it "does not normalize unicode when byte semantics requested" do
|
1077
|
+
uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str
|
1078
|
+
expect(uri).to eq("http://example.com/search/Cafe%CC%81/")
|
1079
|
+
end
|
1080
|
+
end
|
961
1081
|
context "expand with a processor" do
|
962
1082
|
subject {
|
963
1083
|
Addressable::Template.new("http://example.com/search/{query}/")
|
964
1084
|
}
|
965
1085
|
it "processes spaces" do
|
966
|
-
subject.expand({"query" => "an example search query"},
|
967
|
-
ExampleTwoProcessor).to_str.
|
1086
|
+
expect(subject.expand({"query" => "an example search query"},
|
1087
|
+
ExampleTwoProcessor).to_str).to eq(
|
968
1088
|
"http://example.com/search/an+example+search+query/"
|
1089
|
+
)
|
969
1090
|
end
|
970
1091
|
it "validates" do
|
971
|
-
|
1092
|
+
expect{
|
972
1093
|
subject.expand({"query" => "Bogus!"},
|
973
1094
|
ExampleTwoProcessor).to_str
|
974
|
-
}.
|
1095
|
+
}.to raise_error(Addressable::Template::InvalidTemplateValueError)
|
975
1096
|
end
|
976
1097
|
end
|
977
1098
|
context "partial_expand query with missing param in middle" do
|
@@ -979,8 +1100,9 @@ describe Addressable::Template do
|
|
979
1100
|
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
980
1101
|
}
|
981
1102
|
it "builds a new pattern" do
|
982
|
-
subject.partial_expand("one" => "1", "three" => "3").pattern.
|
1103
|
+
expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
|
983
1104
|
"http://example.com/?one=1{&two}&three=3/"
|
1105
|
+
)
|
984
1106
|
end
|
985
1107
|
end
|
986
1108
|
context "partial_expand with query string" do
|
@@ -988,8 +1110,9 @@ describe Addressable::Template do
|
|
988
1110
|
Addressable::Template.new("http://example.com/{?two,one}/")
|
989
1111
|
}
|
990
1112
|
it "builds a new pattern" do
|
991
|
-
subject.partial_expand("one" => "1").pattern.
|
992
|
-
"http://example.com
|
1113
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1114
|
+
"http://example.com/?one=1{&two}/"
|
1115
|
+
)
|
993
1116
|
end
|
994
1117
|
end
|
995
1118
|
context "partial_expand with path operator" do
|
@@ -997,8 +1120,9 @@ describe Addressable::Template do
|
|
997
1120
|
Addressable::Template.new("http://example.com{/one,two}/")
|
998
1121
|
}
|
999
1122
|
it "builds a new pattern" do
|
1000
|
-
subject.partial_expand("one" => "1").pattern.
|
1123
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1001
1124
|
"http://example.com/1{/two}/"
|
1125
|
+
)
|
1002
1126
|
end
|
1003
1127
|
end
|
1004
1128
|
end
|
@@ -1007,20 +1131,20 @@ describe Addressable::Template do
|
|
1007
1131
|
subject { Addressable::Template.new("foo{foo}/{bar}baz") }
|
1008
1132
|
it "can match" do
|
1009
1133
|
data = subject.match("foofoo/bananabaz")
|
1010
|
-
data.mapping["foo"].
|
1011
|
-
data.mapping["bar"].
|
1134
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1135
|
+
expect(data.mapping["bar"]).to eq("banana")
|
1012
1136
|
end
|
1013
1137
|
it "can fail" do
|
1014
|
-
subject.match("bar/foo").
|
1015
|
-
subject.match("foobaz").
|
1138
|
+
expect(subject.match("bar/foo")).to be_nil
|
1139
|
+
expect(subject.match("foobaz")).to be_nil
|
1016
1140
|
end
|
1017
1141
|
it "can match empty" do
|
1018
1142
|
data = subject.match("foo/baz")
|
1019
|
-
data.mapping["foo"].
|
1020
|
-
data.mapping["bar"].
|
1143
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1144
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1021
1145
|
end
|
1022
1146
|
it "lists vars" do
|
1023
|
-
subject.variables.
|
1147
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1024
1148
|
end
|
1025
1149
|
end
|
1026
1150
|
|
@@ -1028,27 +1152,27 @@ describe Addressable::Template do
|
|
1028
1152
|
subject { Addressable::Template.new("foo{+foo}{#bar}baz") }
|
1029
1153
|
it "can match" do
|
1030
1154
|
data = subject.match("foo/test/banana#bazbaz")
|
1031
|
-
data.mapping["foo"].
|
1032
|
-
data.mapping["bar"].
|
1155
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1156
|
+
expect(data.mapping["bar"]).to eq("baz")
|
1033
1157
|
end
|
1034
1158
|
it "can match empty level 2 #" do
|
1035
1159
|
data = subject.match("foo/test/bananabaz")
|
1036
|
-
data.mapping["foo"].
|
1037
|
-
data.mapping["bar"].
|
1160
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1161
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1038
1162
|
data = subject.match("foo/test/banana#baz")
|
1039
|
-
data.mapping["foo"].
|
1040
|
-
data.mapping["bar"].
|
1163
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1164
|
+
expect(data.mapping["bar"]).to eq("")
|
1041
1165
|
end
|
1042
1166
|
it "can match empty level 2 +" do
|
1043
1167
|
data = subject.match("foobaz")
|
1044
|
-
data.mapping["foo"].
|
1045
|
-
data.mapping["bar"].
|
1168
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1169
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1046
1170
|
data = subject.match("foo#barbaz")
|
1047
|
-
data.mapping["foo"].
|
1048
|
-
data.mapping["bar"].
|
1171
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1172
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1049
1173
|
end
|
1050
1174
|
it "lists vars" do
|
1051
|
-
subject.variables.
|
1175
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1052
1176
|
end
|
1053
1177
|
end
|
1054
1178
|
|
@@ -1057,56 +1181,56 @@ describe Addressable::Template do
|
|
1057
1181
|
subject { Addressable::Template.new("foo{foo,bar}baz") }
|
1058
1182
|
it "can match" do
|
1059
1183
|
data = subject.match("foofoo,barbaz")
|
1060
|
-
data.mapping["foo"].
|
1061
|
-
data.mapping["bar"].
|
1184
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1185
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1062
1186
|
end
|
1063
1187
|
it "lists vars" do
|
1064
|
-
subject.variables.
|
1188
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1065
1189
|
end
|
1066
1190
|
end
|
1067
1191
|
context "+ operator" do
|
1068
1192
|
subject { Addressable::Template.new("foo{+foo,bar}baz") }
|
1069
1193
|
it "can match" do
|
1070
1194
|
data = subject.match("foofoo/bar,barbaz")
|
1071
|
-
data.mapping["bar"].
|
1072
|
-
data.mapping["foo"].
|
1195
|
+
expect(data.mapping["bar"]).to eq("foo/bar,bar")
|
1196
|
+
expect(data.mapping["foo"]).to eq("")
|
1073
1197
|
end
|
1074
1198
|
it "lists vars" do
|
1075
|
-
subject.variables.
|
1199
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1076
1200
|
end
|
1077
1201
|
end
|
1078
1202
|
context ". operator" do
|
1079
1203
|
subject { Addressable::Template.new("foo{.foo,bar}baz") }
|
1080
1204
|
it "can match" do
|
1081
1205
|
data = subject.match("foo.foo.barbaz")
|
1082
|
-
data.mapping["foo"].
|
1083
|
-
data.mapping["bar"].
|
1206
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1207
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1084
1208
|
end
|
1085
1209
|
it "lists vars" do
|
1086
|
-
subject.variables.
|
1210
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1087
1211
|
end
|
1088
1212
|
end
|
1089
1213
|
context "/ operator" do
|
1090
1214
|
subject { Addressable::Template.new("foo{/foo,bar}baz") }
|
1091
1215
|
it "can match" do
|
1092
1216
|
data = subject.match("foo/foo/barbaz")
|
1093
|
-
data.mapping["foo"].
|
1094
|
-
data.mapping["bar"].
|
1217
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1218
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1095
1219
|
end
|
1096
1220
|
it "lists vars" do
|
1097
|
-
subject.variables.
|
1221
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1098
1222
|
end
|
1099
1223
|
end
|
1100
1224
|
context "; operator" do
|
1101
1225
|
subject { Addressable::Template.new("foo{;foo,bar,baz}baz") }
|
1102
1226
|
it "can match" do
|
1103
1227
|
data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz")
|
1104
|
-
data.mapping["foo"].
|
1105
|
-
data.mapping["bar"].
|
1106
|
-
data.mapping["baz"].
|
1228
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1229
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1230
|
+
expect(data.mapping["baz"]).to eq("")
|
1107
1231
|
end
|
1108
1232
|
it "lists vars" do
|
1109
|
-
subject.variables.
|
1233
|
+
expect(subject.variables).to eq(%w(foo bar baz))
|
1110
1234
|
end
|
1111
1235
|
end
|
1112
1236
|
context "? operator" do
|
@@ -1114,11 +1238,11 @@ describe Addressable::Template do
|
|
1114
1238
|
subject { Addressable::Template.new("foo{?foo,bar}baz") }
|
1115
1239
|
it "can match" do
|
1116
1240
|
data = subject.match("foo?foo=bar%20baz&bar=foobaz")
|
1117
|
-
data.mapping["foo"].
|
1118
|
-
data.mapping["bar"].
|
1241
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1242
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1119
1243
|
end
|
1120
1244
|
it "lists vars" do
|
1121
|
-
subject.variables.
|
1245
|
+
expect(subject.variables).to eq(%w(foo bar))
|
1122
1246
|
end
|
1123
1247
|
end
|
1124
1248
|
|
@@ -1127,30 +1251,30 @@ describe Addressable::Template do
|
|
1127
1251
|
|
1128
1252
|
it "can match empty" do
|
1129
1253
|
data = subject.match("/path")
|
1130
|
-
data.mapping["page"].
|
1131
|
-
data.mapping["per_page"].
|
1132
|
-
data.mapping.keys.sort.
|
1254
|
+
expect(data.mapping["page"]).to eq(nil)
|
1255
|
+
expect(data.mapping["per_page"]).to eq(nil)
|
1256
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1133
1257
|
end
|
1134
1258
|
|
1135
1259
|
it "can match first var" do
|
1136
1260
|
data = subject.match("/path?page=1")
|
1137
|
-
data.mapping["page"].
|
1138
|
-
data.mapping["per_page"].
|
1139
|
-
data.mapping.keys.sort.
|
1261
|
+
expect(data.mapping["page"]).to eq("1")
|
1262
|
+
expect(data.mapping["per_page"]).to eq(nil)
|
1263
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1140
1264
|
end
|
1141
1265
|
|
1142
1266
|
it "can match second var" do
|
1143
1267
|
data = subject.match("/path?per_page=1")
|
1144
|
-
data.mapping["page"].
|
1145
|
-
data.mapping["per_page"].
|
1146
|
-
data.mapping.keys.sort.
|
1268
|
+
expect(data.mapping["page"]).to eq(nil)
|
1269
|
+
expect(data.mapping["per_page"]).to eq("1")
|
1270
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1147
1271
|
end
|
1148
1272
|
|
1149
1273
|
it "can match both vars" do
|
1150
1274
|
data = subject.match("/path?page=2&per_page=1")
|
1151
|
-
data.mapping["page"].
|
1152
|
-
data.mapping["per_page"].
|
1153
|
-
data.mapping.keys.sort.
|
1275
|
+
expect(data.mapping["page"]).to eq("2")
|
1276
|
+
expect(data.mapping["per_page"]).to eq("1")
|
1277
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1154
1278
|
end
|
1155
1279
|
end
|
1156
1280
|
|
@@ -1158,11 +1282,11 @@ describe Addressable::Template do
|
|
1158
1282
|
subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
|
1159
1283
|
it "can match" do
|
1160
1284
|
data = subject.match("http://cyberscore.dev/api/users?username=foobaz")
|
1161
|
-
data.mapping["username"].
|
1285
|
+
expect(data.mapping["username"]).to eq("foobaz")
|
1162
1286
|
end
|
1163
1287
|
it "lists vars" do
|
1164
|
-
subject.variables.
|
1165
|
-
subject.keys.
|
1288
|
+
expect(subject.variables).to eq(%w(username))
|
1289
|
+
expect(subject.keys).to eq(%w(username))
|
1166
1290
|
end
|
1167
1291
|
end
|
1168
1292
|
end
|
@@ -1170,11 +1294,11 @@ describe Addressable::Template do
|
|
1170
1294
|
subject { Addressable::Template.new("foo{&foo,bar}baz") }
|
1171
1295
|
it "can match" do
|
1172
1296
|
data = subject.match("foo&foo=bar%20baz&bar=foobaz")
|
1173
|
-
data.mapping["foo"].
|
1174
|
-
data.mapping["bar"].
|
1297
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1298
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1175
1299
|
end
|
1176
1300
|
it "lists vars" do
|
1177
|
-
subject.variables.
|
1301
|
+
expect(subject.variables).to eq(%w(foo bar))
|
1178
1302
|
end
|
1179
1303
|
end
|
1180
1304
|
end
|
@@ -1184,70 +1308,78 @@ describe Addressable::Template do
|
|
1184
1308
|
context "EXPRESSION" do
|
1185
1309
|
subject { Addressable::Template::EXPRESSION }
|
1186
1310
|
it "should be able to match an expression" do
|
1187
|
-
subject.
|
1188
|
-
subject.
|
1189
|
-
subject.
|
1190
|
-
subject.
|
1191
|
-
subject.
|
1192
|
-
subject.
|
1193
|
-
subject.
|
1311
|
+
expect(subject).to match("{foo}")
|
1312
|
+
expect(subject).to match("{foo,9}")
|
1313
|
+
expect(subject).to match("{foo.bar,baz}")
|
1314
|
+
expect(subject).to match("{+foo.bar,baz}")
|
1315
|
+
expect(subject).to match("{foo,foo%20bar}")
|
1316
|
+
expect(subject).to match("{#foo:20,baz*}")
|
1317
|
+
expect(subject).to match("stuff{#foo:20,baz*}things")
|
1194
1318
|
end
|
1195
1319
|
it "should fail on non vars" do
|
1196
|
-
subject.
|
1197
|
-
subject.
|
1198
|
-
subject.
|
1320
|
+
expect(subject).not_to match("!{foo")
|
1321
|
+
expect(subject).not_to match("{foo.bar.}")
|
1322
|
+
expect(subject).not_to match("!{}")
|
1199
1323
|
end
|
1200
1324
|
end
|
1201
1325
|
context "VARNAME" do
|
1202
1326
|
subject { Addressable::Template::VARNAME }
|
1203
1327
|
it "should be able to match a variable" do
|
1204
|
-
subject.
|
1205
|
-
subject.
|
1206
|
-
subject.
|
1207
|
-
subject.
|
1208
|
-
subject.
|
1209
|
-
subject.
|
1210
|
-
subject.
|
1328
|
+
expect(subject).to match("foo")
|
1329
|
+
expect(subject).to match("9")
|
1330
|
+
expect(subject).to match("foo.bar")
|
1331
|
+
expect(subject).to match("foo_bar")
|
1332
|
+
expect(subject).to match("foo_bar.baz")
|
1333
|
+
expect(subject).to match("foo%20bar")
|
1334
|
+
expect(subject).to match("foo%20bar.baz")
|
1211
1335
|
end
|
1212
1336
|
it "should fail on non vars" do
|
1213
|
-
subject.
|
1214
|
-
subject.
|
1215
|
-
subject.
|
1216
|
-
subject.
|
1217
|
-
subject.
|
1218
|
-
subject.
|
1337
|
+
expect(subject).not_to match("!foo")
|
1338
|
+
expect(subject).not_to match("foo.bar.")
|
1339
|
+
expect(subject).not_to match("foo%2%00bar")
|
1340
|
+
expect(subject).not_to match("foo_ba%r")
|
1341
|
+
expect(subject).not_to match("foo_bar*")
|
1342
|
+
expect(subject).not_to match("foo_bar:20")
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
it 'should parse in a reasonable time' do
|
1346
|
+
expect do
|
1347
|
+
Timeout.timeout(0.1) do
|
1348
|
+
expect(subject).not_to match("0"*25 + "!")
|
1349
|
+
end
|
1350
|
+
end.not_to raise_error
|
1219
1351
|
end
|
1220
1352
|
end
|
1221
1353
|
context "VARIABLE_LIST" do
|
1222
1354
|
subject { Addressable::Template::VARIABLE_LIST }
|
1223
1355
|
it "should be able to match a variable list" do
|
1224
|
-
subject.
|
1225
|
-
subject.
|
1226
|
-
subject.
|
1227
|
-
subject.
|
1356
|
+
expect(subject).to match("foo,bar")
|
1357
|
+
expect(subject).to match("foo")
|
1358
|
+
expect(subject).to match("foo,bar*,baz")
|
1359
|
+
expect(subject).to match("foo.bar,bar_baz*,baz:12")
|
1228
1360
|
end
|
1229
1361
|
it "should fail on non vars" do
|
1230
|
-
subject.
|
1231
|
-
subject.
|
1232
|
-
subject.
|
1362
|
+
expect(subject).not_to match(",foo,bar*,baz")
|
1363
|
+
expect(subject).not_to match("foo,*bar,baz")
|
1364
|
+
expect(subject).not_to match("foo,,bar*,baz")
|
1233
1365
|
end
|
1234
1366
|
end
|
1235
1367
|
context "VARSPEC" do
|
1236
1368
|
subject { Addressable::Template::VARSPEC }
|
1237
1369
|
it "should be able to match a variable with modifier" do
|
1238
|
-
subject.
|
1239
|
-
subject.
|
1240
|
-
subject.
|
1241
|
-
subject.
|
1242
|
-
subject.
|
1243
|
-
subject.
|
1370
|
+
expect(subject).to match("9:8")
|
1371
|
+
expect(subject).to match("foo.bar*")
|
1372
|
+
expect(subject).to match("foo_bar:12")
|
1373
|
+
expect(subject).to match("foo_bar.baz*")
|
1374
|
+
expect(subject).to match("foo%20bar:12")
|
1375
|
+
expect(subject).to match("foo%20bar.baz*")
|
1244
1376
|
end
|
1245
1377
|
it "should fail on non vars" do
|
1246
|
-
subject.
|
1247
|
-
subject.
|
1248
|
-
subject.
|
1249
|
-
subject.
|
1250
|
-
subject.
|
1378
|
+
expect(subject).not_to match("!foo")
|
1379
|
+
expect(subject).not_to match("*foo")
|
1380
|
+
expect(subject).not_to match("fo*o")
|
1381
|
+
expect(subject).not_to match("fo:o")
|
1382
|
+
expect(subject).not_to match("foo:")
|
1251
1383
|
end
|
1252
1384
|
end
|
1253
1385
|
end
|
@@ -1272,45 +1404,45 @@ describe Addressable::Template::MatchData do
|
|
1272
1404
|
|
1273
1405
|
describe 'values_at' do
|
1274
1406
|
it 'returns an array with the values' do
|
1275
|
-
its.values_at(0, 2).
|
1407
|
+
expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd'])
|
1276
1408
|
end
|
1277
1409
|
it 'allows mixing integer an string keys' do
|
1278
|
-
its.values_at('foo', 1).
|
1410
|
+
expect(its.values_at('foo', 1)).to eq(['ab', 'ab'])
|
1279
1411
|
end
|
1280
1412
|
it 'accepts unknown keys' do
|
1281
|
-
its.values_at('baz', 'foo').
|
1413
|
+
expect(its.values_at('baz', 'foo')).to eq([nil, 'ab'])
|
1282
1414
|
end
|
1283
1415
|
end
|
1284
1416
|
|
1285
1417
|
describe '[]' do
|
1286
1418
|
context 'string key' do
|
1287
1419
|
it 'returns the corresponding capture' do
|
1288
|
-
its['foo'].
|
1289
|
-
its['bar'].
|
1420
|
+
expect(its['foo']).to eq('ab')
|
1421
|
+
expect(its['bar']).to eq('cd')
|
1290
1422
|
end
|
1291
1423
|
it 'returns nil for unknown keys' do
|
1292
|
-
its['baz'].
|
1424
|
+
expect(its['baz']).to be_nil
|
1293
1425
|
end
|
1294
1426
|
end
|
1295
1427
|
context 'symbol key' do
|
1296
1428
|
it 'returns the corresponding capture' do
|
1297
|
-
its[:foo].
|
1298
|
-
its[:bar].
|
1429
|
+
expect(its[:foo]).to eq('ab')
|
1430
|
+
expect(its[:bar]).to eq('cd')
|
1299
1431
|
end
|
1300
1432
|
it 'returns nil for unknown keys' do
|
1301
|
-
its[:baz].
|
1433
|
+
expect(its[:baz]).to be_nil
|
1302
1434
|
end
|
1303
1435
|
end
|
1304
1436
|
context 'integer key' do
|
1305
1437
|
it 'returns the full URI for index 0' do
|
1306
|
-
its[0].
|
1438
|
+
expect(its[0]).to eq('ab/cd')
|
1307
1439
|
end
|
1308
1440
|
it 'returns the corresponding capture' do
|
1309
|
-
its[1].
|
1310
|
-
its[2].
|
1441
|
+
expect(its[1]).to eq('ab')
|
1442
|
+
expect(its[2]).to eq('cd')
|
1311
1443
|
end
|
1312
1444
|
it 'returns nil for unknown keys' do
|
1313
|
-
its[3].
|
1445
|
+
expect(its[3]).to be_nil
|
1314
1446
|
end
|
1315
1447
|
end
|
1316
1448
|
context 'other key' do
|
@@ -1320,8 +1452,8 @@ describe Addressable::Template::MatchData do
|
|
1320
1452
|
end
|
1321
1453
|
context 'with length' do
|
1322
1454
|
it 'returns an array starting at index with given length' do
|
1323
|
-
its[0, 2].
|
1324
|
-
its[2, 1].
|
1455
|
+
expect(its[0, 2]).to eq(['ab/cd', 'ab'])
|
1456
|
+
expect(its[2, 1]).to eq(['cd'])
|
1325
1457
|
end
|
1326
1458
|
end
|
1327
1459
|
end
|