uri_template 0.0.2 → 0.1.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.
- data/CHANGELOG +6 -0
 - data/lib/uri_template.rb +10 -35
 - data/lib/uri_template/colon.rb +0 -0
 - data/lib/uri_template/draft2.rb +0 -0
 - data/lib/uri_template/draft7.rb +211 -184
 - data/uri_template.gemspec +3 -3
 - metadata +10 -9
 
    
        data/CHANGELOG
    CHANGED
    
    | 
         @@ -1,3 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # 0.1.0 -  2.11.2011
         
     | 
| 
      
 2 
     | 
    
         
            +
            - Removed Sections. They made too many headaches.
         
     | 
| 
      
 3 
     | 
    
         
            +
            + Made draft7 template concatenateable. This should replace sections.
         
     | 
| 
      
 4 
     | 
    
         
            +
            * BUGFIX: multiline uris were matched
         
     | 
| 
      
 5 
     | 
    
         
            +
            * BUGFIX: variablenames were decoded when this was not appreciated
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       1 
7 
     | 
    
         
             
            # 0.0.2 -  1.11.2011
         
     | 
| 
       2 
8 
     | 
    
         
             
            * BUGFIX: Concatenating empty sections no more leads to catch-all templates, when an emtpy template was appreciated.
         
     | 
| 
       3 
9 
     | 
    
         
             
            + The extracted variables now contains the keys :suffix and :prefix if the match didn't consume the whole uri.
         
     | 
    
        data/lib/uri_template.rb
    CHANGED
    
    | 
         @@ -18,6 +18,7 @@ 
     | 
|
| 
       18 
18 
     | 
    
         
             
            # A base module for all implementations of a uri template.
         
     | 
| 
       19 
19 
     | 
    
         
             
            module URITemplate
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
      
 21 
     | 
    
         
            +
              autoload :Utils, 'uri_template/utils'
         
     | 
| 
       21 
22 
     | 
    
         
             
              autoload :Draft7, 'uri_template/draft7'
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
              # A hash with all available implementations.
         
     | 
| 
         @@ -39,6 +40,7 @@ module URITemplate 
     | 
|
| 
       39 
40 
     | 
    
         
             
              #   URITemplate.resolve_class("template",:draft7) #=> [ URITemplate::Draft7, ["template"] ]
         
     | 
| 
       40 
41 
     | 
    
         
             
              # 
         
     | 
| 
       41 
42 
     | 
    
         
             
              # @raise ArgumentError when no class was found.
         
     | 
| 
      
 43 
     | 
    
         
            +
              #
         
     | 
| 
       42 
44 
     | 
    
         
             
              def self.resolve_class(*args)
         
     | 
| 
       43 
45 
     | 
    
         
             
                symbols, rest = args.partition{|x| x.kind_of? Symbol }
         
     | 
| 
       44 
46 
     | 
    
         
             
                version = symbols.fetch(0, :default)
         
     | 
| 
         @@ -66,45 +68,18 @@ module URITemplate 
     | 
|
| 
       66 
68 
     | 
    
         
             
              module Invalid
         
     | 
| 
       67 
69 
     | 
    
         
             
              end
         
     | 
| 
       68 
70 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
              # A base module for all implementation of a template section.
         
     | 
| 
       70 
     | 
    
         
            -
              # Sections are a custom extension to the uri template spec.
         
     | 
| 
       71 
     | 
    
         
            -
              # A template section ( in comparison to a template ) can be unbounded on its ends. Therefore they don't necessarily match a whole uri and can be concatenated.
         
     | 
| 
       72 
     | 
    
         
            -
              module Section
         
     | 
| 
       73 
     | 
    
         
            -
              
         
     | 
| 
       74 
     | 
    
         
            -
                include URITemplate
         
     | 
| 
       75 
     | 
    
         
            -
              
         
     | 
| 
       76 
     | 
    
         
            -
                # Same as {URITemplate.new} but for sections
         
     | 
| 
       77 
     | 
    
         
            -
                def self.new(*args)
         
     | 
| 
       78 
     | 
    
         
            -
                  klass, rest = URITemplate.resolve_class(*args)
         
     | 
| 
       79 
     | 
    
         
            -
                  return klass::Section.new(*rest)
         
     | 
| 
       80 
     | 
    
         
            -
                end
         
     | 
| 
       81 
     | 
    
         
            -
                
         
     | 
| 
       82 
     | 
    
         
            -
                # @abstract
         
     | 
| 
       83 
     | 
    
         
            -
                # Concatenates this section with an other section.
         
     | 
| 
       84 
     | 
    
         
            -
                def >>(other)
         
     | 
| 
       85 
     | 
    
         
            -
                  raise "Please implement #>> on #{self.class.inspect}"
         
     | 
| 
       86 
     | 
    
         
            -
                end
         
     | 
| 
       87 
     | 
    
         
            -
                
         
     | 
| 
       88 
     | 
    
         
            -
                # @abstract
         
     | 
| 
       89 
     | 
    
         
            -
                # Is this section left bounded?
         
     | 
| 
       90 
     | 
    
         
            -
                def left_bound?
         
     | 
| 
       91 
     | 
    
         
            -
                  raise "Please implement #left_bound? on #{self.class.inspect}"
         
     | 
| 
       92 
     | 
    
         
            -
                end
         
     | 
| 
       93 
     | 
    
         
            -
              
         
     | 
| 
       94 
     | 
    
         
            -
                # @abstract
         
     | 
| 
       95 
     | 
    
         
            -
                # Is this section right bounded?
         
     | 
| 
       96 
     | 
    
         
            -
                def right_bound?
         
     | 
| 
       97 
     | 
    
         
            -
                  raise "Please implement #right_bound? on #{self.class.inspect}"
         
     | 
| 
       98 
     | 
    
         
            -
                end
         
     | 
| 
       99 
     | 
    
         
            -
              
         
     | 
| 
       100 
     | 
    
         
            -
              end
         
     | 
| 
       101 
     | 
    
         
            -
              
         
     | 
| 
       102 
71 
     | 
    
         
             
              # @abstract
         
     | 
| 
       103 
72 
     | 
    
         
             
              # Expands this uri template with the given variables.
         
     | 
| 
       104 
73 
     | 
    
         
             
              # The variables should be converted to strings using {Utils#object_to_param}.
         
     | 
| 
       105 
     | 
    
         
            -
              # @raise Unconvertable if a variable could not be converted.
         
     | 
| 
      
 74 
     | 
    
         
            +
              # @raise {Unconvertable} if a variable could not be converted to a string.
         
     | 
| 
       106 
75 
     | 
    
         
             
              def expand(variables={})
         
     | 
| 
       107 
     | 
    
         
            -
                raise "Please implement #expand on #{self.class.inspect}"
         
     | 
| 
      
 76 
     | 
    
         
            +
                raise "Please implement #expand on #{self.class.inspect}."
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
              
         
     | 
| 
      
 79 
     | 
    
         
            +
              # @abstract
         
     | 
| 
      
 80 
     | 
    
         
            +
              # Returns the type of this template. The type is a symbol which can be used in {.resolve_class} to resolve the type of this template.
         
     | 
| 
      
 81 
     | 
    
         
            +
              def type
         
     | 
| 
      
 82 
     | 
    
         
            +
                raise "Please implement #type on #{self.class.inspect}."
         
     | 
| 
       108 
83 
     | 
    
         
             
              end
         
     | 
| 
       109 
84 
     | 
    
         | 
| 
       110 
85 
     | 
    
         
             
            end
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
    
        data/lib/uri_template/draft7.rb
    CHANGED
    
    | 
         @@ -34,7 +34,7 @@ class URITemplate::Draft7 
     | 
|
| 
       34 
34 
     | 
    
         
             
              Utils = URITemplate::Utils
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
              # @private
         
     | 
| 
       37 
     | 
    
         
            -
              LITERAL = /^([^"'%<>\\^`{|}\s]|%\h\h)+/
         
     | 
| 
      
 37 
     | 
    
         
            +
              LITERAL = /^([^"'%<>\\^`{|}\s\p{Cc}]|%\h\h)+/
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
              # @private
         
     | 
| 
       40 
40 
     | 
    
         
             
              CHARACTER_CLASSES = {
         
     | 
| 
         @@ -60,19 +60,19 @@ class URITemplate::Draft7 
     | 
|
| 
       60 
60 
     | 
    
         
             
              }
         
     | 
| 
       61 
61 
     | 
    
         | 
| 
       62 
62 
     | 
    
         
             
              # Specifies that no processing should be done upon extraction.
         
     | 
| 
       63 
     | 
    
         
            -
              # @see extract
         
     | 
| 
      
 63 
     | 
    
         
            +
              # @see #extract
         
     | 
| 
       64 
64 
     | 
    
         
             
              NO_PROCESSING = []
         
     | 
| 
       65 
65 
     | 
    
         | 
| 
       66 
66 
     | 
    
         
             
              # Specifies that the extracted values should be processed.
         
     | 
| 
       67 
     | 
    
         
            -
              # @see extract
         
     | 
| 
      
 67 
     | 
    
         
            +
              # @see #extract
         
     | 
| 
       68 
68 
     | 
    
         
             
              CONVERT_VALUES = [:convert_values]
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
              # Specifies that the extracted variable list should be processed.
         
     | 
| 
       71 
     | 
    
         
            -
              # @see extract
         
     | 
| 
      
 71 
     | 
    
         
            +
              # @see #extract
         
     | 
| 
       72 
72 
     | 
    
         
             
              CONVERT_RESULT = [:convert_result]
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
       74 
74 
     | 
    
         
             
              # Default processing. Means: convert values and the list itself.
         
     | 
| 
       75 
     | 
    
         
            -
              # @see extract
         
     | 
| 
      
 75 
     | 
    
         
            +
              # @see #extract
         
     | 
| 
       76 
76 
     | 
    
         
             
              DEFAULT_PROCESSING = CONVERT_VALUES + CONVERT_RESULT
         
     | 
| 
       77 
77 
     | 
    
         | 
| 
       78 
78 
     | 
    
         
             
              # @private
         
     | 
| 
         @@ -99,11 +99,15 @@ __REGEXP__ 
     | 
|
| 
       99 
99 
     | 
    
         
             
            (?<varchar> [a-zA-Z_]|%[0-9a-fA-F]{2}){0}
         
     | 
| 
       100 
100 
     | 
    
         
             
            (?<varname> \g<varchar>(?:\g<varchar>|\.)*){0}
         
     | 
| 
       101 
101 
     | 
    
         
             
            (?<varspec> \g<varname>\*?(?::\d+)?){0}
         
     | 
| 
       102 
     | 
    
         
            -
            ^(([^"'%<>^`{|}\s]|%\h\h)+|\{\g<operator>(?<vars>\g<varspec>(?:,\g<varspec>)*)\})*$
         
     | 
| 
      
 102 
     | 
    
         
            +
            ^(([^"'%<>^`{|}\s\p{Cc}]|%\h\h)+|\{\g<operator>(?<vars>\g<varspec>(?:,\g<varspec>)*)\})*$
         
     | 
| 
       103 
103 
     | 
    
         
             
            __REGEXP__
         
     | 
| 
       104 
104 
     | 
    
         | 
| 
       105 
105 
     | 
    
         
             
              # @private
         
     | 
| 
       106 
     | 
    
         
            -
              class  
     | 
| 
      
 106 
     | 
    
         
            +
              class Token
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
              
         
     | 
| 
      
 109 
     | 
    
         
            +
              # @private
         
     | 
| 
      
 110 
     | 
    
         
            +
              class Literal < Token
         
     | 
| 
       107 
111 
     | 
    
         | 
| 
       108 
112 
     | 
    
         
             
                attr_reader :string
         
     | 
| 
       109 
113 
     | 
    
         | 
| 
         @@ -115,6 +119,10 @@ __REGEXP__ 
     | 
|
| 
       115 
119 
     | 
    
         
             
                  0
         
     | 
| 
       116 
120 
     | 
    
         
             
                end
         
     | 
| 
       117 
121 
     | 
    
         | 
| 
      
 122 
     | 
    
         
            +
                def level
         
     | 
| 
      
 123 
     | 
    
         
            +
                  1
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
                
         
     | 
| 
       118 
126 
     | 
    
         
             
                def expand(*_)
         
     | 
| 
       119 
127 
     | 
    
         
             
                  return @string
         
     | 
| 
       120 
128 
     | 
    
         
             
                end
         
     | 
| 
         @@ -128,58 +136,9 @@ __REGEXP__ 
     | 
|
| 
       128 
136 
     | 
    
         
             
                end
         
     | 
| 
       129 
137 
     | 
    
         | 
| 
       130 
138 
     | 
    
         
             
              end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
              # @private
         
     | 
| 
       133 
     | 
    
         
            -
              class Terminal
         
     | 
| 
       134 
     | 
    
         
            -
                def expand(*_)
         
     | 
| 
       135 
     | 
    
         
            -
                  ''
         
     | 
| 
       136 
     | 
    
         
            -
                end
         
     | 
| 
       137 
     | 
    
         
            -
                
         
     | 
| 
       138 
     | 
    
         
            -
                def size
         
     | 
| 
       139 
     | 
    
         
            -
                  0
         
     | 
| 
       140 
     | 
    
         
            -
                end
         
     | 
| 
       141 
     | 
    
         
            -
              end
         
     | 
| 
       142 
     | 
    
         
            -
              
         
     | 
| 
       143 
     | 
    
         
            -
              # @private
         
     | 
| 
       144 
     | 
    
         
            -
              class LeftBound < Terminal
         
     | 
| 
       145 
     | 
    
         
            -
                
         
     | 
| 
       146 
     | 
    
         
            -
                def to_r_source(*_)
         
     | 
| 
       147 
     | 
    
         
            -
                  '^'
         
     | 
| 
       148 
     | 
    
         
            -
                end
         
     | 
| 
       149 
     | 
    
         
            -
                
         
     | 
| 
       150 
     | 
    
         
            -
                def to_s
         
     | 
| 
       151 
     | 
    
         
            -
                  ''
         
     | 
| 
       152 
     | 
    
         
            -
                end
         
     | 
| 
       153 
     | 
    
         
            -
                
         
     | 
| 
       154 
     | 
    
         
            -
              end
         
     | 
| 
       155 
     | 
    
         
            -
              
         
     | 
| 
       156 
     | 
    
         
            -
              # @private
         
     | 
| 
       157 
     | 
    
         
            -
              class RightBound < Terminal
         
     | 
| 
       158 
     | 
    
         
            -
                
         
     | 
| 
       159 
     | 
    
         
            -
                def to_r_source(*_)
         
     | 
| 
       160 
     | 
    
         
            -
                  '$'
         
     | 
| 
       161 
     | 
    
         
            -
                end
         
     | 
| 
       162 
     | 
    
         
            -
                
         
     | 
| 
       163 
     | 
    
         
            -
                def to_s
         
     | 
| 
       164 
     | 
    
         
            -
                  ''
         
     | 
| 
       165 
     | 
    
         
            -
                end
         
     | 
| 
       166 
     | 
    
         
            -
                
         
     | 
| 
       167 
     | 
    
         
            -
              end
         
     | 
| 
       168 
     | 
    
         
            -
              
         
     | 
| 
       169 
     | 
    
         
            -
              # @private
         
     | 
| 
       170 
     | 
    
         
            -
              class Open < Terminal
         
     | 
| 
       171 
     | 
    
         
            -
                
         
     | 
| 
       172 
     | 
    
         
            -
                def to_r_source(*_)
         
     | 
| 
       173 
     | 
    
         
            -
                  ''
         
     | 
| 
       174 
     | 
    
         
            -
                end
         
     | 
| 
       175 
     | 
    
         
            -
                
         
     | 
| 
       176 
     | 
    
         
            -
                def to_s
         
     | 
| 
       177 
     | 
    
         
            -
                  "\u2026"
         
     | 
| 
       178 
     | 
    
         
            -
                end
         
     | 
| 
       179 
     | 
    
         
            -
              end
         
     | 
| 
       180 
     | 
    
         
            -
              
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
       181 
140 
     | 
    
         
             
              # @private
         
     | 
| 
       182 
     | 
    
         
            -
              class Expression
         
     | 
| 
      
 141 
     | 
    
         
            +
              class Expression < Token
         
     | 
| 
       183 
142 
     | 
    
         | 
| 
       184 
143 
     | 
    
         
             
                attr_reader :variables, :max_length
         
     | 
| 
       185 
144 
     | 
    
         | 
| 
         @@ -192,6 +151,7 @@ __REGEXP__ 
     | 
|
| 
       192 
151 
     | 
    
         
             
                PAIR_CONNECTOR = '='.freeze
         
     | 
| 
       193 
152 
     | 
    
         
             
                PAIR_IF_EMPTY = true
         
     | 
| 
       194 
153 
     | 
    
         
             
                LIST_CONNECTOR = ','.freeze
         
     | 
| 
      
 154 
     | 
    
         
            +
                BASE_LEVEL = 1
         
     | 
| 
       195 
155 
     | 
    
         | 
| 
       196 
156 
     | 
    
         
             
                CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved]
         
     | 
| 
       197 
157 
     | 
    
         | 
| 
         @@ -202,6 +162,18 @@ __REGEXP__ 
     | 
|
| 
       202 
162 
     | 
    
         
             
                  @variables.size
         
     | 
| 
       203 
163 
     | 
    
         
             
                end
         
     | 
| 
       204 
164 
     | 
    
         | 
| 
      
 165 
     | 
    
         
            +
                def level
         
     | 
| 
      
 166 
     | 
    
         
            +
                  if @variables.none?{|_,expand,ml| expand || (ml > 0) }
         
     | 
| 
      
 167 
     | 
    
         
            +
                    if @variables.size == 1
         
     | 
| 
      
 168 
     | 
    
         
            +
                      return self.class::BASE_LEVEL
         
     | 
| 
      
 169 
     | 
    
         
            +
                    else
         
     | 
| 
      
 170 
     | 
    
         
            +
                      return 3
         
     | 
| 
      
 171 
     | 
    
         
            +
                    end
         
     | 
| 
      
 172 
     | 
    
         
            +
                  else
         
     | 
| 
      
 173 
     | 
    
         
            +
                    return 4
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
                end
         
     | 
| 
      
 176 
     | 
    
         
            +
                
         
     | 
| 
       205 
177 
     | 
    
         
             
                def expand( vars, options )
         
     | 
| 
       206 
178 
     | 
    
         
             
                  result = []
         
     | 
| 
       207 
179 
     | 
    
         
             
                  variables.each{| var, expand , max_length |
         
     | 
| 
         @@ -243,7 +215,7 @@ __REGEXP__ 
     | 
|
| 
       243 
215 
     | 
    
         
             
                      value = "(?:\\g<#{self.class::CHARACTER_CLASS[:class_name]}>|,)#{(max_length > 0)?'{,'+max_length.to_s+'}':'*'}"
         
     | 
| 
       244 
216 
     | 
    
         
             
                      if expand
         
     | 
| 
       245 
217 
     | 
    
         
             
                        #if self.class::PAIR_IF_EMPTY
         
     | 
| 
       246 
     | 
    
         
            -
                        pair = " 
     | 
| 
      
 218 
     | 
    
         
            +
                        pair = "(?:\\g<c_vn_>#{Regexp.escape(self.class::PAIR_CONNECTOR)})?#{value}"
         
     | 
| 
       247 
219 
     | 
    
         | 
| 
       248 
220 
     | 
    
         
             
                        if first
         
     | 
| 
       249 
221 
     | 
    
         
             
                          source << "(?<v#{base_counter + i}>(?:#{pair})(?:#{Regexp.escape(self.class::SEPARATOR)}#{pair})*)"
         
     | 
| 
         @@ -274,7 +246,7 @@ __REGEXP__ 
     | 
|
| 
       274 
246 
     | 
    
         
             
                        # could be list or map, too
         
     | 
| 
       275 
247 
     | 
    
         
             
                        value = "\\g<#{self.class::CHARACTER_CLASS[:class_name]}>#{(max_length > 0)?'{,'+max_length.to_s+'}':'*'}"
         
     | 
| 
       276 
248 
     | 
    
         | 
| 
       277 
     | 
    
         
            -
                        pair = " 
     | 
| 
      
 249 
     | 
    
         
            +
                        pair = "(?:\\g<c_vn_>#{Regexp.escape(self.class::PAIR_CONNECTOR)})?#{value}"
         
     | 
| 
       278 
250 
     | 
    
         | 
| 
       279 
251 
     | 
    
         
             
                        value = "#{pair}(?:#{Regexp.escape(self.class::SEPARATOR)}#{pair})*"
         
     | 
| 
       280 
252 
     | 
    
         
             
                      elsif last
         
     | 
| 
         @@ -323,12 +295,12 @@ __REGEXP__ 
     | 
|
| 
       323 
295 
     | 
    
         
             
                        found_value = true
         
     | 
| 
       324 
296 
     | 
    
         
             
                        splitted << [ match['name'][0..-2], decode(match['value'] + rest , false) ]
         
     | 
| 
       325 
297 
     | 
    
         
             
                      else
         
     | 
| 
       326 
     | 
    
         
            -
                        splitted << [  
     | 
| 
      
 298 
     | 
    
         
            +
                        splitted << [ match['value'] + rest, nil ]
         
     | 
| 
       327 
299 
     | 
    
         
             
                      end
         
     | 
| 
       328 
300 
     | 
    
         
             
                      rest = match.post_match
         
     | 
| 
       329 
301 
     | 
    
         
             
                    end
         
     | 
| 
       330 
302 
     | 
    
         
             
                    if !found_value
         
     | 
| 
       331 
     | 
    
         
            -
                      return [ [ name, splitted.map{|n,v|  
     | 
| 
      
 303 
     | 
    
         
            +
                      return [ [ name, splitted.map{|n,v| decode(n , false) } ] ]
         
     | 
| 
       332 
304 
     | 
    
         
             
                    else
         
     | 
| 
       333 
305 
     | 
    
         
             
                      return [ [ name, splitted ] ]
         
     | 
| 
       334 
306 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -433,6 +405,7 @@ __REGEXP__ 
     | 
|
| 
       433 
405 
     | 
    
         | 
| 
       434 
406 
     | 
    
         
             
                  CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved_reserved_pct]
         
     | 
| 
       435 
407 
     | 
    
         
             
                  OPERATOR = '+'.freeze
         
     | 
| 
      
 408 
     | 
    
         
            +
                  BASE_LEVEL = 2
         
     | 
| 
       436 
409 
     | 
    
         | 
| 
       437 
410 
     | 
    
         
             
                end
         
     | 
| 
       438 
411 
     | 
    
         | 
| 
         @@ -441,6 +414,7 @@ __REGEXP__ 
     | 
|
| 
       441 
414 
     | 
    
         
             
                  CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved_reserved_pct]
         
     | 
| 
       442 
415 
     | 
    
         
             
                  PREFIX = '#'.freeze
         
     | 
| 
       443 
416 
     | 
    
         
             
                  OPERATOR = '#'.freeze
         
     | 
| 
      
 417 
     | 
    
         
            +
                  BASE_LEVEL = 2
         
     | 
| 
       444 
418 
     | 
    
         | 
| 
       445 
419 
     | 
    
         
             
                end
         
     | 
| 
       446 
420 
     | 
    
         | 
| 
         @@ -449,6 +423,7 @@ __REGEXP__ 
     | 
|
| 
       449 
423 
     | 
    
         
             
                  SEPARATOR = '.'.freeze
         
     | 
| 
       450 
424 
     | 
    
         
             
                  PREFIX = '.'.freeze
         
     | 
| 
       451 
425 
     | 
    
         
             
                  OPERATOR = '.'.freeze
         
     | 
| 
      
 426 
     | 
    
         
            +
                  BASE_LEVEL = 3
         
     | 
| 
       452 
427 
     | 
    
         | 
| 
       453 
428 
     | 
    
         
             
                end
         
     | 
| 
       454 
429 
     | 
    
         | 
| 
         @@ -457,6 +432,7 @@ __REGEXP__ 
     | 
|
| 
       457 
432 
     | 
    
         
             
                  SEPARATOR = '/'.freeze
         
     | 
| 
       458 
433 
     | 
    
         
             
                  PREFIX = '/'.freeze
         
     | 
| 
       459 
434 
     | 
    
         
             
                  OPERATOR = '/'.freeze
         
     | 
| 
      
 435 
     | 
    
         
            +
                  BASE_LEVEL = 3
         
     | 
| 
       460 
436 
     | 
    
         | 
| 
       461 
437 
     | 
    
         
             
                end
         
     | 
| 
       462 
438 
     | 
    
         | 
| 
         @@ -467,6 +443,7 @@ __REGEXP__ 
     | 
|
| 
       467 
443 
     | 
    
         
             
                  NAMED = true
         
     | 
| 
       468 
444 
     | 
    
         
             
                  PAIR_IF_EMPTY = false
         
     | 
| 
       469 
445 
     | 
    
         
             
                  OPERATOR = ';'.freeze
         
     | 
| 
      
 446 
     | 
    
         
            +
                  BASE_LEVEL = 3
         
     | 
| 
       470 
447 
     | 
    
         | 
| 
       471 
448 
     | 
    
         
             
                end
         
     | 
| 
       472 
449 
     | 
    
         | 
| 
         @@ -476,6 +453,7 @@ __REGEXP__ 
     | 
|
| 
       476 
453 
     | 
    
         
             
                  PREFIX = '?'.freeze
         
     | 
| 
       477 
454 
     | 
    
         
             
                  NAMED = true
         
     | 
| 
       478 
455 
     | 
    
         
             
                  OPERATOR = '?'.freeze
         
     | 
| 
      
 456 
     | 
    
         
            +
                  BASE_LEVEL = 3
         
     | 
| 
       479 
457 
     | 
    
         | 
| 
       480 
458 
     | 
    
         
             
                end
         
     | 
| 
       481 
459 
     | 
    
         | 
| 
         @@ -485,6 +463,7 @@ __REGEXP__ 
     | 
|
| 
       485 
463 
     | 
    
         
             
                  PREFIX = '&'.freeze
         
     | 
| 
       486 
464 
     | 
    
         
             
                  NAMED = true
         
     | 
| 
       487 
465 
     | 
    
         
             
                  OPERATOR = '&'.freeze
         
     | 
| 
      
 466 
     | 
    
         
            +
                  BASE_LEVEL = 3
         
     | 
| 
       488 
467 
     | 
    
         | 
| 
       489 
468 
     | 
    
         
             
                end
         
     | 
| 
       490 
469 
     | 
    
         | 
| 
         @@ -559,6 +538,7 @@ __REGEXP__ 
     | 
|
| 
       559 
538 
     | 
    
         | 
| 
       560 
539 
     | 
    
         
             
                # Tries to convert the given param in to a instance of {Draft7}
         
     | 
| 
       561 
540 
     | 
    
         
             
                # It basically passes thru instances of that class, parses strings and return nil on everything else.
         
     | 
| 
      
 541 
     | 
    
         
            +
                #
         
     | 
| 
       562 
542 
     | 
    
         
             
                # @example
         
     | 
| 
       563 
543 
     | 
    
         
             
                #   URITemplate::Draft7.try_convert( Object.new ) #=> nil
         
     | 
| 
       564 
544 
     | 
    
         
             
                #   tpl = URITemplate::Draft7.new('{foo}')
         
     | 
| 
         @@ -566,6 +546,7 @@ __REGEXP__ 
     | 
|
| 
       566 
546 
     | 
    
         
             
                #   URITemplate::Draft7.try_convert('{foo}') #=> tpl
         
     | 
| 
       567 
547 
     | 
    
         
             
                #   # This pattern is invalid, so it wont be parsed:
         
     | 
| 
       568 
548 
     | 
    
         
             
                #   URITemplate::Draft7.try_convert('{foo') #=> nil
         
     | 
| 
      
 549 
     | 
    
         
            +
                #
         
     | 
| 
       569 
550 
     | 
    
         
             
                def try_convert(x)
         
     | 
| 
       570 
551 
     | 
    
         
             
                  if x.kind_of? self
         
     | 
| 
       571 
552 
     | 
    
         
             
                    return x
         
     | 
| 
         @@ -576,6 +557,19 @@ __REGEXP__ 
     | 
|
| 
       576 
557 
     | 
    
         
             
                  end
         
     | 
| 
       577 
558 
     | 
    
         
             
                end
         
     | 
| 
       578 
559 
     | 
    
         | 
| 
      
 560 
     | 
    
         
            +
                
         
     | 
| 
      
 561 
     | 
    
         
            +
                # Like {.try_convert}, but raises an ArgumentError, when the conversion failed.
         
     | 
| 
      
 562 
     | 
    
         
            +
                # 
         
     | 
| 
      
 563 
     | 
    
         
            +
                # @raise ArgumentError
         
     | 
| 
      
 564 
     | 
    
         
            +
                def convert(x)
         
     | 
| 
      
 565 
     | 
    
         
            +
                  o = self.try_convert(x)
         
     | 
| 
      
 566 
     | 
    
         
            +
                  if o.nil?
         
     | 
| 
      
 567 
     | 
    
         
            +
                    raise ArgumentError, "Expected to receive something that can be converted to an #{self.class}, but got: #{x.inspect}."
         
     | 
| 
      
 568 
     | 
    
         
            +
                  else
         
     | 
| 
      
 569 
     | 
    
         
            +
                    return o
         
     | 
| 
      
 570 
     | 
    
         
            +
                  end
         
     | 
| 
      
 571 
     | 
    
         
            +
                end
         
     | 
| 
      
 572 
     | 
    
         
            +
                
         
     | 
| 
       579 
573 
     | 
    
         
             
                # Tests whether a given pattern is a valid template pattern.
         
     | 
| 
       580 
574 
     | 
    
         
             
                # @example
         
     | 
| 
       581 
575 
     | 
    
         
             
                #   URITemplate::Draft7.valid? 'foo' #=> true
         
     | 
| 
         @@ -663,28 +657,49 @@ __REGEXP__ 
     | 
|
| 
       663 
657 
     | 
    
         
             
              def to_r
         
     | 
| 
       664 
658 
     | 
    
         
             
                classes = CHARACTER_CLASSES.map{|_,v| v[:class]+"{0}\n" }
         
     | 
| 
       665 
659 
     | 
    
         
             
                bc = 0
         
     | 
| 
       666 
     | 
    
         
            -
                @regexp ||= Regexp.new(classes.join + tokens.map{|part|
         
     | 
| 
      
 660 
     | 
    
         
            +
                @regexp ||= Regexp.new(classes.join + '\A' + tokens.map{|part|
         
     | 
| 
       667 
661 
     | 
    
         
             
                  r = part.to_r_source(bc)
         
     | 
| 
       668 
662 
     | 
    
         
             
                  bc += part.size
         
     | 
| 
       669 
663 
     | 
    
         
             
                  r
         
     | 
| 
       670 
     | 
    
         
            -
                }.join, Regexp::EXTENDED)
         
     | 
| 
      
 664 
     | 
    
         
            +
                }.join + '\z' , Regexp::EXTENDED)
         
     | 
| 
       671 
665 
     | 
    
         
             
              end
         
     | 
| 
       672 
666 
     | 
    
         | 
| 
       673 
667 
     | 
    
         | 
| 
       674 
668 
     | 
    
         
             
              # Extracts variables from a uri ( given as string ) or an instance of MatchData ( which was matched by the regexp of this template.
         
     | 
| 
       675 
     | 
    
         
            -
              # The actual result depends on the value of  
     | 
| 
      
 669 
     | 
    
         
            +
              # The actual result depends on the value of post_processing.
         
     | 
| 
       676 
670 
     | 
    
         
             
              # This argument specifies whether pair arrays should be converted to hashes.
         
     | 
| 
       677 
671 
     | 
    
         
             
              # 
         
     | 
| 
       678 
     | 
    
         
            -
              # @example
         
     | 
| 
      
 672 
     | 
    
         
            +
              # @example Default Processing
         
     | 
| 
       679 
673 
     | 
    
         
             
              #   URITemplate::Draft7.new('{var}').extract('value') #=> {'var'=>'value'}
         
     | 
| 
       680 
674 
     | 
    
         
             
              #   URITemplate::Draft7.new('{&args*}').extract('&a=1&b=2') #=> {'args'=>{'a'=>'1','b'=>'2'}}
         
     | 
| 
       681 
675 
     | 
    
         
             
              #   URITemplate::Draft7.new('{&arg,arg}').extract('&arg=1&arg=2') #=> {'arg'=>'2'}
         
     | 
| 
       682 
676 
     | 
    
         
             
              #
         
     | 
| 
       683 
     | 
    
         
            -
              # @example
         
     | 
| 
      
 677 
     | 
    
         
            +
              # @example No Processing
         
     | 
| 
       684 
678 
     | 
    
         
             
              #   URITemplate::Draft7.new('{var}').extract('value', URITemplate::Draft7::NO_PROCESSING) #=> [['var','value']]
         
     | 
| 
       685 
679 
     | 
    
         
             
              #   URITemplate::Draft7.new('{&args*}').extract('&a=1&b=2', URITemplate::Draft7::NO_PROCESSING) #=> [['args',[['a','1'],['b','2']]]]
         
     | 
| 
       686 
680 
     | 
    
         
             
              #   URITemplate::Draft7.new('{&arg,arg}').extract('&arg=1&arg=2', URITemplate::Draft7::NO_PROCESSING) #=> [['arg','1'],['arg','2']]
         
     | 
| 
       687 
681 
     | 
    
         
             
              #
         
     | 
| 
      
 682 
     | 
    
         
            +
              # @raise Encoding::InvalidByteSequenceError when the given uri was not properly encoded.
         
     | 
| 
      
 683 
     | 
    
         
            +
              # @raise Encoding::UndefinedConversionError when the given uri could not be converted to utf-8.
         
     | 
| 
      
 684 
     | 
    
         
            +
              # @raise Encoding::CompatibilityError when the given uri could not be converted to utf-8.
         
     | 
| 
      
 685 
     | 
    
         
            +
              #
         
     | 
| 
      
 686 
     | 
    
         
            +
              # @param [String,MatchData] Uri_or_MatchData A uri or a matchdata from which the variables should be extracted.
         
     | 
| 
      
 687 
     | 
    
         
            +
              # @param [Array] Processing Specifies which processing should be done.
         
     | 
| 
      
 688 
     | 
    
         
            +
              # 
         
     | 
| 
      
 689 
     | 
    
         
            +
              # @note
         
     | 
| 
      
 690 
     | 
    
         
            +
              #   Don't expect that an extraction can fully recover the expanded variables. Extract rather generates a variable list which should expand to the uri from which it were extracted. In general the following equation should hold true:
         
     | 
| 
      
 691 
     | 
    
         
            +
              #     a_tpl.expand( a_tpl.extract( an_uri ) ) == an_uri
         
     | 
| 
      
 692 
     | 
    
         
            +
              #
         
     | 
| 
      
 693 
     | 
    
         
            +
              # @example Extraction cruces
         
     | 
| 
      
 694 
     | 
    
         
            +
              #   two_lists = URITemplate::Draft7.new('{listA*,listB*}')
         
     | 
| 
      
 695 
     | 
    
         
            +
              #   uri = two_lists.expand('listA'=>[1,2],'listB'=>[3,4]) #=> "1,2,3,4"
         
     | 
| 
      
 696 
     | 
    
         
            +
              #   variables = two_lists.extract( uri ) #=> {'listA'=>["1","2","3","4"],'listB'=>nil}
         
     | 
| 
      
 697 
     | 
    
         
            +
              #   # However, like said in the note:
         
     | 
| 
      
 698 
     | 
    
         
            +
              #   two_lists.expand( variables ) == uri #=> true
         
     | 
| 
      
 699 
     | 
    
         
            +
              #
         
     | 
| 
      
 700 
     | 
    
         
            +
              # @note
         
     | 
| 
      
 701 
     | 
    
         
            +
              #   The current implementation drops duplicated variables instead of checking them.
         
     | 
| 
      
 702 
     | 
    
         
            +
              #   
         
     | 
| 
       688 
703 
     | 
    
         
             
              #   
         
     | 
| 
       689 
704 
     | 
    
         
             
              def extract(uri_or_match, post_processing = DEFAULT_PROCESSING )
         
     | 
| 
       690 
705 
     | 
    
         
             
                if uri_or_match.kind_of? String
         
     | 
| 
         @@ -703,12 +718,6 @@ __REGEXP__ 
     | 
|
| 
       703 
718 
     | 
    
         
             
                  return nil
         
     | 
| 
       704 
719 
     | 
    
         
             
                else
         
     | 
| 
       705 
720 
     | 
    
         
             
                  result = extract_matchdata(m)
         
     | 
| 
       706 
     | 
    
         
            -
                  if m.pre_match and m.pre_match.size > 0
         
     | 
| 
       707 
     | 
    
         
            -
                    result.unshift( [:prefix, m.pre_match] )
         
     | 
| 
       708 
     | 
    
         
            -
                  end
         
     | 
| 
       709 
     | 
    
         
            -
                  if m.post_match and m.post_match.size > 0
         
     | 
| 
       710 
     | 
    
         
            -
                    result.push( [:suffix, m.post_match] )
         
     | 
| 
       711 
     | 
    
         
            -
                  end
         
     | 
| 
       712 
721 
     | 
    
         
             
                  if post_processing.include? :convert_values
         
     | 
| 
       713 
722 
     | 
    
         
             
                    result.map!{|k,v| [k, Utils.pair_array_to_hash(v)] }
         
     | 
| 
       714 
723 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -738,140 +747,158 @@ __REGEXP__ 
     | 
|
| 
       738 
747 
     | 
    
         
             
              end
         
     | 
| 
       739 
748 
     | 
    
         | 
| 
       740 
749 
     | 
    
         
             
              alias to_s pattern
         
     | 
| 
      
 750 
     | 
    
         
            +
              
         
     | 
| 
      
 751 
     | 
    
         
            +
              # Compares two template patterns.
         
     | 
| 
      
 752 
     | 
    
         
            +
              def ==(tpl)
         
     | 
| 
      
 753 
     | 
    
         
            +
                return false if self.class != tpl.class
         
     | 
| 
      
 754 
     | 
    
         
            +
                return self.pattern == tpl.pattern
         
     | 
| 
      
 755 
     | 
    
         
            +
              end
         
     | 
| 
      
 756 
     | 
    
         
            +
              
         
     | 
| 
      
 757 
     | 
    
         
            +
              # @method ===(uri)
         
     | 
| 
      
 758 
     | 
    
         
            +
              # Alias for to_r.=== . Tests whether this template matches a given uri.
         
     | 
| 
      
 759 
     | 
    
         
            +
              # @return TrueClass, FalseClass
         
     | 
| 
      
 760 
     | 
    
         
            +
              def_delegators :to_r, :===
         
     | 
| 
      
 761 
     | 
    
         
            +
              
         
     | 
| 
      
 762 
     | 
    
         
            +
              # @method match(uri)
         
     | 
| 
      
 763 
     | 
    
         
            +
              # Alias for to_r.match . Matches this template against the given uri.
         
     | 
| 
      
 764 
     | 
    
         
            +
              # @yield MatchData
         
     | 
| 
      
 765 
     | 
    
         
            +
              # @return MatchData, Object 
         
     | 
| 
      
 766 
     | 
    
         
            +
              def_delegators :to_r, :match
         
     | 
| 
       741 
767 
     | 
    
         | 
| 
       742 
     | 
    
         
            -
              #  
     | 
| 
       743 
     | 
    
         
            -
              # 
     | 
| 
       744 
     | 
    
         
            -
              # Unboundedness is denoted with unicode character \u2026 ( … ).
         
     | 
| 
       745 
     | 
    
         
            -
              # 
         
     | 
| 
       746 
     | 
    
         
            -
              # @example
         
     | 
| 
       747 
     | 
    
         
            -
              #   prefix = URITemplate::Draft7::Section.new('/prefix…')
         
     | 
| 
       748 
     | 
    
         
            -
              #   template = URITemplate::Draft7.new('/prefix')
         
     | 
| 
       749 
     | 
    
         
            -
              #   prefix === '/prefix/something completly different' #=> true
         
     | 
| 
       750 
     | 
    
         
            -
              #   template === '/prefix/something completly different' #=> false
         
     | 
| 
       751 
     | 
    
         
            -
              #   prefix.to_r.match('/prefix/something completly different').post_match #=> '/something completly different'
         
     | 
| 
       752 
     | 
    
         
            -
              # 
         
     | 
| 
      
 768 
     | 
    
         
            +
              # The type of this template.
         
     | 
| 
      
 769 
     | 
    
         
            +
              #
         
     | 
| 
       753 
770 
     | 
    
         
             
              # @example
         
     | 
| 
       754 
     | 
    
         
            -
              #    
     | 
| 
       755 
     | 
    
         
            -
              #    
     | 
| 
       756 
     | 
    
         
            -
              #    
     | 
| 
       757 
     | 
    
         
            -
              # 
     | 
| 
       758 
     | 
    
         
            -
              #  
     | 
| 
      
 771 
     | 
    
         
            +
              #   tpl1 = URITemplate::Draft7.new('/foo')
         
     | 
| 
      
 772 
     | 
    
         
            +
              #   tpl2 = URITemplate.new( tpl1.pattern, tpl1.type )
         
     | 
| 
      
 773 
     | 
    
         
            +
              #   tpl1 == tpl2 #=> true
         
     | 
| 
      
 774 
     | 
    
         
            +
              #
         
     | 
| 
      
 775 
     | 
    
         
            +
              # @see {URITemplate#type}
         
     | 
| 
      
 776 
     | 
    
         
            +
              def type
         
     | 
| 
      
 777 
     | 
    
         
            +
                :draft7
         
     | 
| 
      
 778 
     | 
    
         
            +
              end
         
     | 
| 
      
 779 
     | 
    
         
            +
              
         
     | 
| 
      
 780 
     | 
    
         
            +
              # Returns the level of this template according to the draft ( http://tools.ietf.org/html/draft-gregorio-uritemplate-07#section-1.2 ). Higher level means higher complexity.
         
     | 
| 
      
 781 
     | 
    
         
            +
              # Basically this is defined as:
         
     | 
| 
       759 
782 
     | 
    
         
             
              # 
         
     | 
| 
      
 783 
     | 
    
         
            +
              # * Level 1: no operators, one variable per expansion, no variable modifiers
         
     | 
| 
      
 784 
     | 
    
         
            +
              # * Level 2: '+' and '#' operators, one variable per expansion, no variable modifiers
         
     | 
| 
      
 785 
     | 
    
         
            +
              # * Level 3: all operators, multiple variables per expansion, no variable modifiers
         
     | 
| 
      
 786 
     | 
    
         
            +
              # * Level 4: all operators, multiple variables per expansion, all variable modifiers
         
     | 
| 
      
 787 
     | 
    
         
            +
              #
         
     | 
| 
       760 
788 
     | 
    
         
             
              # @example
         
     | 
| 
       761 
     | 
    
         
            -
              #   
         
     | 
| 
       762 
     | 
    
         
            -
              #    
     | 
| 
       763 
     | 
    
         
            -
              # 
     | 
| 
       764 
     | 
    
         
            -
              # 
     | 
| 
       765 
     | 
    
         
            -
              # 
     | 
| 
       766 
     | 
    
         
            -
              # 
     | 
| 
       767 
     | 
    
         
            -
              # 
     | 
| 
       768 
     | 
    
         
            -
              # 
     | 
| 
       769 
     | 
    
         
            -
              # 
     | 
| 
       770 
     | 
    
         
            -
              # 
     | 
| 
       771 
     | 
    
         
            -
               
     | 
| 
       772 
     | 
    
         
            -
             
     | 
| 
       773 
     | 
    
         
            -
               
     | 
| 
       774 
     | 
    
         
            -
              #   end
         
     | 
| 
       775 
     | 
    
         
            -
              #   route( 'app_a/do_something' ) #=> "app_a: do_something with {:suffix=>\"do_something\"}"
         
     | 
| 
       776 
     | 
    
         
            -
              #   route( 'app_b/1337/something_else' ) #=> "app_b: something_else with {\"x\"=>\"1337\", :suffix=>\"something_else\"}"
         
     | 
| 
       777 
     | 
    
         
            -
              #   route( 'bla' ) #=> 'not found'
         
     | 
| 
       778 
     | 
    
         
            -
              # 
         
     | 
| 
       779 
     | 
    
         
            -
              class Section < self
         
     | 
| 
       780 
     | 
    
         
            -
              
         
     | 
| 
       781 
     | 
    
         
            -
                include URITemplate::Section
         
     | 
| 
      
 789 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo/').level #=> 1
         
     | 
| 
      
 790 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{bar}').level #=> 1
         
     | 
| 
      
 791 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{#bar}').level #=> 2
         
     | 
| 
      
 792 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{.bar}').level #=> 3
         
     | 
| 
      
 793 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{bar,baz}').level #=> 3
         
     | 
| 
      
 794 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{bar:20}').level #=> 4
         
     | 
| 
      
 795 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/foo{bar*}').level #=> 4
         
     | 
| 
      
 796 
     | 
    
         
            +
              #
         
     | 
| 
      
 797 
     | 
    
         
            +
              # Templates of lower levels might be convertible to other formats while templates of higher levels might be incompatible. Level 1 for example should be convertible to any other format since it just contains simple expansions.
         
     | 
| 
      
 798 
     | 
    
         
            +
              #
         
     | 
| 
      
 799 
     | 
    
         
            +
              def level
         
     | 
| 
      
 800 
     | 
    
         
            +
                tokens.map(&:level).max
         
     | 
| 
      
 801 
     | 
    
         
            +
              end
         
     | 
| 
       782 
802 
     | 
    
         | 
| 
       783 
     | 
    
         
            -
             
     | 
| 
       784 
     | 
    
         
            -
             
     | 
| 
      
 803 
     | 
    
         
            +
              # Tries to conatenate two templates, as if they were path segments.
         
     | 
| 
      
 804 
     | 
    
         
            +
              # Removes double slashes or insert one if they are missing.
         
     | 
| 
      
 805 
     | 
    
         
            +
              #
         
     | 
| 
      
 806 
     | 
    
         
            +
              # @example
         
     | 
| 
      
 807 
     | 
    
         
            +
              #   tpl = URITemplate::Draft7.new('/xy/')
         
     | 
| 
      
 808 
     | 
    
         
            +
              #   (tpl / '/z/' ).pattern #=> '/xy/z/'
         
     | 
| 
      
 809 
     | 
    
         
            +
              #   (tpl / 'z/' ).pattern #=> '/xy/z/'
         
     | 
| 
      
 810 
     | 
    
         
            +
              #   (tpl / '{/z}' ).pattern #=> '/xy{/z}'
         
     | 
| 
      
 811 
     | 
    
         
            +
              #   (tpl / 'a' / 'b' ).pattern #=> '/xy/a/b'
         
     | 
| 
      
 812 
     | 
    
         
            +
              #
         
     | 
| 
      
 813 
     | 
    
         
            +
              def /(o)
         
     | 
| 
      
 814 
     | 
    
         
            +
                other = self.class.convert(o)
         
     | 
| 
       785 
815 
     | 
    
         | 
| 
       786 
     | 
    
         
            -
                 
     | 
| 
       787 
     | 
    
         
            -
             
     | 
| 
       788 
     | 
    
         
            -
                  tokens.first.kind_of? LeftBound
         
     | 
| 
      
 816 
     | 
    
         
            +
                if other.absolute?
         
     | 
| 
      
 817 
     | 
    
         
            +
                  raise ArgumentError, "Expected to receive a relative template but got an absoulte one: #{other.inspect}. If you think this is a bug, please report it."
         
     | 
| 
       789 
818 
     | 
    
         
             
                end
         
     | 
| 
       790 
819 
     | 
    
         | 
| 
       791 
     | 
    
         
            -
                 
     | 
| 
       792 
     | 
    
         
            -
             
     | 
| 
       793 
     | 
    
         
            -
                  tokens.last.kind_of? RightBound
         
     | 
| 
      
 820 
     | 
    
         
            +
                if other.pattern == ''
         
     | 
| 
      
 821 
     | 
    
         
            +
                  return self
         
     | 
| 
       794 
822 
     | 
    
         
             
                end
         
     | 
| 
       795 
     | 
    
         
            -
                
         
     | 
| 
       796 
     | 
    
         
            -
                #  
     | 
| 
       797 
     | 
    
         
            -
                 
     | 
| 
       798 
     | 
    
         
            -
             
     | 
| 
       799 
     | 
    
         
            -
             
     | 
| 
       800 
     | 
    
         
            -
             
     | 
| 
       801 
     | 
    
         
            -
             
     | 
| 
       802 
     | 
    
         
            -
             
     | 
| 
       803 
     | 
    
         
            -
             
     | 
| 
       804 
     | 
    
         
            -
             
     | 
| 
       805 
     | 
    
         
            -
             
     | 
| 
       806 
     | 
    
         
            -
             
     | 
| 
       807 
     | 
    
         
            -
                #   sect = URITemplate::Draft7::Section.new('…')
         
     | 
| 
       808 
     | 
    
         
            -
                #   combo = sect >> '…'
         
     | 
| 
       809 
     | 
    
         
            -
                #   combo.pattern #=> ""
         
     | 
| 
       810 
     | 
    
         
            -
                #   combo === "" #=> true
         
     | 
| 
       811 
     | 
    
         
            -
                #   combo === "/foo" #=> false
         
     | 
| 
       812 
     | 
    
         
            -
                # 
         
     | 
| 
       813 
     | 
    
         
            -
                # @return Section
         
     | 
| 
       814 
     | 
    
         
            -
                def >>(other)
         
     | 
| 
       815 
     | 
    
         
            -
                  o = self.class.try_convert(other)
         
     | 
| 
       816 
     | 
    
         
            -
                  if o.kind_of? Section
         
     | 
| 
       817 
     | 
    
         
            -
                    if !self.right_bound?
         
     | 
| 
       818 
     | 
    
         
            -
                      if o.pattern == ELLIPSIS
         
     | 
| 
       819 
     | 
    
         
            -
                        return self.class.new("", o.options)
         
     | 
| 
       820 
     | 
    
         
            -
                      elsif !o.left_bound?
         
     | 
| 
       821 
     | 
    
         
            -
                        #if self.tokens.size == 1
         
     | 
| 
       822 
     | 
    
         
            -
                        #  return o
         
     | 
| 
       823 
     | 
    
         
            -
                        #end
         
     | 
| 
       824 
     | 
    
         
            -
                        tkns = self.tokens[0..-2] + o.tokens[1..-1]
         
     | 
| 
       825 
     | 
    
         
            -
                        unless tkns.first.kind_of? Terminal
         
     | 
| 
       826 
     | 
    
         
            -
                          tkns.unshift(LeftBound.new)
         
     | 
| 
       827 
     | 
    
         
            -
                        end
         
     | 
| 
       828 
     | 
    
         
            -
                        unless tkns.last.kind_of? Terminal
         
     | 
| 
       829 
     | 
    
         
            -
                          tkns.push(RightBound.new)
         
     | 
| 
       830 
     | 
    
         
            -
                        end
         
     | 
| 
       831 
     | 
    
         
            -
                        return self.class.new(tkns, o.options)
         
     | 
| 
      
 823 
     | 
    
         
            +
                # Merge!
         
     | 
| 
      
 824 
     | 
    
         
            +
                # Analyze the last token of this an the first token of the next and try to merge them
         
     | 
| 
      
 825 
     | 
    
         
            +
                if self.tokens.last.kind_of?(Literal)
         
     | 
| 
      
 826 
     | 
    
         
            +
                  if self.tokens.last.string[-1] == '/' # the last token ends with an /
         
     | 
| 
      
 827 
     | 
    
         
            +
                    if other.tokens.first.kind_of? Literal
         
     | 
| 
      
 828 
     | 
    
         
            +
                      # both seems to be paths, merge them!
         
     | 
| 
      
 829 
     | 
    
         
            +
                      if other.tokens.first.string[0] == '/'
         
     | 
| 
      
 830 
     | 
    
         
            +
                        # strip one '/'
         
     | 
| 
      
 831 
     | 
    
         
            +
                        return self.class.new( self.tokens[0..-2] + [ Literal.new(self.tokens.last.string + other.tokens.first.string[1..-1]) ] + other.tokens[1..-1] )
         
     | 
| 
      
 832 
     | 
    
         
            +
                      else
         
     | 
| 
      
 833 
     | 
    
         
            +
                        # no problem, but we can merge them
         
     | 
| 
      
 834 
     | 
    
         
            +
                        return self.class.new( self.tokens[0..-2] + [ Literal.new(self.tokens.last.string + other.tokens.first.string) ] + other.tokens[1..-1] )
         
     | 
| 
       832 
835 
     | 
    
         
             
                      end
         
     | 
| 
      
 836 
     | 
    
         
            +
                    elsif other.tokens.first.kind_of? Expression::Path
         
     | 
| 
      
 837 
     | 
    
         
            +
                      # this will automatically insert '/'
         
     | 
| 
      
 838 
     | 
    
         
            +
                      # so we can strip one '/'
         
     | 
| 
      
 839 
     | 
    
         
            +
                      return self.class.new( self.tokens[0..-2] + [ Literal.new(self.tokens.last.string[0..-2]) ] + other.tokens )
         
     | 
| 
       833 
840 
     | 
    
         
             
                    end
         
     | 
| 
       834 
     | 
    
         
            -
                    raise ArgumentError, "Expected something that could be converted to a URITemplate section, but got #{other.inspect}"
         
     | 
| 
       835 
841 
     | 
    
         
             
                  end
         
     | 
| 
       836 
842 
     | 
    
         
             
                end
         
     | 
| 
      
 843 
     | 
    
         
            +
                if other.tokens.first.kind_of?(Expression::Path) or (other.tokens.first.kind_of?(Literal) and other.tokens.first.string[0] == '/')
         
     | 
| 
      
 844 
     | 
    
         
            +
                  return self.class.new( self.tokens + other.tokens )
         
     | 
| 
      
 845 
     | 
    
         
            +
                else
         
     | 
| 
      
 846 
     | 
    
         
            +
                  return self.class.new( self.tokens + [Literal.new('/')] + other.tokens )
         
     | 
| 
      
 847 
     | 
    
         
            +
                end
         
     | 
| 
      
 848 
     | 
    
         
            +
              end
         
     | 
| 
      
 849 
     | 
    
         
            +
              
         
     | 
| 
      
 850 
     | 
    
         
            +
              
         
     | 
| 
      
 851 
     | 
    
         
            +
              #
         
     | 
| 
      
 852 
     | 
    
         
            +
              # should be relative:
         
     | 
| 
      
 853 
     | 
    
         
            +
              #  xxx ...
         
     | 
| 
      
 854 
     | 
    
         
            +
              #  {xxx}x ...
         
     | 
| 
      
 855 
     | 
    
         
            +
              # 
         
     | 
| 
      
 856 
     | 
    
         
            +
              #  should not be relative:
         
     | 
| 
      
 857 
     | 
    
         
            +
              #  {proto}:// ...
         
     | 
| 
      
 858 
     | 
    
         
            +
              #  http:// ...
         
     | 
| 
      
 859 
     | 
    
         
            +
              #  http{ssl}:// ...
         
     | 
| 
      
 860 
     | 
    
         
            +
              #
         
     | 
| 
      
 861 
     | 
    
         
            +
              def absolute?
         
     | 
| 
      
 862 
     | 
    
         
            +
                read_chars = ""
         
     | 
| 
       837 
863 
     | 
    
         | 
| 
       838 
     | 
    
         
            -
                 
     | 
| 
       839 
     | 
    
         
            -
             
     | 
| 
       840 
     | 
    
         
            -
             
     | 
| 
       841 
     | 
    
         
            -
             
     | 
| 
       842 
     | 
    
         
            -
             
     | 
| 
       843 
     | 
    
         
            -
             
     | 
| 
       844 
     | 
    
         
            -
             
     | 
| 
       845 
     | 
    
         
            -
             
     | 
| 
       846 
     | 
    
         
            -
                     
     | 
| 
      
 864 
     | 
    
         
            +
                tokens.each do |token|
         
     | 
| 
      
 865 
     | 
    
         
            +
                  if token.kind_of? Expression
         
     | 
| 
      
 866 
     | 
    
         
            +
                    if token.class::OPERATOR == ''
         
     | 
| 
      
 867 
     | 
    
         
            +
                      read_chars << "x"
         
     | 
| 
      
 868 
     | 
    
         
            +
                    else
         
     | 
| 
      
 869 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 870 
     | 
    
         
            +
                    end
         
     | 
| 
      
 871 
     | 
    
         
            +
                  elsif token.kind_of? Literal
         
     | 
| 
      
 872 
     | 
    
         
            +
                    read_chars << token.string
         
     | 
| 
      
 873 
     | 
    
         
            +
                  end
         
     | 
| 
      
 874 
     | 
    
         
            +
                  if read_chars =~ /^[a-z]+:\/\//i
         
     | 
| 
      
 875 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 876 
     | 
    
         
            +
                  elsif read_chars =~ /(?<!:|\/)\/(?!\/)/
         
     | 
| 
      
 877 
     | 
    
         
            +
                    return false
         
     | 
| 
       847 
878 
     | 
    
         
             
                  end
         
     | 
| 
       848 
     | 
    
         
            -
                  pat = pat[ (lb ? 0 : 1)..(rb ? -1 : -2) ]
         
     | 
| 
       849 
     | 
    
         
            -
                  [lb ? LeftBound.new : Open.new] + Tokenizer.new(pat).to_a + [rb ? RightBound.new : Open.new]
         
     | 
| 
       850 
879 
     | 
    
         
             
                end
         
     | 
| 
       851 
     | 
    
         
            -
             
     | 
| 
      
 880 
     | 
    
         
            +
                
         
     | 
| 
      
 881 
     | 
    
         
            +
                return false
         
     | 
| 
       852 
882 
     | 
    
         
             
              end
         
     | 
| 
       853 
883 
     | 
    
         | 
| 
       854 
     | 
    
         
            -
              #  
     | 
| 
       855 
     | 
    
         
            -
               
     | 
| 
       856 
     | 
    
         
            -
             
     | 
| 
       857 
     | 
    
         
            -
             
     | 
| 
      
 884 
     | 
    
         
            +
              # Returns the number of static characters in this template.
         
     | 
| 
      
 885 
     | 
    
         
            +
              # This method is useful for routing, since it's often pointful to use the url with fewer variable characters.
         
     | 
| 
      
 886 
     | 
    
         
            +
              # For example 'static' and 'sta{var}' both match 'static', but in most cases 'static' should be prefered over 'sta{var}' since it's more specific.
         
     | 
| 
      
 887 
     | 
    
         
            +
              #
         
     | 
| 
      
 888 
     | 
    
         
            +
              # @example
         
     | 
| 
      
 889 
     | 
    
         
            +
              #   URITemplate::Draft7.new('/xy/').static_characters #=> 4
         
     | 
| 
      
 890 
     | 
    
         
            +
              #   URITemplate::Draft7.new('{foo}').static_characters #=> 0
         
     | 
| 
      
 891 
     | 
    
         
            +
              #   URITemplate::Draft7.new('a{foo}b').static_characters #=> 2
         
     | 
| 
      
 892 
     | 
    
         
            +
              #
         
     | 
| 
      
 893 
     | 
    
         
            +
              # @return Numeric
         
     | 
| 
      
 894 
     | 
    
         
            +
              def static_characters
         
     | 
| 
      
 895 
     | 
    
         
            +
                @static_characters ||= tokens.select{|t| t.kind_of?(Literal) }.map{|t| t.string.size }.inject(0,:+)
         
     | 
| 
       858 
896 
     | 
    
         
             
              end
         
     | 
| 
       859 
     | 
    
         
            -
              
         
     | 
| 
       860 
     | 
    
         
            -
              # @method ===(uri)
         
     | 
| 
       861 
     | 
    
         
            -
              # Alias for to_r.=== . Tests whether this template matches a given uri.
         
     | 
| 
       862 
     | 
    
         
            -
              # @return TrueClass, FalseClass
         
     | 
| 
       863 
     | 
    
         
            -
              def_delegators :to_r, :===
         
     | 
| 
       864 
     | 
    
         
            -
              
         
     | 
| 
       865 
     | 
    
         
            -
              # @method match(uri)
         
     | 
| 
       866 
     | 
    
         
            -
              # Alias for to_r.match . Matches this template against the given uri.
         
     | 
| 
       867 
     | 
    
         
            -
              # @yield MatchData
         
     | 
| 
       868 
     | 
    
         
            -
              # @return MatchData, Object 
         
     | 
| 
       869 
     | 
    
         
            -
              def_delegators :to_r, :match
         
     | 
| 
       870 
897 
     | 
    
         | 
| 
       871 
898 
     | 
    
         
             
            protected
         
     | 
| 
       872 
899 
     | 
    
         
             
              # @private
         
     | 
| 
       873 
900 
     | 
    
         
             
              def tokenize!
         
     | 
| 
       874 
     | 
    
         
            -
                 
     | 
| 
      
 901 
     | 
    
         
            +
                Tokenizer.new(pattern).to_a
         
     | 
| 
       875 
902 
     | 
    
         
             
              end
         
     | 
| 
       876 
903 
     | 
    
         | 
| 
       877 
904 
     | 
    
         
             
              def tokens
         
     | 
    
        data/uri_template.gemspec
    CHANGED
    
    | 
         @@ -1,12 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       2 
2 
     | 
    
         
             
              s.name = 'uri_template'
         
     | 
| 
       3 
     | 
    
         
            -
              s.version = '0.0 
     | 
| 
       4 
     | 
    
         
            -
              s.date = '2011-11- 
     | 
| 
      
 3 
     | 
    
         
            +
              s.version = '0.1.0'
         
     | 
| 
      
 4 
     | 
    
         
            +
              s.date = '2011-11-02'
         
     | 
| 
       5 
5 
     | 
    
         
             
              s.authors = ["HannesG"]
         
     | 
| 
       6 
6 
     | 
    
         
             
              s.email = %q{hannes.georg@googlemail.com}
         
     | 
| 
       7 
7 
     | 
    
         
             
              s.summary = 'A templating system for URIs.'
         
     | 
| 
       8 
8 
     | 
    
         
             
              s.homepage = 'http://github.com/hannesg/uri_template'
         
     | 
| 
       9 
     | 
    
         
            -
              s.description = 'A templating system for URIs, which implements http://tools.ietf.org/html/draft-gregorio-uritemplate-07 . An implementation of an older version of that spec is known as addressable. This  
     | 
| 
      
 9 
     | 
    
         
            +
              s.description = 'A templating system for URIs, which implements http://tools.ietf.org/html/draft-gregorio-uritemplate-07 . An implementation of an older version of that spec is known as addressable. This gem however is intended to be extended when newer specs evolve. For now only draft 7 is supported. Downside: only for 1.9 compatible since it uses Oniguruma regexp.'
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
              s.require_paths = ['lib']
         
     | 
| 
       12 
12 
     | 
    
         | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: uri_template
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.0 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
6 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       7 
7 
     | 
    
         
             
            authors:
         
     | 
| 
         @@ -9,11 +9,11 @@ authors: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date: 2011-11- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2011-11-02 00:00:00.000000000Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: rspec
         
     | 
| 
       16 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: &14484700 !ruby/object:Gem::Requirement
         
     | 
| 
       17 
17 
     | 
    
         
             
                none: false
         
     | 
| 
       18 
18 
     | 
    
         
             
                requirements:
         
     | 
| 
       19 
19 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -21,10 +21,10 @@ dependencies: 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       22 
22 
     | 
    
         
             
              type: :development
         
     | 
| 
       23 
23 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       24 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: *14484700
         
     | 
| 
       25 
25 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       26 
26 
     | 
    
         
             
              name: yard
         
     | 
| 
       27 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 27 
     | 
    
         
            +
              requirement: &14482080 !ruby/object:Gem::Requirement
         
     | 
| 
       28 
28 
     | 
    
         
             
                none: false
         
     | 
| 
       29 
29 
     | 
    
         
             
                requirements:
         
     | 
| 
       30 
30 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -32,18 +32,19 @@ dependencies: 
     | 
|
| 
       32 
32 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       33 
33 
     | 
    
         
             
              type: :development
         
     | 
| 
       34 
34 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       35 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 35 
     | 
    
         
            +
              version_requirements: *14482080
         
     | 
| 
       36 
36 
     | 
    
         
             
            description: ! 'A templating system for URIs, which implements http://tools.ietf.org/html/draft-gregorio-uritemplate-07
         
     | 
| 
       37 
37 
     | 
    
         
             
              . An implementation of an older version of that spec is known as addressable. This
         
     | 
| 
       38 
     | 
    
         
            -
               
     | 
| 
       39 
     | 
    
         
            -
               
     | 
| 
       40 
     | 
    
         
            -
              regexp.'
         
     | 
| 
      
 38 
     | 
    
         
            +
              gem however is intended to be extended when newer specs evolve. For now only draft
         
     | 
| 
      
 39 
     | 
    
         
            +
              7 is supported. Downside: only for 1.9 compatible since it uses Oniguruma regexp.'
         
     | 
| 
       41 
40 
     | 
    
         
             
            email: hannes.georg@googlemail.com
         
     | 
| 
       42 
41 
     | 
    
         
             
            executables: []
         
     | 
| 
       43 
42 
     | 
    
         
             
            extensions: []
         
     | 
| 
       44 
43 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       45 
44 
     | 
    
         
             
            files:
         
     | 
| 
       46 
45 
     | 
    
         
             
            - lib/uri_template.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/uri_template/colon.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/uri_template/draft2.rb
         
     | 
| 
       47 
48 
     | 
    
         
             
            - lib/uri_template/draft7.rb
         
     | 
| 
       48 
49 
     | 
    
         
             
            - lib/uri_template/utils.rb
         
     | 
| 
       49 
50 
     | 
    
         
             
            - uri_template.gemspec
         
     |