addressable 2.6.0 → 2.8.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +64 -0
- data/Gemfile +14 -16
- data/README.md +12 -10
- data/Rakefile +14 -8
- data/addressable.gemspec +28 -0
- data/lib/addressable/idna/native.rb +8 -3
- data/lib/addressable/idna/pure.rb +20 -191
- data/lib/addressable/idna.rb +0 -1
- data/lib/addressable/template.rb +37 -53
- data/lib/addressable/uri.rb +257 -176
- data/lib/addressable/version.rb +2 -3
- data/spec/addressable/idna_spec.rb +9 -7
- data/spec/addressable/net_http_compat_spec.rb +0 -1
- data/spec/addressable/security_spec.rb +0 -1
- data/spec/addressable/template_spec.rb +78 -265
- data/spec/addressable/uri_spec.rb +503 -208
- data/spec/spec_helper.rb +9 -0
- data/tasks/gem.rake +9 -7
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +1 -1
- metadata +16 -15
- data/spec/addressable/rack_mount_compat_spec.rb +0 -106
data/lib/addressable/template.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# encoding:utf-8
|
4
3
|
#--
|
5
4
|
# Copyright (C) Bob Aman
|
6
5
|
#
|
@@ -37,7 +36,7 @@ module Addressable
|
|
37
36
|
Addressable::URI::CharacterClasses::DIGIT + '_'
|
38
37
|
|
39
38
|
var_char =
|
40
|
-
"(
|
39
|
+
"(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
|
41
40
|
RESERVED =
|
42
41
|
"(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
|
43
42
|
UNRESERVED =
|
@@ -412,7 +411,7 @@ module Addressable
|
|
412
411
|
# match.captures
|
413
412
|
# #=> ["a", ["b", "c"]]
|
414
413
|
def match(uri, processor=nil)
|
415
|
-
uri = Addressable::URI.parse(uri)
|
414
|
+
uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
|
416
415
|
mapping = {}
|
417
416
|
|
418
417
|
# First, we need to process the pattern, and extract the values.
|
@@ -653,50 +652,16 @@ module Addressable
|
|
653
652
|
self.to_regexp.named_captures
|
654
653
|
end
|
655
654
|
|
656
|
-
##
|
657
|
-
# Generates a route result for a given set of parameters.
|
658
|
-
# Should only be used by rack-mount.
|
659
|
-
#
|
660
|
-
# @param params [Hash] The set of parameters used to expand the template.
|
661
|
-
# @param recall [Hash] Default parameters used to expand the template.
|
662
|
-
# @param options [Hash] Either a `:processor` or a `:parameterize` block.
|
663
|
-
#
|
664
|
-
# @api private
|
665
|
-
def generate(params={}, recall={}, options={})
|
666
|
-
merged = recall.merge(params)
|
667
|
-
if options[:processor]
|
668
|
-
processor = options[:processor]
|
669
|
-
elsif options[:parameterize]
|
670
|
-
# TODO: This is sending me into fits trying to shoe-horn this into
|
671
|
-
# the existing API. I think I've got this backwards and processors
|
672
|
-
# should be a set of 4 optional blocks named :validate, :transform,
|
673
|
-
# :match, and :restore. Having to use a singleton here is a huge
|
674
|
-
# code smell.
|
675
|
-
processor = Object.new
|
676
|
-
class <<processor
|
677
|
-
attr_accessor :block
|
678
|
-
def transform(name, value)
|
679
|
-
block.call(name, value)
|
680
|
-
end
|
681
|
-
end
|
682
|
-
processor.block = options[:parameterize]
|
683
|
-
else
|
684
|
-
processor = nil
|
685
|
-
end
|
686
|
-
result = self.expand(merged, processor)
|
687
|
-
result.to_s if result
|
688
|
-
end
|
689
|
-
|
690
655
|
private
|
691
656
|
def ordered_variable_defaults
|
692
657
|
@ordered_variable_defaults ||= begin
|
693
658
|
expansions, _ = parse_template_pattern(pattern)
|
694
|
-
expansions.
|
659
|
+
expansions.flat_map do |capture|
|
695
660
|
_, _, varlist = *capture.match(EXPRESSION)
|
696
661
|
varlist.split(',').map do |varspec|
|
697
662
|
varspec[VARSPEC, 1]
|
698
663
|
end
|
699
|
-
end
|
664
|
+
end
|
700
665
|
end
|
701
666
|
end
|
702
667
|
|
@@ -927,25 +892,24 @@ module Addressable
|
|
927
892
|
# operator.
|
928
893
|
#
|
929
894
|
# @param [Hash, Array, String] value
|
930
|
-
# Normalizes keys and values with
|
895
|
+
# Normalizes unicode keys and values with String#unicode_normalize (NFC)
|
931
896
|
#
|
932
897
|
# @return [Hash, Array, String] The normalized values
|
933
898
|
def normalize_value(value)
|
934
|
-
unless value.is_a?(Hash)
|
935
|
-
value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str
|
936
|
-
end
|
937
|
-
|
938
899
|
# Handle unicode normalization
|
939
|
-
if value.
|
940
|
-
value.map! { |val|
|
900
|
+
if value.respond_to?(:to_ary)
|
901
|
+
value.to_ary.map! { |val| normalize_value(val) }
|
941
902
|
elsif value.kind_of?(Hash)
|
942
903
|
value = value.inject({}) { |acc, (k, v)|
|
943
|
-
acc[
|
944
|
-
Addressable::IDNA.unicode_normalize_kc(v)
|
904
|
+
acc[normalize_value(k)] = normalize_value(v)
|
945
905
|
acc
|
946
906
|
}
|
947
907
|
else
|
948
|
-
value =
|
908
|
+
value = value.to_s if !value.kind_of?(String)
|
909
|
+
if value.encoding != Encoding::UTF_8
|
910
|
+
value = value.dup.force_encoding(Encoding::UTF_8)
|
911
|
+
end
|
912
|
+
value = value.unicode_normalize(:nfc)
|
949
913
|
end
|
950
914
|
value
|
951
915
|
end
|
@@ -973,15 +937,35 @@ module Addressable
|
|
973
937
|
end
|
974
938
|
end
|
975
939
|
|
940
|
+
##
|
941
|
+
# Generates the <tt>Regexp</tt> that parses a template pattern. Memoizes the
|
942
|
+
# value if template processor not set (processors may not be deterministic)
|
943
|
+
#
|
944
|
+
# @param [String] pattern The URI template pattern.
|
945
|
+
# @param [#match] processor The template processor to use.
|
946
|
+
#
|
947
|
+
# @return [Array, Regexp]
|
948
|
+
# An array of expansion variables nad a regular expression which may be
|
949
|
+
# used to parse a template pattern
|
950
|
+
def parse_template_pattern(pattern, processor = nil)
|
951
|
+
if processor.nil? && pattern == @pattern
|
952
|
+
@cached_template_parse ||=
|
953
|
+
parse_new_template_pattern(pattern, processor)
|
954
|
+
else
|
955
|
+
parse_new_template_pattern(pattern, processor)
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
976
959
|
##
|
977
960
|
# Generates the <tt>Regexp</tt> that parses a template pattern.
|
978
961
|
#
|
979
962
|
# @param [String] pattern The URI template pattern.
|
980
963
|
# @param [#match] processor The template processor to use.
|
981
964
|
#
|
982
|
-
# @return [Regexp]
|
983
|
-
#
|
984
|
-
|
965
|
+
# @return [Array, Regexp]
|
966
|
+
# An array of expansion variables nad a regular expression which may be
|
967
|
+
# used to parse a template pattern
|
968
|
+
def parse_new_template_pattern(pattern, processor = nil)
|
985
969
|
# Escape the pattern. The two gsubs restore the escaped curly braces
|
986
970
|
# back to their original form. Basically, escape everything that isn't
|
987
971
|
# within an expansion.
|
@@ -1037,7 +1021,7 @@ module Addressable
|
|
1037
1021
|
end
|
1038
1022
|
|
1039
1023
|
# Ensure that the regular expression matches the whole URI.
|
1040
|
-
regexp_string = "
|
1024
|
+
regexp_string = "\\A#{regexp_string}\\z"
|
1041
1025
|
return expansions, Regexp.new(regexp_string)
|
1042
1026
|
end
|
1043
1027
|
|