Object
This is an implementation of a URI template based on URI">tinyurl.com/uritemplatedraft03">URI Template draft 03.
Creates a new Addressable::Template object.
@param [#] pattern The URI Template pattern.
@return [Addressable::Template] The initialized Template object.
# File lib/addressable/template.rb, line 129 129: def initialize(pattern) 130: if !pattern.respond_to?(:to_str) 131: raise TypeError, "Can't convert #{pattern.class} into String." 132: end 133: @pattern = pattern.to_str.freeze 134: end
Expands a URI template into a full URI.
@param [Hash] mapping The mapping that corresponds to the pattern. @param [#, #] processor
An optional processor object may be supplied.
The object should respond to either the validate or transform messages or both. Both the validate and transform methods should take two parameters: name and value. The validate method should return true or false; true if the value of the variable is valid, false otherwise. An InvalidTemplateValueError exception will be raised if the value is invalid. The transform method should return the transformed variable value as a String. If a transform method is used, the value will not be percent encoded automatically. Unicode normalization will be performed both before and after sending the value to the transform method.
@return [Addressable::URI] The expanded URI template.
@example
class ExampleProcessor def self.validate(name, value) return !!(value =~ /^[\w ]+$/) if name == "query" return true end def self.transform(name, value) return value.gsub(/ /, "+") if name == "query" return value end end Addressable::Template.new( "http://example.com/search/{query}/" ).expand( {"query" => "an example search query"}, ExampleProcessor ).to_str #=> "http://example.com/search/an+example+search+query/" Addressable::Template.new( "http://example.com/search/{-list|+|query}/" ).expand( {"query" => "an example search query".split(" ")} ).to_str #=> "http://example.com/search/an+example+search+query/" Addressable::Template.new( "http://example.com/search/{query}/" ).expand( {"query" => "bogus!"}, ExampleProcessor ).to_str #=> Addressable::Template::InvalidTemplateValueError
# File lib/addressable/template.rb, line 456 456: def expand(mapping, processor=nil) 457: result = self.pattern.dup 458: transformed_mapping = transform_mapping(mapping, processor) 459: result.gsub!( 460: /#{OPERATOR_EXPANSION}|#{VARIABLE_EXPANSION}/ 461: ) do |capture| 462: if capture =~ OPERATOR_EXPANSION 463: operator, argument, variables, default_mapping = 464: parse_template_expansion(capture, transformed_mapping) 465: expand_method = "expand_#{operator}_operator" 466: if ([expand_method, expand_method.to_sym] & private_methods).empty? 467: raise InvalidTemplateOperatorError, 468: "Invalid template operator: #{operator}" 469: else 470: send(expand_method.to_sym, argument, variables, default_mapping) 471: end 472: else 473: varname, _, vardefault = capture.scan(/^\{(.+?)(=(.*))?\}$/)[0] 474: transformed_mapping[varname] || vardefault 475: end 476: end 477: return Addressable::URI.parse(result) 478: end
Extracts a mapping from the URI using a URI Template pattern.
@param [Addressable::URI, #] uri
The URI to extract from.
@param [#, #] processor
A template processor object may optionally be supplied.
The object should respond to either the restore or match messages or both. The restore method should take two parameters: [String] name and [String] value. The restore method should reverse any transformations that have been performed on the value to ensure a valid URI. The match method should take a single parameter: [String] name. The match method should return a String containing a regular expression capture group for matching on that particular variable. The default value is “.*?”. The match method has no effect on multivariate operator expansions.
@return [Hash, NilClass] The Hash mapping that was extracted from the URI, or nil if the URI didn’t match the template.
@example
class ExampleProcessor def self.restore(name, value) return value.gsub(/\+/, " ") if name == "query" return value end def self.match(name) return ".*?" if name == "first" return ".*" end end uri = Addressable::URI.parse( "http://example.com/search/an+example+search+query/" ) Addressable::Template.new( "http://example.com/search/{query}/" ).extract(uri, ExampleProcessor) #=> {"query" => "an example search query"} uri = Addressable::URI.parse("http://example.com/a/b/c/") Addressable::Template.new( "http://example.com/{first}/{second}/" ).extract(uri, ExampleProcessor) #=> {"first" => "a", "second" => "b/c"} uri = Addressable::URI.parse("http://example.com/a/b/c/") Addressable::Template.new( "http://example.com/{first}/{-list|/|second}/" ).extract(uri) #=> {"first" => "a", "second" => ["b", "c"]}
# File lib/addressable/template.rb, line 204 204: def extract(uri, processor=nil) 205: match_data = self.match(uri, processor) 206: return (match_data ? match_data.mapping : nil) 207: end
Extracts match data from the URI using a URI Template pattern.
@param [Addressable::URI, #] uri
The URI to extract from.
@param [#, #] processor
A template processor object may optionally be supplied.
The object should respond to either the restore or match messages or both. The restore method should take two parameters: [String] name and [String] value. The restore method should reverse any transformations that have been performed on the value to ensure a valid URI. The match method should take a single parameter: [String] name. The match method should return a String containing a regular expression capture group for matching on that particular variable. The default value is “.*?”. The match method has no effect on multivariate operator expansions.
@return [Hash, NilClass] The Hash mapping that was extracted from the URI, or nil if the URI didn’t match the template.
@example
class ExampleProcessor def self.restore(name, value) return value.gsub(/\+/, " ") if name == "query" return value end def self.match(name) return ".*?" if name == "first" return ".*" end end uri = Addressable::URI.parse( "http://example.com/search/an+example+search+query/" ) match = Addressable::Template.new( "http://example.com/search/{query}/" ).match(uri, ExampleProcessor) match.variables #=> ["query"] match.captures #=> ["an example search query"] uri = Addressable::URI.parse("http://example.com/a/b/c/") match = Addressable::Template.new( "http://example.com/{first}/{second}/" ).match(uri, ExampleProcessor) match.variables #=> ["first", "second"] match.captures #=> ["a", "b/c"] uri = Addressable::URI.parse("http://example.com/a/b/c/") match = Addressable::Template.new( "http://example.com/{first}/{-list|/|second}/" ).match(uri) match.variables #=> ["first", "second"] match.captures #=> ["a", ["b", "c"]]
# File lib/addressable/template.rb, line 273 273: def match(uri, processor=nil) 274: uri = Addressable::URI.parse(uri) 275: mapping = {} 276: 277: # First, we need to process the pattern, and extract the values. 278: expansions, expansion_regexp = 279: parse_template_pattern(pattern, processor) 280: unparsed_values = uri.to_str.scan(expansion_regexp).flatten 281: 282: if uri.to_str == pattern 283: return Addressable::Template::MatchData.new(uri, self, mapping) 284: elsif expansions.size > 0 && expansions.size == unparsed_values.size 285: expansions.each_with_index do |expansion, index| 286: unparsed_value = unparsed_values[index] 287: if expansion =~ OPERATOR_EXPANSION 288: operator, argument, variables = 289: parse_template_expansion(expansion) 290: extract_method = "extract_#{operator}_operator" 291: if ([extract_method, extract_method.to_sym] & 292: private_methods).empty? 293: raise InvalidTemplateOperatorError, 294: "Invalid template operator: #{operator}" 295: else 296: begin 297: send( 298: extract_method.to_sym, unparsed_value, processor, 299: argument, variables, mapping 300: ) 301: rescue TemplateOperatorAbortedError 302: return nil 303: end 304: end 305: else 306: name = expansion[VARIABLE_EXPANSION, 1] 307: value = unparsed_value 308: if processor != nil && processor.respond_to?(:restore) 309: value = processor.restore(name, value) 310: end 311: if mapping[name] == nil || mapping[name] == value 312: mapping[name] = value 313: else 314: return nil 315: end 316: end 317: end 318: return Addressable::Template::MatchData.new(uri, self, mapping) 319: else 320: return nil 321: end 322: end
Expands a URI template into another URI template.
@param [Hash] mapping The mapping that corresponds to the pattern. @param [#, #] processor
An optional processor object may be supplied.
The object should respond to either the validate or transform messages or both. Both the validate and transform methods should take two parameters: name and value. The validate method should return true or false; true if the value of the variable is valid, false otherwise. An InvalidTemplateValueError exception will be raised if the value is invalid. The transform method should return the transformed variable value as a String. If a transform method is used, the value will not be percent encoded automatically. Unicode normalization will be performed both before and after sending the value to the transform method.
@return [Addressable::Template] The partially expanded URI template.
@example
Addressable::Template.new( "http://example.com/{one}/{two}/" ).partial_expand({"one" => "1"}).pattern #=> "http://example.com/1/{two}/" Addressable::Template.new( "http://example.com/search/{-list|+|query}/" ).partial_expand( {"query" => "an example search query".split(" ")} ).pattern #=> "http://example.com/search/an+example+search+query/" Addressable::Template.new( "http://example.com/{-join|&|one,two}/" ).partial_expand({"one" => "1"}).pattern #=> "http://example.com/?one=1{-prefix|&two=|two}" Addressable::Template.new( "http://example.com/{-join|&|one,two,three}/" ).partial_expand({"one" => "1", "three" => 3}).pattern #=> "http://example.com/?one=1{-prefix|&two=|two}&three=3"
# File lib/addressable/template.rb, line 367 367: def partial_expand(mapping, processor=nil) 368: result = self.pattern.dup 369: transformed_mapping = transform_mapping(mapping, processor) 370: result.gsub!( 371: /#{OPERATOR_EXPANSION}|#{VARIABLE_EXPANSION}/ 372: ) do |capture| 373: if capture =~ OPERATOR_EXPANSION 374: operator, argument, variables, default_mapping = 375: parse_template_expansion(capture, transformed_mapping) 376: expand_method = "expand_#{operator}_operator" 377: if ([expand_method, expand_method.to_sym] & private_methods).empty? 378: raise InvalidTemplateOperatorError, 379: "Invalid template operator: #{operator}" 380: else 381: send( 382: expand_method.to_sym, argument, variables, 383: default_mapping, true 384: ) 385: end 386: else 387: varname, _, vardefault = capture.scan(/^\{(.+?)(=(.*))?\}$/)[0] 388: if transformed_mapping[varname] 389: transformed_mapping[varname] 390: elsif vardefault 391: "{#{varname}=#{vardefault}}" 392: else 393: "{#{varname}}" 394: end 395: end 396: end 397: return Addressable::Template.new(result) 398: end
Returns a mapping of variables to their default values specified in the template. Variables without defaults are not returned.
@return [Hash] Mapping of template variables to their defaults
# File lib/addressable/template.rb, line 497 497: def variable_defaults 498: @variable_defaults ||= 499: Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] 500: end
Returns an Array of variables used within the template pattern. The variables are listed in the Array in the order they appear within the pattern. Multiple occurrences of a variable within a pattern are not represented in this Array.
@return [Array] The variables present in the template’s pattern.
# File lib/addressable/template.rb, line 487 487: def variables 488: @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq 489: end
Expands a URI Template join operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 710 710: def expand_join_operator(argument, variables, mapping, partial=false) 711: if !partial 712: variable_values = variables.inject([]) do |accu, variable| 713: if !mapping[variable].kind_of?(Array) 714: if mapping[variable] 715: accu << variable + "=" + (mapping[variable]) 716: end 717: else 718: raise InvalidTemplateOperatorError, 719: "Template operator 'join' does not accept Array values." 720: end 721: accu 722: end 723: variable_values.join(argument) 724: else 725: buffer = "" 726: state = :suffix 727: variables.each_with_index do |variable, index| 728: if !mapping[variable].kind_of?(Array) 729: if mapping[variable] 730: if buffer.empty? || buffer[1..1] == "}" 731: buffer << (variable + "=" + (mapping[variable])) 732: elsif state == :suffix 733: buffer << argument 734: buffer << (variable + "=" + (mapping[variable])) 735: else 736: buffer << (variable + "=" + (mapping[variable])) 737: end 738: else 739: if !buffer.empty? && (buffer[1..1] != "}" || state == :prefix) 740: buffer << "{-opt|#{argument}|#{variable}}" 741: state = :prefix 742: end 743: if buffer.empty? && variables.size == 1 744: # Evaluates back to itself 745: buffer << "{-join|#{argument}|#{variable}}" 746: else 747: buffer << "{-prefix|#{variable}=|#{variable}}" 748: end 749: if (index != (variables.size - 1) && state == :suffix) 750: buffer << "{-opt|#{argument}|#{variable}}" 751: elsif index != (variables.size - 1) && 752: mapping[variables[index + 1]] 753: buffer << argument 754: state = :prefix 755: end 756: end 757: else 758: raise InvalidTemplateOperatorError, 759: "Template operator 'join' does not accept Array values." 760: end 761: end 762: buffer 763: end 764: end
Expands a URI Template list operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 774 774: def expand_list_operator(argument, variables, mapping, partial=false) 775: if variables.size != 1 776: raise InvalidTemplateOperatorError, 777: "Template operator 'list' takes exactly one variable." 778: end 779: if !partial || mapping[variables.first] 780: values = mapping[variables.first] 781: if values 782: if values.kind_of?(Array) 783: values.join(argument) 784: else 785: raise InvalidTemplateOperatorError, 786: "Template operator 'list' only accepts Array values." 787: end 788: end 789: else 790: "{-list|#{argument}|#{variables.first}}" 791: end 792: end
Expands a URI Template neg operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 638 638: def expand_neg_operator(argument, variables, mapping, partial=false) 639: variables_present = variables.any? do |variable| 640: mapping[variable] != [] && 641: mapping[variable] 642: end 643: if partial && !variables_present 644: "{-neg|#{argument}|#{variables.join(",")}}" 645: elsif variables_present 646: "" 647: else 648: argument 649: end 650: end
Expands a URI Template opt operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 616 616: def expand_opt_operator(argument, variables, mapping, partial=false) 617: variables_present = variables.any? do |variable| 618: mapping[variable] != [] && 619: mapping[variable] 620: end 621: if partial && !variables_present 622: "{-opt|#{argument}|#{variables.join(",")}}" 623: elsif variables_present 624: argument 625: else 626: "" 627: end 628: end
Expands a URI Template prefix operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 660 660: def expand_prefix_operator(argument, variables, mapping, partial=false) 661: if variables.size != 1 662: raise InvalidTemplateOperatorError, 663: "Template operator 'prefix' takes exactly one variable." 664: end 665: value = mapping[variables.first] 666: if !partial || value 667: if value.kind_of?(Array) 668: (value.map { |list_value| argument + list_value }).join("") 669: elsif value 670: argument + value.to_s 671: end 672: else 673: "{-prefix|#{argument}|#{variables.first}}" 674: end 675: end
Expands a URI Template suffix operator.
@param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The expanded result.
# File lib/addressable/template.rb, line 685 685: def expand_suffix_operator(argument, variables, mapping, partial=false) 686: if variables.size != 1 687: raise InvalidTemplateOperatorError, 688: "Template operator 'suffix' takes exactly one variable." 689: end 690: value = mapping[variables.first] 691: if !partial || value 692: if value.kind_of?(Array) 693: (value.map { |list_value| list_value + argument }).join("") 694: elsif value 695: value.to_s + argument 696: end 697: else 698: "{-suffix|#{argument}|#{variables.first}}" 699: end 700: end
Extracts a URI Template join operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 991 991: def extract_join_operator(value, processor, argument, variables, mapping) 992: unparsed_values = value.split(argument) 993: parsed_variables = [] 994: for unparsed_value in unparsed_values 995: name = unparsed_value[/^(.+?)=(.+)$/, 1] 996: parsed_variables << name 997: parsed_value = unparsed_value[/^(.+?)=(.+)$/, 2] 998: if processor && processor.respond_to?(:restore) 999: parsed_value = processor.restore(name, parsed_value) 1000: end 1001: if mapping[name] == nil || mapping[name] == parsed_value 1002: mapping[name] = parsed_value 1003: else 1004: raise TemplateOperatorAbortedError, 1005: "Value mismatch for repeated variable." 1006: end 1007: end 1008: for variable in variables 1009: if !parsed_variables.include?(variable) && mapping[variable] != nil 1010: raise TemplateOperatorAbortedError, 1011: "Value mismatch for repeated variable." 1012: end 1013: end 1014: if (parsed_variables & variables) != parsed_variables 1015: raise TemplateOperatorAbortedError, 1016: "Template operator 'join' variable mismatch: " + 1017: "#{parsed_variables.inspect}, #{variables.inspect}" 1018: end 1019: end
Extracts a URI Template list operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 1031 1031: def extract_list_operator(value, processor, argument, variables, mapping) 1032: if variables.size != 1 1033: raise InvalidTemplateOperatorError, 1034: "Template operator 'list' takes exactly one variable." 1035: end 1036: values = value.split(argument, 1) 1037: values.pop if values[1] == "" 1038: if processor && processor.respond_to?(:restore) 1039: values.map! { |value| processor.restore(variables.first, value) } 1040: end 1041: if mapping[variables.first] == nil || mapping[variables.first] == values 1042: mapping[variables.first] = values 1043: else 1044: raise TemplateOperatorAbortedError, 1045: "Value mismatch for repeated variable." 1046: end 1047: end
Extracts a URI Template neg operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 902 902: def extract_neg_operator( 903: value, processor, argument, variables, mapping) 904: if value != "" && value != argument 905: raise TemplateOperatorAbortedError, 906: "Value for template operator 'neg' was unexpected." 907: end 908: end
Extracts a URI Template opt operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 884 884: def extract_opt_operator( 885: value, processor, argument, variables, mapping) 886: if value != "" && value != argument 887: raise TemplateOperatorAbortedError, 888: "Value for template operator 'opt' was unexpected." 889: end 890: end
Extracts a URI Template prefix operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 920 920: def extract_prefix_operator( 921: value, processor, argument, variables, mapping) 922: if variables.size != 1 923: raise InvalidTemplateOperatorError, 924: "Template operator 'prefix' takes exactly one variable." 925: end 926: if value[0...argument.size] != argument 927: raise TemplateOperatorAbortedError, 928: "Value for template operator 'prefix' missing expected prefix." 929: end 930: values = value.split(argument, 1) 931: values << "" if value[-argument.size..1] == argument 932: values.shift if values[0] == "" 933: values.pop if values[1] == "" 934: 935: if processor && processor.respond_to?(:restore) 936: values.map! { |value| processor.restore(variables.first, value) } 937: end 938: values = values.first if values.size == 1 939: if mapping[variables.first] == nil || mapping[variables.first] == values 940: mapping[variables.first] = values 941: else 942: raise TemplateOperatorAbortedError, 943: "Value mismatch for repeated variable." 944: end 945: end
Extracts a URI Template suffix operator.
@param [String] value The unparsed value to extract from. @param [#] processor The processor object. @param [String] argument The argument to the operator. @param [Array] variables The variables the operator is working on. @param [Hash] mapping The mapping of variables to values.
@return [String] The extracted result.
# File lib/addressable/template.rb, line 957 957: def extract_suffix_operator( 958: value, processor, argument, variables, mapping) 959: if variables.size != 1 960: raise InvalidTemplateOperatorError, 961: "Template operator 'suffix' takes exactly one variable." 962: end 963: if value[-argument.size..1] != argument 964: raise TemplateOperatorAbortedError, 965: "Value for template operator 'suffix' missing expected suffix." 966: end 967: values = value.split(argument, 1) 968: values.pop if values[1] == "" 969: if processor && processor.respond_to?(:restore) 970: values.map! { |value| processor.restore(variables.first, value) } 971: end 972: values = values.first if values.size == 1 973: if mapping[variables.first] == nil || mapping[variables.first] == values 974: mapping[variables.first] = values 975: else 976: raise TemplateOperatorAbortedError, 977: "Value mismatch for repeated variable." 978: end 979: end
# File lib/addressable/template.rb, line 503 503: def ordered_variable_defaults 504: @ordered_variable_defaults ||= (begin 505: expansions, expansion_regexp = parse_template_pattern(pattern) 506: 507: expansions.inject([]) do |result, expansion| 508: case expansion 509: when OPERATOR_EXPANSION 510: _, _, variables, mapping = parse_template_expansion(expansion) 511: result.concat variables.map { |var| [var, mapping[var]] } 512: when VARIABLE_EXPANSION 513: result << [$1, $2] 514: end 515: result 516: end 517: end) 518: end
Parses a URI template expansion String.
@param [String] expansion The operator String. @param [Hash] mapping An optional mapping to merge defaults into.
@return [Array]
A tuple of the operator, argument, variables, and mapping.
# File lib/addressable/template.rb, line 802 802: def parse_template_expansion(capture, mapping={}) 803: operator, argument, variables = capture[1...1].split("|", 1) 804: operator.gsub!(/^\-/, "") 805: variables = variables.split(",", 1) 806: mapping = (variables.inject({}) do |accu, var| 807: varname, _, vardefault = var.scan(/^(.+?)(=(.*))?$/)[0] 808: accu[varname] = vardefault 809: accu 810: end).merge(mapping) 811: variables = variables.map { |var| var.gsub(/=.*$/, "") } 812: return operator, argument, variables, mapping 813: end
Generates the Regexp that parses a template pattern.
@param [String] pattern The URI template pattern. @param [#] processor The template processor to use.
@return [Regexp]
A regular expression which may be used to parse a template pattern.
# File lib/addressable/template.rb, line 823 823: def parse_template_pattern(pattern, processor=nil) 824: # Escape the pattern. The two gsubs restore the escaped curly braces 825: # back to their original form. Basically, escape everything that isn't 826: # within an expansion. 827: escaped_pattern = Regexp.escape( 828: pattern 829: ).gsub(/\\\{(.*?)\\\}/) do |escaped| 830: escaped.gsub(/\\(.)/, "\\1") 831: end 832: 833: expansions = [] 834: 835: # Create a regular expression that captures the values of the 836: # variables in the URI. 837: regexp_string = escaped_pattern.gsub( 838: /#{OPERATOR_EXPANSION}|#{VARIABLE_EXPANSION}/ 839: ) do |expansion| 840: expansions << expansion 841: if expansion =~ OPERATOR_EXPANSION 842: capture_group = "(.*)" 843: operator, argument, names, _ = 844: parse_template_expansion(expansion) 845: if processor != nil && processor.respond_to?(:match) 846: # We can only lookup the match values for single variable 847: # operator expansions. Besides, ".*" is usually the only 848: # reasonable value for multivariate operators anyways. 849: if ["prefix", "suffix", "list"].include?(operator) 850: capture_group = "(#{processor.match(names.first)})" 851: end 852: elsif operator == "prefix" 853: capture_group = "(#{Regexp.escape(argument)}.*?)" 854: elsif operator == "suffix" 855: capture_group = "(.*?#{Regexp.escape(argument)})" 856: end 857: capture_group 858: else 859: capture_group = "(.*?)" 860: if processor != nil && processor.respond_to?(:match) 861: name = expansion[/\{([^\}=]+)(=[^\}]+)?\}/, 1] 862: capture_group = "(#{processor.match(name)})" 863: end 864: capture_group 865: end 866: end 867: 868: # Ensure that the regular expression matches the whole URI. 869: regexp_string = "^#{regexp_string}$" 870: 871: return expansions, Regexp.new(regexp_string) 872: end
Transforms a mapping so that values can be substituted into the template.
@param [Hash] mapping The mapping of variables to values. @param [#, #] processor
An optional processor object may be supplied.
The object should respond to either the validate or transform messages or both. Both the validate and transform methods should take two parameters: name and value. The validate method should return true or false; true if the value of the variable is valid, false otherwise. An InvalidTemplateValueError exception will be raised if the value is invalid. The transform method should return the transformed variable value as a String. If a transform method is used, the value will not be percent encoded automatically. Unicode normalization will be performed both before and after sending the value to the transform method.
@return [Hash] The transformed mapping.
# File lib/addressable/template.rb, line 541 541: def transform_mapping(mapping, processor=nil) 542: return mapping.inject({}) do |accu, pair| 543: name, value = pair 544: value = value.to_s if Numeric === value || Symbol === value 545: 546: unless value.respond_to?(:to_ary) || value.respond_to?(:to_str) 547: raise TypeError, 548: "Can't convert #{value.class} into String or Array." 549: end 550: 551: if Symbol === name 552: name = name.to_s 553: elsif name.respond_to?(:to_str) 554: name = name.to_str 555: else 556: raise TypeError, 557: "Can't convert #{name.class} into String." 558: end 559: value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str 560: 561: # Handle unicode normalization 562: if value.kind_of?(Array) 563: value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) } 564: else 565: value = Addressable::IDNA.unicode_normalize_kc(value) 566: end 567: 568: if processor == nil || !processor.respond_to?(:transform) 569: # Handle percent escaping 570: if value.kind_of?(Array) 571: transformed_value = value.map do |val| 572: Addressable::URI.encode_component( 573: val, Addressable::URI::CharacterClasses::UNRESERVED) 574: end 575: else 576: transformed_value = Addressable::URI.encode_component( 577: value, Addressable::URI::CharacterClasses::UNRESERVED) 578: end 579: end 580: 581: # Process, if we've got a processor 582: if processor != nil 583: if processor.respond_to?(:validate) 584: if !processor.validate(name, value) 585: display_value = value.kind_of?(Array) ? value.inspect : value 586: raise InvalidTemplateValueError, 587: "#{name}=#{display_value} is an invalid template value." 588: end 589: end 590: if processor.respond_to?(:transform) 591: transformed_value = processor.transform(name, value) 592: if transformed_value.kind_of?(Array) 593: transformed_value.map! do |val| 594: Addressable::IDNA.unicode_normalize_kc(val) 595: end 596: else 597: transformed_value = 598: Addressable::IDNA.unicode_normalize_kc(transformed_value) 599: end 600: end 601: end 602: 603: accu[name] = transformed_value 604: accu 605: end 606: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.