addressable 2.4.0 → 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.
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # encoding:utf-8
2
4
  #--
3
- # Copyright (C) 2006-2015 Bob Aman
5
+ # Copyright (C) Bob Aman
4
6
  #
5
7
  # Licensed under the Apache License, Version 2.0 (the "License");
6
8
  # you may not use this file except in compliance with the License.
@@ -35,7 +37,7 @@ module Addressable
35
37
  Addressable::URI::CharacterClasses::DIGIT + '_'
36
38
 
37
39
  var_char =
38
- "(?:(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
40
+ "(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
39
41
  RESERVED =
40
42
  "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
41
43
  UNRESERVED =
@@ -410,7 +412,7 @@ module Addressable
410
412
  # match.captures
411
413
  # #=> ["a", ["b", "c"]]
412
414
  def match(uri, processor=nil)
413
- uri = Addressable::URI.parse(uri)
415
+ uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
414
416
  mapping = {}
415
417
 
416
418
  # First, we need to process the pattern, and extract the values.
@@ -488,6 +490,8 @@ module Addressable
488
490
  # @param [Hash] mapping The mapping that corresponds to the pattern.
489
491
  # @param [#validate, #transform] processor
490
492
  # An optional processor object may be supplied.
493
+ # @param [Boolean] normalize_values
494
+ # Optional flag to enable/disable unicode normalization. Default: true
491
495
  #
492
496
  # The object should respond to either the <tt>validate</tt> or
493
497
  # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
@@ -518,11 +522,11 @@ module Addressable
518
522
  # "http://example.com/{?one,two,three}/"
519
523
  # ).partial_expand({"one" => "1", "three" => 3}).pattern
520
524
  # #=> "http://example.com/?one=1{&two}&three=3"
521
- def partial_expand(mapping, processor=nil)
525
+ def partial_expand(mapping, processor=nil, normalize_values=true)
522
526
  result = self.pattern.dup
523
527
  mapping = normalize_keys(mapping)
524
528
  result.gsub!( EXPRESSION ) do |capture|
525
- transform_partial_capture(mapping, capture, processor)
529
+ transform_partial_capture(mapping, capture, processor, normalize_values)
526
530
  end
527
531
  return Addressable::Template.new(result)
528
532
  end
@@ -533,6 +537,8 @@ module Addressable
533
537
  # @param [Hash] mapping The mapping that corresponds to the pattern.
534
538
  # @param [#validate, #transform] processor
535
539
  # An optional processor object may be supplied.
540
+ # @param [Boolean] normalize_values
541
+ # Optional flag to enable/disable unicode normalization. Default: true
536
542
  #
537
543
  # The object should respond to either the <tt>validate</tt> or
538
544
  # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
@@ -583,11 +589,11 @@ module Addressable
583
589
  # ExampleProcessor
584
590
  # ).to_str
585
591
  # #=> Addressable::Template::InvalidTemplateValueError
586
- def expand(mapping, processor=nil)
592
+ def expand(mapping, processor=nil, normalize_values=true)
587
593
  result = self.pattern.dup
588
594
  mapping = normalize_keys(mapping)
589
595
  result.gsub!( EXPRESSION ) do |capture|
590
- transform_capture(mapping, capture, processor)
596
+ transform_capture(mapping, capture, processor, normalize_values)
591
597
  end
592
598
  return Addressable::URI.parse(result)
593
599
  end
@@ -647,40 +653,6 @@ module Addressable
647
653
  self.to_regexp.named_captures
648
654
  end
649
655
 
650
- ##
651
- # Generates a route result for a given set of parameters.
652
- # Should only be used by rack-mount.
653
- #
654
- # @param params [Hash] The set of parameters used to expand the template.
655
- # @param recall [Hash] Default parameters used to expand the template.
656
- # @param options [Hash] Either a `:processor` or a `:parameterize` block.
657
- #
658
- # @api private
659
- def generate(params={}, recall={}, options={})
660
- merged = recall.merge(params)
661
- if options[:processor]
662
- processor = options[:processor]
663
- elsif options[:parameterize]
664
- # TODO: This is sending me into fits trying to shoe-horn this into
665
- # the existing API. I think I've got this backwards and processors
666
- # should be a set of 4 optional blocks named :validate, :transform,
667
- # :match, and :restore. Having to use a singleton here is a huge
668
- # code smell.
669
- processor = Object.new
670
- class <<processor
671
- attr_accessor :block
672
- def transform(name, value)
673
- block.call(name, value)
674
- end
675
- end
676
- processor.block = options[:parameterize]
677
- else
678
- processor = nil
679
- end
680
- result = self.expand(merged, processor)
681
- result.to_s if result
682
- end
683
-
684
656
  private
685
657
  def ordered_variable_defaults
686
658
  @ordered_variable_defaults ||= begin
@@ -704,6 +676,8 @@ module Addressable
704
676
  # The expression to expand
705
677
  # @param [#validate, #transform] processor
706
678
  # An optional processor object may be supplied.
679
+ # @param [Boolean] normalize_values
680
+ # Optional flag to enable/disable unicode normalization. Default: true
707
681
  #
708
682
  # The object should respond to either the <tt>validate</tt> or
709
683
  # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
@@ -718,56 +692,36 @@ module Addressable
718
692
  # after sending the value to the transform method.
719
693
  #
720
694
  # @return [String] The expanded expression
721
- def transform_partial_capture(mapping, capture, processor = nil)
695
+ def transform_partial_capture(mapping, capture, processor = nil,
696
+ normalize_values = true)
722
697
  _, operator, varlist = *capture.match(EXPRESSION)
723
698
 
724
- vars = varlist.split(',')
699
+ vars = varlist.split(",")
725
700
 
726
- if '?' == operator
701
+ if operator == "?"
727
702
  # partial expansion of form style query variables sometimes requires a
728
703
  # slight reordering of the variables to produce a valid url.
729
704
  first_to_expand = vars.find { |varspec|
730
705
  _, name, _ = *varspec.match(VARSPEC)
731
- mapping.key? name
706
+ mapping.key?(name) && !mapping[name].nil?
732
707
  }
733
708
 
734
709
  vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand
735
710
  end
736
711
 
737
- vars
738
- .zip(operator_sequence(operator).take(vars.length))
739
- .reduce("") do |acc, (varspec, op)|
712
+ vars.
713
+ inject("".dup) do |acc, varspec|
740
714
  _, name, _ = *varspec.match(VARSPEC)
741
-
742
- acc << if mapping.key? name
743
- transform_capture(mapping, "{#{op}#{varspec}}", processor)
744
- else
745
- "{#{op}#{varspec}}"
746
- end
747
- end
748
- end
749
-
750
- ##
751
- # Creates a lazy Enumerator of the operators that should be used to expand
752
- # variables in a varlist starting with `operator`. For example, an operator
753
- # `"?"` results in the sequence `"?","&","&"...`
754
- #
755
- # @param [String] operator from which to generate a sequence
756
- #
757
- # @return [Enumerator] sequence of operators
758
- def operator_sequence(operator)
759
- rest_operator = if "?" == operator
760
- "&"
761
- else
762
- operator
763
- end
764
- head_operator = operator
765
-
766
- Enumerator.new do |y|
767
- y << head_operator.to_s
768
- while true
769
- y << rest_operator.to_s
770
- end
715
+ next_val = if mapping.key? name
716
+ transform_capture(mapping, "{#{operator}#{varspec}}",
717
+ processor, normalize_values)
718
+ else
719
+ "{#{operator}#{varspec}}"
720
+ end
721
+ # If we've already expanded at least one '?' operator with non-empty
722
+ # value, change to '&'
723
+ operator = "&" if (operator == "?") && (next_val != "")
724
+ acc << next_val
771
725
  end
772
726
  end
773
727
 
@@ -780,6 +734,9 @@ module Addressable
780
734
  # The expression to replace
781
735
  # @param [#validate, #transform] processor
782
736
  # An optional processor object may be supplied.
737
+ # @param [Boolean] normalize_values
738
+ # Optional flag to enable/disable unicode normalization. Default: true
739
+ #
783
740
  #
784
741
  # The object should respond to either the <tt>validate</tt> or
785
742
  # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
@@ -794,7 +751,8 @@ module Addressable
794
751
  # after sending the value to the transform method.
795
752
  #
796
753
  # @return [String] The expanded expression
797
- def transform_capture(mapping, capture, processor=nil)
754
+ def transform_capture(mapping, capture, processor=nil,
755
+ normalize_values=true)
798
756
  _, operator, varlist = *capture.match(EXPRESSION)
799
757
  return_value = varlist.split(',').inject([]) do |acc, varspec|
800
758
  _, name, modifier = *varspec.match(VARSPEC)
@@ -814,7 +772,7 @@ module Addressable
814
772
  "Can't convert #{value.class} into String or Array."
815
773
  end
816
774
 
817
- value = normalize_value(value)
775
+ value = normalize_value(value) if normalize_values
818
776
 
819
777
  if processor == nil || !processor.respond_to?(:transform)
820
778
  # Handle percent escaping
@@ -877,7 +835,9 @@ module Addressable
877
835
  end
878
836
  if processor.respond_to?(:transform)
879
837
  transformed_value = processor.transform(name, value)
880
- transformed_value = normalize_value(transformed_value)
838
+ if normalize_values
839
+ transformed_value = normalize_value(transformed_value)
840
+ end
881
841
  end
882
842
  end
883
843
  acc << [name, transformed_value]
@@ -979,15 +939,35 @@ module Addressable
979
939
  end
980
940
  end
981
941
 
942
+ ##
943
+ # Generates the <tt>Regexp</tt> that parses a template pattern. Memoizes the
944
+ # value if template processor not set (processors may not be deterministic)
945
+ #
946
+ # @param [String] pattern The URI template pattern.
947
+ # @param [#match] processor The template processor to use.
948
+ #
949
+ # @return [Array, Regexp]
950
+ # An array of expansion variables nad a regular expression which may be
951
+ # used to parse a template pattern
952
+ def parse_template_pattern(pattern, processor = nil)
953
+ if processor.nil? && pattern == @pattern
954
+ @cached_template_parse ||=
955
+ parse_new_template_pattern(pattern, processor)
956
+ else
957
+ parse_new_template_pattern(pattern, processor)
958
+ end
959
+ end
960
+
982
961
  ##
983
962
  # Generates the <tt>Regexp</tt> that parses a template pattern.
984
963
  #
985
964
  # @param [String] pattern The URI template pattern.
986
965
  # @param [#match] processor The template processor to use.
987
966
  #
988
- # @return [Regexp]
989
- # A regular expression which may be used to parse a template pattern.
990
- def parse_template_pattern(pattern, processor=nil)
967
+ # @return [Array, Regexp]
968
+ # An array of expansion variables nad a regular expression which may be
969
+ # used to parse a template pattern
970
+ def parse_new_template_pattern(pattern, processor = nil)
991
971
  # Escape the pattern. The two gsubs restore the escaped curly braces
992
972
  # back to their original form. Basically, escape everything that isn't
993
973
  # within an expansion.