uri_template 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ # 0.2.1 - 30.12.2011
2
+ * Compatibility: Works now with MRI 1.8.7 and REE
3
+
1
4
  # 0.2.0 - 03.12.2011
2
5
  * Reworked the escaping mechanism
3
6
  + escape_utils can now be used to boost escape/unescape performance
@@ -18,66 +18,74 @@
18
18
  # A base module for all implementations of a uri template.
19
19
  module URITemplate
20
20
 
21
+ # @private
22
+ # Should we use \u.... or \x.. in regexps?
23
+ SUPPORTS_UNICODE_CHARS = begin
24
+ rx = eval('/\u0020/')
25
+ !!(rx =~ " ")
26
+ rescue SyntaxError
27
+ false
28
+ end
29
+
21
30
  # This should make it possible to do basic analysis independently from the concrete type.
22
31
  module Token
23
-
32
+
24
33
  def size
25
34
  variables.size
26
35
  end
27
-
36
+
28
37
  end
29
-
38
+
30
39
  # A module which all literal tokens should include.
31
40
  module Literal
32
-
41
+
33
42
  include Token
34
-
43
+
35
44
  attr_reader :string
36
-
45
+
37
46
  def literal?
38
47
  true
39
48
  end
40
-
49
+
41
50
  def expression?
42
51
  false
43
52
  end
44
-
53
+
45
54
  def variables
46
55
  []
47
56
  end
48
-
57
+
49
58
  def size
50
59
  0
51
60
  end
52
-
61
+
53
62
  def expand(*_)
54
63
  return string
55
64
  end
56
-
65
+
57
66
  end
58
-
59
-
67
+
60
68
  # A module which all non-literal tokens should include.
61
69
  module Expression
62
-
70
+
63
71
  include Token
64
-
72
+
65
73
  attr_reader :variables
66
-
74
+
67
75
  def literal?
68
76
  false
69
77
  end
70
-
78
+
71
79
  def expression?
72
80
  true
73
81
  end
74
-
82
+
75
83
  end
76
84
 
77
85
  autoload :Utils, 'uri_template/utils'
78
86
  autoload :Draft7, 'uri_template/draft7'
79
87
  autoload :Colon, 'uri_template/colon'
80
-
88
+
81
89
  # A hash with all available implementations.
82
90
  # Currently the only implementation is :draft7. But there also aliases :default and :latest available. This should make it possible to add newer specs later.
83
91
  # @see resolve_class
@@ -87,7 +95,7 @@ module URITemplate
87
95
  :colon => :Colon,
88
96
  :latest => :Draft7
89
97
  }
90
-
98
+
91
99
  # Looks up which implementation to use.
92
100
  # Extracts all symbols from args and looks up the first in {VERSIONS}.
93
101
  #
@@ -105,7 +113,7 @@ module URITemplate
105
113
  raise ArgumentError, "Unknown template version #{version.inspect}, defined versions: #{VERSIONS.keys.inspect}" unless VERSIONS.key?(version)
106
114
  return self.const_get(VERSIONS[version]), rest
107
115
  end
108
-
116
+
109
117
  # Creates an uri template using an implementation.
110
118
  # The args should at least contain a pattern string.
111
119
  # Symbols in the args are used to determine the actual implementation.
@@ -121,7 +129,7 @@ module URITemplate
121
129
  klass, rest = resolve_class(*args)
122
130
  return klass.new(*rest)
123
131
  end
124
-
132
+
125
133
  # Tries to convert the given argument into an {URITemplate}.
126
134
  # Returns nil if this fails.
127
135
  #
@@ -135,7 +143,7 @@ module URITemplate
135
143
  return nil
136
144
  end
137
145
  end
138
-
146
+
139
147
  # Same as {.try_convert} but raises an ArgumentError when the given argument could not be converted.
140
148
  #
141
149
  # @raise ArgumentError if the argument is unconvertable
@@ -147,7 +155,7 @@ module URITemplate
147
155
  end
148
156
  return o
149
157
  end
150
-
158
+
151
159
  # Tries to coerce two URITemplates into a common representation.
152
160
  # Returns an array with two {URITemplate}s and two booleans indicating which of the two were converted or raises an ArgumentError.
153
161
  #
@@ -180,7 +188,7 @@ module URITemplate
180
188
  raise ArgumentError, "Expected at least on URITemplate, but got #{a.inspect} and #{b.inspect}" unless a.kind_of? URITemplate or b.kind_of? URITemplate
181
189
  raise ArgumentError, "Cannot coerce #{a.inspect} and #{b.inspect} into a common representation."
182
190
  end
183
-
191
+
184
192
  # Applies a method to a URITemplate with another URITemplate as argument.
185
193
  # This is a useful shorthand since both URITemplates are automatically coerced.
186
194
  #
@@ -194,11 +202,11 @@ module URITemplate
194
202
  a,b,_,_ = self.coerce(a,b)
195
203
  a.send(method,b,*args)
196
204
  end
197
-
205
+
198
206
  # A base class for all errors which will be raised upon invalid syntax.
199
207
  module Invalid
200
208
  end
201
-
209
+
202
210
  # Expands this uri template with the given variables.
203
211
  # The variables should be converted to strings using {Utils#object_to_param}.
204
212
  # @raise {Unconvertable} if a variable could not be converted to a string.
@@ -209,19 +217,19 @@ module URITemplate
209
217
  part.expand(variables)
210
218
  }.join
211
219
  end
212
-
220
+
213
221
  # @abstract
214
222
  # 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.
215
223
  def type
216
224
  raise "Please implement #type on #{self.class.inspect}."
217
225
  end
218
-
226
+
219
227
  # @abstract
220
228
  # Returns the tokens of this templates. Tokens should include either {Literal} or {Expression}.
221
229
  def tokens
222
230
  raise "Please implement #tokens on #{self.class.inspect}."
223
231
  end
224
-
232
+
225
233
  # Returns an array containing all variables. Repeated variables are ignored. The concrete order of the variables may change.
226
234
  # @example
227
235
  # URITemplate.new('{foo}{bar}{baz}').variables #=> ['foo','bar','baz']
@@ -231,7 +239,7 @@ module URITemplate
231
239
  def variables
232
240
  @variables ||= tokens.select(&:expression?).map(&:variables).flatten.uniq
233
241
  end
234
-
242
+
235
243
  # Returns the number of static characters in this template.
236
244
  # This method is useful for routing, since it's often pointful to use the url with fewer variable characters.
237
245
  # 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.
@@ -245,7 +253,7 @@ module URITemplate
245
253
  def static_characters
246
254
  @static_characters ||= tokens.select(&:literal?).map{|t| t.string.size }.inject(0,:+)
247
255
  end
248
-
256
+
249
257
  # Returns whether this uri-template is absolute.
250
258
  # This is detected by checking for "://".
251
259
  #
@@ -260,14 +268,14 @@ module URITemplate
260
268
  end
261
269
  if read_chars =~ /^[a-z]+:\/\//i
262
270
  return @absolute = true
263
- elsif read_chars =~ /(?<!:|\/)\/(?!\/)/
271
+ elsif read_chars =~ /(^|[^:\/])\/(?!\/)/
264
272
  return @absolute = false
265
273
  end
266
274
  end
267
-
275
+
268
276
  return @absolute = false
269
277
  end
270
-
278
+
271
279
  # Opposite of {#absolute?}
272
280
  def relative?
273
281
  !absolute?
@@ -23,7 +23,7 @@ require 'uri_template/utils'
23
23
  # A colon based template denotes variables with a colon.
24
24
  # This template type is realy basic but having just on template type was a bit weird.
25
25
  module URITemplate
26
-
26
+
27
27
  class Colon
28
28
 
29
29
  include URITemplate
@@ -31,46 +31,46 @@ class Colon
31
31
  VAR = /(?:\{:([a-z]+)\}|:([a-z]+)(?![a-z]))/u
32
32
 
33
33
  class Token
34
-
34
+
35
35
  class Variable < self
36
-
36
+
37
37
  include URITemplate::Expression
38
-
38
+
39
39
  attr_reader :name
40
-
40
+
41
41
  def initialize(name)
42
42
  @name = name
43
43
  @variables = [name]
44
44
  end
45
-
45
+
46
46
  def expand(vars)
47
47
  return Utils.escape_url(Utils.object_to_param(vars[@name]))
48
48
  end
49
-
49
+
50
50
  def to_r
51
51
  return ['([^/]*?)'].join
52
52
  end
53
-
53
+
54
54
  end
55
-
55
+
56
56
  class Static < self
57
-
57
+
58
58
  include URITemplate::Literal
59
-
59
+
60
60
  def initialize(str)
61
61
  @string = str
62
62
  end
63
-
63
+
64
64
  def expand(_)
65
65
  return @string
66
66
  end
67
-
67
+
68
68
  def to_r
69
69
  return Regexp.escape(@string)
70
70
  end
71
-
71
+
72
72
  end
73
-
73
+
74
74
  end
75
75
 
76
76
  attr_reader :pattern
@@ -94,7 +94,7 @@ class Colon
94
94
  def initialize(pattern)
95
95
  @pattern = pattern
96
96
  end
97
-
97
+
98
98
  # Extracts variables from an uri.
99
99
  #
100
100
  # @param String uri
@@ -106,19 +106,19 @@ class Colon
106
106
  [v, Utils.unescape_url(md[i+1])]
107
107
  }.flatten(1) ]
108
108
  end
109
-
109
+
110
110
  def type
111
111
  :colon
112
112
  end
113
-
113
+
114
114
  def to_r
115
115
  @regexp ||= Regexp.new('\A' + tokens.map(&:to_r).join + '\z', Utils::KCODE_UTF8)
116
116
  end
117
-
117
+
118
118
  def tokens
119
119
  @tokens ||= tokenize!
120
120
  end
121
-
121
+
122
122
  # Tries to concatenate two templates, as if they were path segments.
123
123
  # Removes double slashes or inserts one if they are missing.
124
124
  #
@@ -136,7 +136,7 @@ class Colon
136
136
  end
137
137
  return self.class.new( File.join( this.pattern, other.pattern ) )
138
138
  end
139
-
139
+
140
140
  protected
141
141
 
142
142
  def tokenize!
@@ -29,127 +29,127 @@ class URITemplate::Draft7
29
29
 
30
30
  include URITemplate
31
31
  extend Forwardable
32
-
32
+
33
33
  # @private
34
34
  Utils = URITemplate::Utils
35
-
36
- # @private
37
- # \/ - unicode ctrl-chars ( \p{Cc} doen't work with rbx
38
- LITERAL = /^([^"'%<>\\^`{|}\s\p{Cntrl}]|%\h\h)+/u
39
-
35
+
36
+ if SUPPORTS_UNICODE_CHARS
37
+ # @private
38
+ # \/ - unicode ctrl-chars
39
+ LITERAL = /([^"'%<>\\^`{|}\u0000-\u001F\u007F-\u009F\s]|%[0-9a-fA-F]{2})+/u
40
+ else
41
+ # @private
42
+ LITERAL = Regexp.compile('([^"\'%<>\\\\^`{|}\x00-\x1F\x7F-\x9F\s]|%[0-9a-fA-F]{2})+',Utils::KCODE_UTF8)
43
+ end
44
+
40
45
  # @private
41
46
  CHARACTER_CLASSES = {
42
-
47
+
43
48
  :unreserved => {
44
- :unencoded => /([^A-Za-z0-9\-\._])/u,
45
- :class => '(?:[A-Za-z0-9\-\._]|%\h\h)',
46
-
47
- :class_name => 'c_u_',
49
+ :class => '(?:[A-Za-z0-9\-\._]|%[0-9a-fA-F]{2})',
48
50
  :grabs_comma => false
49
51
  },
50
52
  :unreserved_reserved_pct => {
51
- :unencoded => /([^A-Za-z0-9\-\._:\/?#\[\]@!\$%'\(\)*+,;=]|%(?!\h\h))/u,
52
- :class => '(?:[A-Za-z0-9\-\._:\/?#\[\]@!\$%\'\(\)*+,;=]|%\h\h)',
53
- :class_name => 'c_urp_',
53
+ :class => '(?:[A-Za-z0-9\-\._:\/?#\[\]@!\$%\'\(\)*+,;=]|%[0-9a-fA-F]{2})',
54
54
  :grabs_comma => true
55
55
  },
56
-
56
+
57
57
  :varname => {
58
58
  :class => '(?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*?',
59
59
  :class_name => 'c_vn_'
60
60
  }
61
-
61
+
62
62
  }
63
-
63
+
64
64
  # Specifies that no processing should be done upon extraction.
65
65
  # @see #extract
66
66
  NO_PROCESSING = []
67
-
67
+
68
68
  # Specifies that the extracted values should be processed.
69
69
  # @see #extract
70
70
  CONVERT_VALUES = [:convert_values]
71
-
71
+
72
72
  # Specifies that the extracted variable list should be processed.
73
73
  # @see #extract
74
74
  CONVERT_RESULT = [:convert_result]
75
-
75
+
76
76
  # Default processing. Means: convert values and the list itself.
77
77
  # @see #extract
78
78
  DEFAULT_PROCESSING = CONVERT_VALUES + CONVERT_RESULT
79
-
79
+
80
80
  # @private
81
81
  VAR = Regexp.compile(<<'__REGEXP__'.strip, Utils::KCODE_UTF8)
82
82
  ((?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*)(\*)?(?::(\d+))?
83
83
  __REGEXP__
84
-
84
+
85
85
  # @private
86
86
  EXPRESSION = Regexp.compile(<<'__REGEXP__'.strip, Utils::KCODE_UTF8)
87
87
  \{([+#\./;?&]?)((?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*\*?(?::\d+)?(?:,(?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*\*?(?::\d+)?)*)\}
88
88
  __REGEXP__
89
89
 
90
90
  # @private
91
- URI = Regexp.compile(<<'__REGEXP__'.strip, Utils::KCODE_UTF8)
92
- \A(([^"'%<>^`{|}\s\p{Cntrl}]|%\h\h)+|\{([+#\./;?&]?)((?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*\*?(?::\d+)?(?:,(?:[a-zA-Z_]|%[0-9a-fA-F]{2})(?:[a-zA-Z_\.]|%[0-9a-fA-F]{2})*\*?(?::\d+)?)*)\})*\z
91
+ URI = Regexp.compile(<<__REGEXP__.strip, Utils::KCODE_UTF8)
92
+ \\A(#{LITERAL.source}|#{EXPRESSION.source})*\\z
93
93
  __REGEXP__
94
94
 
95
95
  SLASH = ?/
96
-
96
+
97
97
  # @private
98
98
  class Token
99
99
  end
100
-
100
+
101
101
  # @private
102
102
  class Literal < Token
103
-
103
+
104
104
  include URITemplate::Literal
105
-
105
+
106
106
  def initialize(string)
107
107
  @string = string
108
108
  end
109
-
109
+
110
110
  def level
111
111
  1
112
112
  end
113
-
113
+
114
114
  def arity
115
115
  0
116
116
  end
117
-
117
+
118
118
  def to_r_source(*_)
119
119
  Regexp.escape(@string)
120
120
  end
121
-
121
+
122
122
  def to_s
123
123
  @string
124
124
  end
125
-
125
+
126
126
  end
127
127
 
128
128
  # @private
129
129
  class Expression < Token
130
-
130
+
131
131
  include URITemplate::Expression
132
-
132
+
133
133
  attr_reader :variables, :max_length
134
-
134
+
135
135
  def initialize(vars)
136
136
  @variable_specs = vars
137
137
  @variables = vars.map(&:first)
138
138
  @variables.uniq!
139
139
  end
140
-
140
+
141
141
  PREFIX = ''.freeze
142
142
  SEPARATOR = ','.freeze
143
143
  PAIR_CONNECTOR = '='.freeze
144
144
  PAIR_IF_EMPTY = true
145
145
  LIST_CONNECTOR = ','.freeze
146
146
  BASE_LEVEL = 1
147
-
147
+
148
148
  CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved]
149
-
149
+
150
150
  NAMED = false
151
151
  OPERATOR = ''
152
-
152
+
153
153
  def level
154
154
  if @variable_specs.none?{|_,expand,ml| expand || (ml > 0) }
155
155
  if @variable_specs.size == 1
@@ -161,16 +161,16 @@ __REGEXP__
161
161
  return 4
162
162
  end
163
163
  end
164
-
164
+
165
165
  def arity
166
166
  @variable_specs.size
167
167
  end
168
-
168
+
169
169
  def expand( vars )
170
170
  result = []
171
171
  @variable_specs.each{| var, expand , max_length |
172
172
  unless vars[var].nil?
173
- if vars[var].kind_of? Hash
173
+ if vars[var].kind_of?(Hash) or Utils.pair_array?(vars[var])
174
174
  result.push( *transform_hash(var, vars[var], expand, max_length) )
175
175
  elsif vars[var].kind_of? Array
176
176
  result.push( *transform_array(var, vars[var], expand, max_length) )
@@ -189,11 +189,11 @@ __REGEXP__
189
189
  return ''
190
190
  end
191
191
  end
192
-
192
+
193
193
  def to_s
194
194
  return '{' + self.class::OPERATOR + @variable_specs.map{|name,expand,max_length| name + (expand ? '*': '') + (max_length > 0 ? (':' + max_length.to_s) : '') }.join(',') + '}'
195
195
  end
196
-
196
+
197
197
  #TODO: certain things after a slurpy variable will never get matched. therefore, it's pointless to add expressions for them
198
198
  #TODO: variables, which appear twice could be compacted, don't they?
199
199
  def to_r_source
@@ -203,11 +203,11 @@ __REGEXP__
203
203
  i = 0
204
204
  if self.class::NAMED
205
205
  @variable_specs.each{| var, expand , max_length |
206
- value = "(?:#{self.class::CHARACTER_CLASS[:class]}|,)#{(max_length > 0)?'{,'+max_length.to_s+'}':'*'}"
206
+ value = "(?:#{self.class::CHARACTER_CLASS[:class]}|,)#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*'}"
207
207
  if expand
208
208
  #if self.class::PAIR_IF_EMPTY
209
209
  pair = "(?:#{CHARACTER_CLASSES[:varname][:class]}#{Regexp.escape(self.class::PAIR_CONNECTOR)})?#{value}"
210
-
210
+
211
211
  if first
212
212
  source << "((?:#{pair})(?:#{Regexp.escape(self.class::SEPARATOR)}#{pair})*)"
213
213
  else
@@ -219,14 +219,14 @@ __REGEXP__
219
219
  else
220
220
  pair = "#{Regexp.escape(var)}(#{Regexp.escape(self.class::PAIR_CONNECTOR)}#{value}|)"
221
221
  end
222
-
222
+
223
223
  if first
224
224
  source << "(?:#{pair})"
225
225
  else
226
226
  source << "(?:#{Regexp.escape(self.class::SEPARATOR)}#{pair})?"
227
227
  end
228
228
  end
229
-
229
+
230
230
  first = false
231
231
  i = i+1
232
232
  }
@@ -235,20 +235,20 @@ __REGEXP__
235
235
  last = (vs == i)
236
236
  if expand
237
237
  # could be list or map, too
238
- value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{,'+max_length.to_s+'}':'*'}"
239
-
238
+ value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*'}"
239
+
240
240
  pair = "(?:#{CHARACTER_CLASSES[:varname][:class]}#{Regexp.escape(self.class::PAIR_CONNECTOR)})?#{value}"
241
-
241
+
242
242
  value = "#{pair}(?:#{Regexp.escape(self.class::SEPARATOR)}#{pair})*"
243
243
  elsif last
244
244
  # the last will slurp lists
245
245
  if self.class::CHARACTER_CLASS[:grabs_comma]
246
- value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{,'+max_length.to_s+'}':'*?'}"
246
+ value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*?'}"
247
247
  else
248
- value = "(?:#{self.class::CHARACTER_CLASS[:class]}|,)#{(max_length > 0)?'{,'+max_length.to_s+'}':'*?'}"
248
+ value = "(?:#{self.class::CHARACTER_CLASS[:class]}|,)#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*?'}"
249
249
  end
250
250
  else
251
- value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{,'+max_length.to_s+'}':'*?'}"
251
+ value = "#{self.class::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*?'}"
252
252
  end
253
253
  if first
254
254
  source << "(#{value})"
@@ -261,7 +261,7 @@ __REGEXP__
261
261
  end
262
262
  return '(?:' + Regexp.escape(self.class::PREFIX) + source.join + ')?'
263
263
  end
264
-
264
+
265
265
  def extract(position,matched)
266
266
  name, expand, max_length = @variable_specs[position]
267
267
  if matched.nil?
@@ -302,38 +302,38 @@ __REGEXP__
302
302
  elsif self.class::NAMED
303
303
  return [ [ name, decode( matched[1..-1] ) ] ]
304
304
  end
305
-
305
+
306
306
  return [ [ name, decode( matched ) ] ]
307
307
  end
308
-
308
+
309
309
  protected
310
-
310
+
311
311
  module ClassMethods
312
-
312
+
313
313
  def hash_extractor(max_length)
314
314
  @hash_extractors ||= {}
315
315
  @hash_extractors[max_length] ||= begin
316
- value = "#{self::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{,'+max_length.to_s+'}':'*?'}"
316
+ value = "#{self::CHARACTER_CLASS[:class]}#{(max_length > 0)?'{0,'+max_length.to_s+'}':'*?'}"
317
317
  pair = "(#{CHARACTER_CLASSES[:varname][:class]}#{Regexp.escape(self::PAIR_CONNECTOR)})?(#{value})"
318
318
  source = "\\A#{Regexp.escape(self::SEPARATOR)}?" + pair + "(\\z|#{Regexp.escape(self::SEPARATOR)}(?!#{Regexp.escape(self::SEPARATOR)}))"
319
319
  Regexp.new( source , Utils::KCODE_UTF8)
320
320
  end
321
321
  end
322
-
322
+
323
323
  end
324
-
324
+
325
325
  extend ClassMethods
326
-
326
+
327
327
  def escape(x)
328
328
  Utils.escape_url(Utils.object_to_param(x))
329
329
  end
330
-
330
+
331
331
  def unescape(x)
332
332
  Utils.unescape_url(x)
333
333
  end
334
-
334
+
335
335
  SPLITTER = /^(?:,(,*)|([^,]+))/
336
-
336
+
337
337
  def decode(x, split = true)
338
338
  if x.nil?
339
339
  if self.class::PAIR_IF_EMPTY
@@ -362,17 +362,17 @@ __REGEXP__
362
362
  unescape(x)
363
363
  end
364
364
  end
365
-
365
+
366
366
  def cut(str,chars)
367
367
  if chars > 0
368
- md = Regexp.compile("\\A#{self.class::CHARACTER_CLASS[:class]}{,#{chars.to_s}}", Utils::KCODE_UTF8).match(str)
368
+ md = Regexp.compile("\\A#{self.class::CHARACTER_CLASS[:class]}{0,#{chars.to_s}}", Utils::KCODE_UTF8).match(str)
369
369
  #TODO: handle invalid matches
370
370
  return md[0]
371
371
  else
372
372
  return str
373
373
  end
374
374
  end
375
-
375
+
376
376
  def pair(key, value, max_length = 0)
377
377
  ek = escape(key)
378
378
  ev = escape(value)
@@ -382,7 +382,7 @@ __REGEXP__
382
382
  return ek + self.class::PAIR_CONNECTOR + cut( ev, max_length )
383
383
  end
384
384
  end
385
-
385
+
386
386
  def transform_hash(name, hsh, expand , max_length)
387
387
  if expand
388
388
  hsh.map{|key,value| pair(key,value) }
@@ -392,7 +392,7 @@ __REGEXP__
392
392
  [ (self.class::NAMED ? escape(name)+self.class::PAIR_CONNECTOR : '' ) + hsh.map{|key,value| escape(key)+self.class::LIST_CONNECTOR+escape(value) }.join(self.class::LIST_CONNECTOR) ]
393
393
  end
394
394
  end
395
-
395
+
396
396
  def transform_array(name, ary, expand , max_length)
397
397
  if expand
398
398
  ary.map{|value| escape(value) }
@@ -402,91 +402,91 @@ __REGEXP__
402
402
  [ (self.class::NAMED ? escape(name)+self.class::PAIR_CONNECTOR : '' ) + ary.map{|value| escape(value) }.join(self.class::LIST_CONNECTOR) ]
403
403
  end
404
404
  end
405
-
405
+
406
406
  class Reserved < self
407
-
407
+
408
408
  CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved_reserved_pct]
409
409
  OPERATOR = '+'.freeze
410
410
  BASE_LEVEL = 2
411
-
411
+
412
412
  def escape(x)
413
413
  Utils.escape_uri(Utils.object_to_param(x))
414
414
  end
415
-
415
+
416
416
  def unescape(x)
417
417
  Utils.unescape_uri(x)
418
418
  end
419
-
419
+
420
420
  end
421
-
421
+
422
422
  class Fragment < self
423
-
423
+
424
424
  CHARACTER_CLASS = CHARACTER_CLASSES[:unreserved_reserved_pct]
425
425
  PREFIX = '#'.freeze
426
426
  OPERATOR = '#'.freeze
427
427
  BASE_LEVEL = 2
428
-
428
+
429
429
  def escape(x)
430
430
  Utils.escape_uri(Utils.object_to_param(x))
431
431
  end
432
-
432
+
433
433
  def unescape(x)
434
434
  Utils.unescape_uri(x)
435
435
  end
436
-
436
+
437
437
  end
438
-
438
+
439
439
  class Label < self
440
-
440
+
441
441
  SEPARATOR = '.'.freeze
442
442
  PREFIX = '.'.freeze
443
443
  OPERATOR = '.'.freeze
444
444
  BASE_LEVEL = 3
445
-
445
+
446
446
  end
447
-
447
+
448
448
  class Path < self
449
-
449
+
450
450
  SEPARATOR = '/'.freeze
451
451
  PREFIX = '/'.freeze
452
452
  OPERATOR = '/'.freeze
453
453
  BASE_LEVEL = 3
454
-
454
+
455
455
  end
456
-
456
+
457
457
  class PathParameters < self
458
-
458
+
459
459
  SEPARATOR = ';'.freeze
460
460
  PREFIX = ';'.freeze
461
461
  NAMED = true
462
462
  PAIR_IF_EMPTY = false
463
463
  OPERATOR = ';'.freeze
464
464
  BASE_LEVEL = 3
465
-
465
+
466
466
  end
467
-
467
+
468
468
  class FormQuery < self
469
-
469
+
470
470
  SEPARATOR = '&'.freeze
471
471
  PREFIX = '?'.freeze
472
472
  NAMED = true
473
473
  OPERATOR = '?'.freeze
474
474
  BASE_LEVEL = 3
475
-
475
+
476
476
  end
477
-
477
+
478
478
  class FormQueryContinuation < self
479
-
479
+
480
480
  SEPARATOR = '&'.freeze
481
481
  PREFIX = '&'.freeze
482
482
  NAMED = true
483
483
  OPERATOR = '&'.freeze
484
484
  BASE_LEVEL = 3
485
-
485
+
486
486
  end
487
-
487
+
488
488
  end
489
-
489
+
490
490
  # @private
491
491
  OPERATORS = {
492
492
  '' => Expression,
@@ -498,33 +498,33 @@ __REGEXP__
498
498
  '?' => Expression::FormQuery,
499
499
  '&' => Expression::FormQueryContinuation
500
500
  }
501
-
501
+
502
502
  # This error is raised when an invalid pattern was given.
503
503
  class Invalid < StandardError
504
-
504
+
505
505
  include URITemplate::Invalid
506
-
506
+
507
507
  attr_reader :pattern, :position
508
-
508
+
509
509
  def initialize(source, position)
510
510
  @pattern = pattern
511
511
  @position = position
512
512
  super("Invalid expression found in #{source.inspect} at #{position}: '#{source[position..-1]}'")
513
513
  end
514
-
514
+
515
515
  end
516
-
516
+
517
517
  # @private
518
518
  class Tokenizer
519
-
519
+
520
520
  include Enumerable
521
-
521
+
522
522
  attr_reader :source
523
-
523
+
524
524
  def initialize(source)
525
525
  @source = source
526
526
  end
527
-
527
+
528
528
  def each
529
529
  if !block_given?
530
530
  return Enumerator.new(self)
@@ -551,12 +551,12 @@ __REGEXP__
551
551
  end
552
552
  end
553
553
  end
554
-
554
+
555
555
  end
556
-
556
+
557
557
  # The class methods for all draft7 templates.
558
558
  module ClassMethods
559
-
559
+
560
560
  # Tries to convert the given param in to a instance of {Draft7}
561
561
  # It basically passes thru instances of that class, parses strings and return nil on everything else.
562
562
  #
@@ -586,8 +586,7 @@ __REGEXP__
586
586
  return nil
587
587
  end
588
588
  end
589
-
590
-
589
+
591
590
  # Like {.try_convert}, but raises an ArgumentError, when the conversion failed.
592
591
  #
593
592
  # @raise ArgumentError
@@ -599,7 +598,7 @@ __REGEXP__
599
598
  return o
600
599
  end
601
600
  end
602
-
601
+
603
602
  # Tests whether a given pattern is a valid template pattern.
604
603
  # @example
605
604
  # URITemplate::Draft7.valid? 'foo' #=> true
@@ -608,13 +607,13 @@ __REGEXP__
608
607
  def valid?(pattern)
609
608
  URI === pattern
610
609
  end
611
-
610
+
612
611
  end
613
-
612
+
614
613
  extend ClassMethods
615
-
614
+
616
615
  attr_reader :options
617
-
616
+
618
617
  # @param String,Array either a pattern as String or an Array of tokens
619
618
  # @param Hash some options
620
619
  # @option :lazy If true the pattern will be parsed on first access, this also means that syntax errors will not be detected unless accessed.
@@ -633,7 +632,7 @@ __REGEXP__
633
632
  raise ArgumentError, "Expected to receive a pattern string, but got #{pattern_or_tokens.inspect}"
634
633
  end
635
634
  end
636
-
635
+
637
636
  # @method expand(variables = {})
638
637
  # Expands the template with the given variables.
639
638
  # The expansion should be compatible to uritemplate spec draft 7 ( http://tools.ietf.org/html/draft-gregorio-uritemplate-07 ).
@@ -648,7 +647,7 @@ __REGEXP__
648
647
  #
649
648
  # @param variables Hash
650
649
  # @return String
651
-
650
+
652
651
  # Compiles this template into a regular expression which can be used to test whether a given uri matches this template. This template is also used for {#===}.
653
652
  #
654
653
  # @example
@@ -666,8 +665,7 @@ __REGEXP__
666
665
  Regexp.new( source.join, Utils::KCODE_UTF8)
667
666
  end
668
667
  end
669
-
670
-
668
+
671
669
  # Extracts variables from a uri ( given as string ) or an instance of MatchData ( which was matched by the regexp of this template.
672
670
  # The actual result depends on the value of post_processing.
673
671
  # This argument specifies whether pair arrays should be converted to hashes.
@@ -724,25 +722,25 @@ __REGEXP__
724
722
  if block_given?
725
723
  return yield result
726
724
  end
727
-
725
+
728
726
  return result
729
727
  end
730
728
  end
731
-
729
+
732
730
  # Extracts variables without any proccessing.
733
731
  # This is equivalent to {#extract} with options {NO_PROCESSING}.
734
732
  # @see #extract
735
733
  def extract_simple(uri_or_match)
736
734
  extract( uri_or_match, NO_PROCESSING )
737
735
  end
738
-
736
+
739
737
  # Returns the pattern for this template.
740
738
  def pattern
741
739
  @pattern ||= tokens.map(&:to_s).join
742
740
  end
743
-
741
+
744
742
  alias to_s pattern
745
-
743
+
746
744
  # Compares two template patterns.
747
745
  def ==(o)
748
746
  this, other, this_converted, _ = URITemplate.coerce( self, o )
@@ -751,12 +749,12 @@ __REGEXP__
751
749
  end
752
750
  return this.pattern == other.pattern
753
751
  end
754
-
752
+
755
753
  # @method ===(uri)
756
754
  # Alias for to_r.=== . Tests whether this template matches a given uri.
757
755
  # @return TrueClass, FalseClass
758
756
  def_delegators :to_r, :===
759
-
757
+
760
758
  # @method match(uri)
761
759
  # Alias for to_r.match . Matches this template against the given uri.
762
760
  # @yield MatchData
@@ -774,7 +772,7 @@ __REGEXP__
774
772
  def type
775
773
  :draft7
776
774
  end
777
-
775
+
778
776
  # 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.
779
777
  # Basically this is defined as:
780
778
  #
@@ -797,7 +795,7 @@ __REGEXP__
797
795
  def level
798
796
  tokens.map(&:level).max
799
797
  end
800
-
798
+
801
799
  # Tries to concatenate two templates, as if they were path segments.
802
800
  # Removes double slashes or insert one if they are missing.
803
801
  #
@@ -813,11 +811,11 @@ __REGEXP__
813
811
  if this_converted
814
812
  return this / other
815
813
  end
816
-
814
+
817
815
  if other.absolute?
818
816
  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."
819
817
  end
820
-
818
+
821
819
  if other.pattern == ''
822
820
  return self
823
821
  end
@@ -848,7 +846,7 @@ __REGEXP__
848
846
  end
849
847
  end
850
848
  end
851
-
849
+
852
850
  if other.tokens.first.kind_of?(Literal)
853
851
  if other.tokens.first.string[0] == SLASH
854
852
  return self.class.new( self.tokens + other.tokens )
@@ -861,7 +859,7 @@ __REGEXP__
861
859
  return self.class.new( self.tokens + [Literal.new('/')] + other.tokens )
862
860
  end
863
861
  end
864
-
862
+
865
863
  # Returns an array containing a the template tokens.
866
864
  def tokens
867
865
  @tokens ||= tokenize!
@@ -872,11 +870,11 @@ protected
872
870
  def tokenize!
873
871
  Tokenizer.new(pattern).to_a
874
872
  end
875
-
873
+
876
874
  def arity
877
875
  @arity ||= tokens.inject(0){|a,t| a + t.arity }
878
876
  end
879
-
877
+
880
878
  # @private
881
879
  def extract_matchdata(matchdata, post_processing)
882
880
  bc = 1
@@ -908,7 +906,5 @@ protected
908
906
  end
909
907
  end
910
908
  end
911
-
912
- end
913
-
914
909
 
910
+ end