uri_template 0.4.0 → 0.5.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.md +53 -0
- data/README.md +56 -0
- data/lib/uri_template/colon.rb +88 -29
- data/lib/uri_template/expression.rb +33 -0
- data/lib/uri_template/literal.rb +53 -0
- data/lib/uri_template/rfc6570/expression/named.rb +72 -0
- data/lib/uri_template/rfc6570/expression/unnamed.rb +76 -0
- data/lib/uri_template/rfc6570/expression.rb +374 -0
- data/lib/uri_template/rfc6570/regex_builder.rb +117 -0
- data/lib/uri_template/rfc6570.rb +18 -536
- data/lib/uri_template/token.rb +64 -0
- data/lib/uri_template/utils.rb +47 -10
- data/lib/uri_template.rb +189 -88
- data/uri_template.gemspec +4 -4
- metadata +14 -10
- data/CHANGELOG +0 -46
- data/README +0 -67
- data/lib/uri_template/draft7.rb +0 -266
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
# This program is free software: you can redistribute it and/or modify
|
3
|
+
# it under the terms of the Affero GNU General Public License as published by
|
4
|
+
# the Free Software Foundation, either version 3 of the License, or
|
5
|
+
# (at your option) any later version.
|
6
|
+
#
|
7
|
+
# This program is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
10
|
+
# GNU General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
14
|
+
#
|
15
|
+
# (c) 2011 - 2012 by Hannes Georg
|
16
|
+
#
|
17
|
+
|
18
|
+
# This should make it possible to do basic analysis independently from the concrete type.
|
19
|
+
# Usually the submodules {URITemplate::Literal} and {URITemplate::Expression} are used.
|
20
|
+
#
|
21
|
+
# @abstract
|
22
|
+
module URITemplate::Token
|
23
|
+
|
24
|
+
EMPTY_ARRAY = [].freeze
|
25
|
+
|
26
|
+
# The variable names used in this token.
|
27
|
+
#
|
28
|
+
# @return [Array<String>]
|
29
|
+
def variables
|
30
|
+
EMPTY_ARRAY
|
31
|
+
end
|
32
|
+
|
33
|
+
# Number of variables in this token
|
34
|
+
def size
|
35
|
+
variables.size
|
36
|
+
end
|
37
|
+
|
38
|
+
def starts_with_slash?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def ends_with_slash?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def scheme?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def host?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# @abstract
|
55
|
+
def expand(variables)
|
56
|
+
raise "Please implement #expand(variables) on #{self.class.inspect}."
|
57
|
+
end
|
58
|
+
|
59
|
+
# @abstract
|
60
|
+
def to_s
|
61
|
+
raise "Please implement #to_s on #{self.class.inspect}."
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/uri_template/utils.rb
CHANGED
@@ -24,17 +24,22 @@ module URITemplate
|
|
24
24
|
|
25
25
|
include Enumerable
|
26
26
|
|
27
|
-
def initialize(regexp)
|
27
|
+
def initialize(regexp, options = {})
|
28
28
|
@regexp = regexp
|
29
|
+
@rest = options.fetch(:rest){ :yield }
|
29
30
|
end
|
30
31
|
|
31
32
|
def each(str)
|
33
|
+
raise ArgumentError, "RegexpEnumerator#each expects a String, but got #{str.inspect}" unless str.kind_of? String
|
32
34
|
return Enumerator.new(self,:each,str) unless block_given?
|
33
35
|
rest = str
|
34
36
|
loop do
|
35
37
|
m = @regexp.match(rest)
|
36
38
|
if m.nil?
|
37
|
-
|
39
|
+
if rest.size > 0
|
40
|
+
yield rest if @rest == :yield
|
41
|
+
raise "Unable to match #{rest.inspect} against #{@regexp.inspect}" if @rest == :raise
|
42
|
+
end
|
38
43
|
break
|
39
44
|
end
|
40
45
|
yield m.pre_match if m.pre_match.size > 0
|
@@ -42,7 +47,10 @@ module URITemplate
|
|
42
47
|
if m[0].size == 0
|
43
48
|
# obviously matches empty string, so post_match will equal rest
|
44
49
|
# terminate or this will loop forever
|
45
|
-
|
50
|
+
if m.post_match.size > 0
|
51
|
+
yield m.post_match if @rest == :yield
|
52
|
+
raise "#{@regexp.inspect} matched an empty string. The rest is #{m.post_match.inspect}." if @rest == :raise
|
53
|
+
end
|
46
54
|
break
|
47
55
|
end
|
48
56
|
rest = m.post_match
|
@@ -95,6 +103,19 @@ module URITemplate
|
|
95
103
|
str.encode(Encoding::UTF_8)
|
96
104
|
end
|
97
105
|
|
106
|
+
# @method force_utf8(str)
|
107
|
+
# enforces UTF8 encoding
|
108
|
+
#
|
109
|
+
# @param str [String]
|
110
|
+
# @return String
|
111
|
+
# @visibility public
|
112
|
+
def force_utf8_encode(str)
|
113
|
+
return str if str.encoding == Encoding::UTF_8
|
114
|
+
str = str.dup if str.frozen?
|
115
|
+
return str.force_encoding(Encoding::UTF_8)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
98
119
|
def to_ascii_fallback(str)
|
99
120
|
str
|
100
121
|
end
|
@@ -103,16 +124,24 @@ module URITemplate
|
|
103
124
|
str
|
104
125
|
end
|
105
126
|
|
127
|
+
def force_utf8_fallback(str)
|
128
|
+
str
|
129
|
+
end
|
130
|
+
|
106
131
|
if "".respond_to?(:encode)
|
107
132
|
# @api private
|
108
133
|
send(:alias_method, :to_ascii, :to_ascii_encode)
|
109
134
|
# @api private
|
110
135
|
send(:alias_method, :to_utf8, :to_utf8_encode)
|
136
|
+
# @api private
|
137
|
+
send(:alias_method, :force_utf8, :force_utf8_encode)
|
111
138
|
else
|
112
139
|
# @api private
|
113
140
|
send(:alias_method, :to_ascii, :to_ascii_fallback)
|
114
141
|
# @api private
|
115
142
|
send(:alias_method, :to_utf8, :to_utf8_fallback)
|
143
|
+
# @api private
|
144
|
+
send(:alias_method, :force_utf8, :force_utf8_fallback)
|
116
145
|
end
|
117
146
|
|
118
147
|
public :to_ascii
|
@@ -150,13 +179,13 @@ module URITemplate
|
|
150
179
|
end
|
151
180
|
|
152
181
|
def unescape_url(s)
|
153
|
-
|
182
|
+
force_utf8( to_ascii(s).gsub('+',' ').gsub(PCT){
|
154
183
|
$1.to_i(16).chr
|
155
184
|
} )
|
156
185
|
end
|
157
186
|
|
158
187
|
def unescape_uri(s)
|
159
|
-
|
188
|
+
force_utf8( to_ascii(s).gsub(PCT){
|
160
189
|
$1.to_i(16).chr
|
161
190
|
})
|
162
191
|
end
|
@@ -190,11 +219,11 @@ module URITemplate
|
|
190
219
|
end
|
191
220
|
|
192
221
|
def unescape_url(s)
|
193
|
-
super(to_ascii(s))
|
222
|
+
force_utf8(super(to_ascii(s)))
|
194
223
|
end
|
195
224
|
|
196
225
|
def unescape_uri(s)
|
197
|
-
super(to_ascii(s))
|
226
|
+
force_utf8(super(to_ascii(s)))
|
198
227
|
end
|
199
228
|
|
200
229
|
end
|
@@ -235,6 +264,14 @@ module URITemplate
|
|
235
264
|
raise Unconvertable.new(object)
|
236
265
|
end
|
237
266
|
|
267
|
+
# @api private
|
268
|
+
# Should we use \u.... or \x.. in regexps?
|
269
|
+
def use_unicode?
|
270
|
+
return eval('Regexp.compile("\u0020")') =~ " "
|
271
|
+
rescue SyntaxError
|
272
|
+
false
|
273
|
+
end
|
274
|
+
|
238
275
|
# Returns true when the given value is an array and it only consists of arrays with two items.
|
239
276
|
# This useful when using a hash is not ideal, since it doesn't allow duplicate keys.
|
240
277
|
# @example
|
@@ -258,14 +295,14 @@ module URITemplate
|
|
258
295
|
# URITemplate::Utils.pair_array_to_hash( [ ['a',1],['a',2],['a',3] ] ) #=> {'a'=>3}
|
259
296
|
#
|
260
297
|
# @example Carful vs. Ignorant
|
261
|
-
# URITemplate::Utils.pair_array_to_hash( [ ['a',1],'foo','bar'], false )
|
262
|
-
# URITemplate::Utils.pair_array_to_hash( [ ['a',1],'foo','bar'], true )
|
298
|
+
# URITemplate::Utils.pair_array_to_hash( [ ['a',1],'foo','bar'], false ) #UNDEFINED!
|
299
|
+
# URITemplate::Utils.pair_array_to_hash( [ ['a',1],'foo','bar'], true ) #=> [ ['a',1], 'foo', 'bar']
|
263
300
|
#
|
264
301
|
# @param x the value to convert
|
265
302
|
# @param careful [true,false] wheter to check every array item. Use this when you expect array with subarrays which are not pairs. Setting this to false however improves runtime by ~30% even with comparetivly short arrays.
|
266
303
|
def pair_array_to_hash(x, careful = false )
|
267
304
|
if careful ? pair_array?(x) : (x.kind_of?(Array) and ( x.empty? or x.first.kind_of?(Array) ) )
|
268
|
-
return Hash[
|
305
|
+
return Hash[ x ]
|
269
306
|
else
|
270
307
|
return x
|
271
308
|
end
|
data/lib/uri_template.rb
CHANGED
@@ -18,87 +18,27 @@
|
|
18
18
|
# A base module for all implementations of a uri template.
|
19
19
|
module URITemplate
|
20
20
|
|
21
|
-
# @private
|
22
|
-
|
23
|
-
SUPPORTS_UNICODE_CHARS = begin
|
24
|
-
if "string".respond_to? :encoding
|
25
|
-
rx = eval('Regexp.compile("\u0020")')
|
26
|
-
!!(rx =~ " ")
|
27
|
-
else
|
28
|
-
rx = eval('/\u0020/')
|
29
|
-
!!(rx =~ " ")
|
30
|
-
end
|
31
|
-
rescue SyntaxError
|
32
|
-
false
|
33
|
-
end
|
34
|
-
|
35
|
-
# This should make it possible to do basic analysis independently from the concrete type.
|
36
|
-
module Token
|
37
|
-
|
38
|
-
def size
|
39
|
-
variables.size
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# A module which all literal tokens should include.
|
45
|
-
module Literal
|
46
|
-
|
47
|
-
include Token
|
48
|
-
|
49
|
-
attr_reader :string
|
50
|
-
|
51
|
-
def literal?
|
52
|
-
true
|
53
|
-
end
|
54
|
-
|
55
|
-
def expression?
|
56
|
-
false
|
57
|
-
end
|
58
|
-
|
59
|
-
def variables
|
60
|
-
[]
|
61
|
-
end
|
62
|
-
|
63
|
-
def size
|
64
|
-
0
|
65
|
-
end
|
66
|
-
|
67
|
-
def expand(*_)
|
68
|
-
return string
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
# A module which all non-literal tokens should include.
|
74
|
-
module Expression
|
75
|
-
|
76
|
-
include Token
|
77
|
-
|
78
|
-
attr_reader :variables
|
79
|
-
|
80
|
-
def literal?
|
81
|
-
false
|
82
|
-
end
|
21
|
+
# @api private
|
22
|
+
SCHEME_REGEX = /\A[a-z]+:/i.freeze
|
83
23
|
|
84
|
-
|
85
|
-
|
86
|
-
end
|
24
|
+
# @api private
|
25
|
+
HOST_REGEX = /\A(?:[a-z]+:)?\/\/[^\/]+/i.freeze
|
87
26
|
|
88
|
-
|
27
|
+
# @api private
|
28
|
+
URI_SPLIT = /\A(?:([a-z]+):)?(?:\/\/)?([^\/]+)?/i.freeze
|
89
29
|
|
90
30
|
autoload :Utils, 'uri_template/utils'
|
91
|
-
autoload :
|
31
|
+
autoload :Token, 'uri_template/token'
|
32
|
+
autoload :Literal, 'uri_template/literal'
|
33
|
+
autoload :Expression, 'uri_template/expression'
|
92
34
|
autoload :RFC6570, 'uri_template/rfc6570'
|
93
35
|
autoload :Colon, 'uri_template/colon'
|
94
36
|
|
95
37
|
# A hash with all available implementations.
|
96
|
-
# Currently the only implementation is :draft7. But there also aliases :default and :latest available. This should make it possible to add newer specs later.
|
97
38
|
# @see resolve_class
|
98
39
|
VERSIONS = {
|
99
|
-
:draft7 => :Draft7,
|
100
40
|
:rfc6570 => :RFC6570,
|
101
|
-
:default => :
|
41
|
+
:default => :RFC6570,
|
102
42
|
:colon => :Colon,
|
103
43
|
:latest => :RFC6570
|
104
44
|
}
|
@@ -107,10 +47,11 @@ module URITemplate
|
|
107
47
|
# Extracts all symbols from args and looks up the first in {VERSIONS}.
|
108
48
|
#
|
109
49
|
# @return Array an array of the class to use and the unused parameters.
|
50
|
+
#
|
110
51
|
# @example
|
111
|
-
# URITemplate.resolve_class() #=> [ URITemplate::
|
112
|
-
# URITemplate.resolve_class(:
|
113
|
-
# URITemplate.resolve_class("template",:
|
52
|
+
# URITemplate.resolve_class() #=> [ URITemplate::RFC6570, [] ]
|
53
|
+
# URITemplate.resolve_class(:colon) #=> [ URITemplate::Colon, [] ]
|
54
|
+
# URITemplate.resolve_class("template",:rfc6570) #=> [ URITemplate::RFC6570, ["template"] ]
|
114
55
|
#
|
115
56
|
# @raise ArgumentError when no class was found.
|
116
57
|
#
|
@@ -130,7 +71,7 @@ module URITemplate
|
|
130
71
|
# tpl.expand('x'=>'y') #=> 'y'
|
131
72
|
#
|
132
73
|
# @example
|
133
|
-
# tpl = URITemplate.new(:
|
74
|
+
# tpl = URITemplate.new(:colon,'/:x') # a new template using the colon implementation
|
134
75
|
#
|
135
76
|
def self.new(*args)
|
136
77
|
klass, rest = resolve_class(*args)
|
@@ -167,8 +108,10 @@ module URITemplate
|
|
167
108
|
# Returns an array with two {URITemplate}s and two booleans indicating which of the two were converted or raises an ArgumentError.
|
168
109
|
#
|
169
110
|
# @example
|
170
|
-
# URITemplate.coerce( URITemplate.new(:
|
171
|
-
# URITemplate.coerce( '{y}', URITemplate.new(:
|
111
|
+
# URITemplate.coerce( URITemplate.new(:rfc6570,'{x}'), '{y}' ) #=> [URITemplate.new(:rfc6570,'{x}'), URITemplate.new(:rfc6570,'{y}'), false, true]
|
112
|
+
# URITemplate.coerce( '{y}', URITemplate.new(:rfc6570,'{x}') ) #=> [URITemplate.new(:rfc6570,'{y}'), URITemplate.new(:rfc6570,'{x}'), true, false]
|
113
|
+
#
|
114
|
+
# @return [Tuple<URITemplate,URITemplate,Bool,Bool>]
|
172
115
|
def self.coerce(a,b)
|
173
116
|
if a.kind_of? URITemplate
|
174
117
|
if a.class == b.class
|
@@ -210,6 +153,19 @@ module URITemplate
|
|
210
153
|
a.send(method,b,*args)
|
211
154
|
end
|
212
155
|
|
156
|
+
def self.coerce_first_arg(meth)
|
157
|
+
alias_method( (meth.to_s + '_without_coercion').to_sym , meth )
|
158
|
+
class_eval(<<-RUBY)
|
159
|
+
def #{meth}(other, *args, &block)
|
160
|
+
this, other, this_converted, _ = URITemplate.coerce( self, other )
|
161
|
+
if this_converted
|
162
|
+
return this.#{meth}(other,*args, &block)
|
163
|
+
end
|
164
|
+
return #{meth}_without_coercion(other,*args, &block)
|
165
|
+
end
|
166
|
+
RUBY
|
167
|
+
end
|
168
|
+
|
213
169
|
# A base class for all errors which will be raised upon invalid syntax.
|
214
170
|
module Invalid
|
215
171
|
end
|
@@ -226,7 +182,9 @@ module URITemplate
|
|
226
182
|
# strings in order to support the Ruby 1.9 hash syntax.
|
227
183
|
#
|
228
184
|
# @raise {Unconvertable} if a variable could not be converted to a string.
|
229
|
-
# @
|
185
|
+
# @raise {InvalidValue} if a value is not suiteable for a certain variable ( e.g. a string when a list is expected ).
|
186
|
+
#
|
187
|
+
# @param variables [#map]
|
230
188
|
# @return String
|
231
189
|
def expand(variables = {})
|
232
190
|
raise ArgumentError, "Expected something that returns to :map, but got: #{variables.inspect}" unless variables.respond_to? :map
|
@@ -241,12 +199,16 @@ module URITemplate
|
|
241
199
|
|
242
200
|
# @abstract
|
243
201
|
# 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.
|
202
|
+
#
|
203
|
+
# @return [Symbol]
|
244
204
|
def type
|
245
205
|
raise "Please implement #type on #{self.class.inspect}."
|
246
206
|
end
|
247
207
|
|
248
208
|
# @abstract
|
249
209
|
# Returns the tokens of this templates. Tokens should include either {Literal} or {Expression}.
|
210
|
+
#
|
211
|
+
# @return [Array<URITemplate::Token>]
|
250
212
|
def tokens
|
251
213
|
raise "Please implement #tokens on #{self.class.inspect}."
|
252
214
|
end
|
@@ -256,9 +218,9 @@ module URITemplate
|
|
256
218
|
# URITemplate.new('{foo}{bar}{baz}').variables #=> ['foo','bar','baz']
|
257
219
|
# URITemplate.new('{a}{c}{a}{b}').variables #=> ['a','c','b']
|
258
220
|
#
|
259
|
-
# @return Array
|
221
|
+
# @return [Array<String>]
|
260
222
|
def variables
|
261
|
-
@variables ||= tokens.
|
223
|
+
@variables ||= tokens.map(&:variables).flatten.uniq.freeze
|
262
224
|
end
|
263
225
|
|
264
226
|
# Returns the number of static characters in this template.
|
@@ -275,28 +237,167 @@ module URITemplate
|
|
275
237
|
@static_characters ||= tokens.select(&:literal?).map{|t| t.string.size }.inject(0,:+)
|
276
238
|
end
|
277
239
|
|
278
|
-
# Returns whether this uri-template
|
279
|
-
#
|
240
|
+
# Returns whether this uri-template includes a host name
|
241
|
+
#
|
242
|
+
# This method is usefull to check wheter this template will generate
|
243
|
+
# or match a uri with a host.
|
244
|
+
#
|
245
|
+
# @see #scheme?
|
280
246
|
#
|
281
|
-
|
282
|
-
|
247
|
+
# @example
|
248
|
+
# URITemplate.new('/foo').host? #=> false
|
249
|
+
# URITemplate.new('//example.com/foo').host? #=> true
|
250
|
+
# URITemplate.new('//{host}/foo').host? #=> true
|
251
|
+
# URITemplate.new('http://example.com/foo').host? #=> true
|
252
|
+
# URITemplate.new('{scheme}://example.com/foo').host? #=> true
|
253
|
+
#
|
254
|
+
def host?
|
255
|
+
return scheme_and_host[1]
|
256
|
+
end
|
257
|
+
|
258
|
+
# Returns whether this uri-template includes a scheme
|
259
|
+
#
|
260
|
+
# This method is usefull to check wheter this template will generate
|
261
|
+
# or match a uri with a scheme.
|
262
|
+
#
|
263
|
+
# @see #host?
|
264
|
+
#
|
265
|
+
# @example
|
266
|
+
# URITemplate.new('/foo').scheme? #=> false
|
267
|
+
# URITemplate.new('//example.com/foo').scheme? #=> false
|
268
|
+
# URITemplate.new('http://example.com/foo').scheme? #=> true
|
269
|
+
# URITemplate.new('{scheme}://example.com/foo').scheme? #=> true
|
270
|
+
#
|
271
|
+
def scheme?
|
272
|
+
return scheme_and_host[0]
|
273
|
+
end
|
274
|
+
|
275
|
+
# Returns the pattern for this template.
|
276
|
+
#
|
277
|
+
# @return String
|
278
|
+
def pattern
|
279
|
+
@pattern ||= tokens.map(&:to_s).join
|
280
|
+
end
|
281
|
+
|
282
|
+
alias to_s pattern
|
283
|
+
|
284
|
+
# Compares two template patterns.
|
285
|
+
def eq(other)
|
286
|
+
return self.pattern == other.pattern
|
287
|
+
end
|
288
|
+
|
289
|
+
coerce_first_arg :eq
|
290
|
+
|
291
|
+
alias == eq
|
292
|
+
|
293
|
+
# Tries to concatenate two templates, as if they were path segments.
|
294
|
+
# Removes double slashes or insert one if they are missing.
|
295
|
+
#
|
296
|
+
# @example
|
297
|
+
# tpl = URITemplate::RFC6570.new('/xy/')
|
298
|
+
# (tpl / '/z/' ).pattern #=> '/xy/z/'
|
299
|
+
# (tpl / 'z/' ).pattern #=> '/xy/z/'
|
300
|
+
# (tpl / '{/z}' ).pattern #=> '/xy{/z}'
|
301
|
+
# (tpl / 'a' / 'b' ).pattern #=> '/xy/a/b'
|
302
|
+
#
|
303
|
+
# @param other [URITemplate, String, ...]
|
304
|
+
# @return URITemplate
|
305
|
+
def path_concat(other)
|
306
|
+
if other.host? or other.scheme?
|
307
|
+
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."
|
308
|
+
end
|
309
|
+
|
310
|
+
return self if other.tokens.none?
|
311
|
+
return other if self.tokens.none?
|
312
|
+
|
313
|
+
tail = self.tokens.last
|
314
|
+
head = other.tokens.first
|
315
|
+
|
316
|
+
if tail.ends_with_slash?
|
317
|
+
if head.starts_with_slash?
|
318
|
+
return self.class.new( remove_double_slash(self.tokens, other.tokens) )
|
319
|
+
end
|
320
|
+
elsif !head.starts_with_slash?
|
321
|
+
return self.class.new( (self.tokens + ['/'] + other.tokens).join)
|
322
|
+
end
|
323
|
+
return self.class.new( (self.tokens + other.tokens).join )
|
324
|
+
end
|
325
|
+
|
326
|
+
coerce_first_arg :path_concat
|
327
|
+
|
328
|
+
alias / path_concat
|
329
|
+
|
330
|
+
# Concatenate two template with conversion.
|
331
|
+
#
|
332
|
+
# @example
|
333
|
+
# tpl = URITemplate::RFC6570.new('foo')
|
334
|
+
# (tpl + '{bar}' ).pattern #=> 'foo{bar}'
|
335
|
+
#
|
336
|
+
# @param other [URITemplate, String, ...]
|
337
|
+
# @return URITemplate
|
338
|
+
def concat(other)
|
339
|
+
if other.host? or other.scheme?
|
340
|
+
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."
|
341
|
+
end
|
342
|
+
|
343
|
+
return self if other.tokens.none?
|
344
|
+
return other if self.tokens.none?
|
345
|
+
return self.class.new( self.to_s + other.to_s )
|
346
|
+
end
|
347
|
+
|
348
|
+
coerce_first_arg :concat
|
349
|
+
|
350
|
+
alias + concat
|
351
|
+
alias >> concat
|
352
|
+
|
353
|
+
# @api private
|
354
|
+
def remove_double_slash( first_tokens, second_tokens )
|
355
|
+
if first_tokens.last.literal?
|
356
|
+
return first_tokens[0..-2] + [ first_tokens.last.to_s[0..-2] ] + second_tokens
|
357
|
+
elsif second_tokens.first.literal?
|
358
|
+
return first_tokens + [ second_tokens.first.to_s[1..-1] ] + second_tokens[1..-1]
|
359
|
+
else
|
360
|
+
raise ArgumentError, "Cannot remove double slashes from #{first_tokens.inspect} and #{second_tokens.inspect}."
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
private :remove_double_slash
|
365
|
+
|
366
|
+
# @api private
|
367
|
+
def scheme_and_host
|
368
|
+
return @scheme_and_host if @scheme_and_host
|
283
369
|
read_chars = ""
|
370
|
+
@scheme_and_host = [false,false]
|
284
371
|
tokens.each do |token|
|
285
372
|
if token.expression?
|
286
373
|
read_chars << "x"
|
374
|
+
if token.scheme?
|
375
|
+
read_chars << ':'
|
376
|
+
end
|
377
|
+
if token.host?
|
378
|
+
read_chars << '//'
|
379
|
+
end
|
380
|
+
read_chars << "x"
|
287
381
|
elsif token.literal?
|
288
382
|
read_chars << token.string
|
289
383
|
end
|
290
|
-
if read_chars =~
|
291
|
-
|
384
|
+
if read_chars =~ SCHEME_REGEX
|
385
|
+
@scheme_and_host = [true, true]
|
386
|
+
break
|
387
|
+
elsif read_chars =~ HOST_REGEX
|
388
|
+
@scheme_and_host[1] = true
|
389
|
+
break
|
292
390
|
elsif read_chars =~ /(^|[^:\/])\/(?!\/)/
|
293
|
-
|
391
|
+
break
|
294
392
|
end
|
295
393
|
end
|
296
|
-
|
297
|
-
return @absolute = false
|
394
|
+
return @scheme_and_host
|
298
395
|
end
|
299
396
|
|
397
|
+
private :scheme_and_host
|
398
|
+
|
399
|
+
alias absolute? host?
|
400
|
+
|
300
401
|
# Opposite of {#absolute?}
|
301
402
|
def relative?
|
302
403
|
!absolute?
|
data/uri_template.gemspec
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'uri_template'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '
|
3
|
+
s.version = '0.5.0'
|
4
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
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
|
9
|
+
s.description = 'A templating system for URIs, which implements RFC6570 and Colon based URITemplates in a clean and straight forward way.'
|
10
10
|
|
11
11
|
s.require_paths = ['lib']
|
12
12
|
|
13
|
-
s.files = Dir.glob('lib/**/**/*.rb') + ['uri_template.gemspec', 'README', 'CHANGELOG']
|
13
|
+
s.files = Dir.glob('lib/**/**/*.rb') + ['uri_template.gemspec', 'README.md', 'CHANGELOG.md']
|
14
14
|
|
15
15
|
s.add_development_dependency 'multi_json'
|
16
16
|
s.add_development_dependency 'rspec'
|
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.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -91,23 +91,27 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
-
description:
|
95
|
-
|
96
|
-
gem however is intended to be extended when newer specs evolve. For now only draft
|
97
|
-
7 and a simple colon based format are supported.'
|
94
|
+
description: A templating system for URIs, which implements RFC6570 and Colon based
|
95
|
+
URITemplates in a clean and straight forward way.
|
98
96
|
email: hannes.georg@googlemail.com
|
99
97
|
executables: []
|
100
98
|
extensions: []
|
101
99
|
extra_rdoc_files: []
|
102
100
|
files:
|
103
|
-
- lib/uri_template/
|
101
|
+
- lib/uri_template/rfc6570/expression.rb
|
102
|
+
- lib/uri_template/rfc6570/regex_builder.rb
|
103
|
+
- lib/uri_template/rfc6570/expression/named.rb
|
104
|
+
- lib/uri_template/rfc6570/expression/unnamed.rb
|
104
105
|
- lib/uri_template/colon.rb
|
106
|
+
- lib/uri_template/literal.rb
|
107
|
+
- lib/uri_template/expression.rb
|
108
|
+
- lib/uri_template/utils.rb
|
105
109
|
- lib/uri_template/rfc6570.rb
|
106
|
-
- lib/uri_template/
|
110
|
+
- lib/uri_template/token.rb
|
107
111
|
- lib/uri_template.rb
|
108
112
|
- uri_template.gemspec
|
109
|
-
- README
|
110
|
-
- CHANGELOG
|
113
|
+
- README.md
|
114
|
+
- CHANGELOG.md
|
111
115
|
homepage: http://github.com/hannesg/uri_template
|
112
116
|
licenses: []
|
113
117
|
post_install_message:
|
data/CHANGELOG
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# 0.4.0 - 06.07.2012
|
2
|
-
+ expand now accepts symbols as keys
|
3
|
-
+ expand now accepts arrays of pairs
|
4
|
-
* fixed some testing bugs
|
5
|
-
|
6
|
-
# 0.3.0 - 24.05.2012
|
7
|
-
+ Implemented the final version. Default implementation is now RFC 6570
|
8
|
-
* BUGFIX: variables with terminal dots were allowed
|
9
|
-
* BUGFIX: lists of commas were parsed incorrectly
|
10
|
-
|
11
|
-
# 0.2.1 - 30.12.2011
|
12
|
-
* Compatibility: Works now with MRI 1.8.7 and REE
|
13
|
-
|
14
|
-
# 0.2.0 - 03.12.2011
|
15
|
-
* Reworked the escaping mechanism
|
16
|
-
+ escape_utils can now be used to boost escape/unescape performance
|
17
|
-
|
18
|
-
# 0.1.4 - 19.11.2011
|
19
|
-
* Compatiblity: Works now with MRI 1.9.3, Rubinius and JRuby
|
20
|
-
* Various (significant!) performance improvements
|
21
|
-
|
22
|
-
# 0.1.3 - 15.11.2011
|
23
|
-
* BUGFIX: Draft7./ now concatenates literals correctly
|
24
|
-
* BUGFIX: Draft7.tokens is now public
|
25
|
-
|
26
|
-
# 0.1.2 - 10.11.2011
|
27
|
-
+ added a new template-type: Colon
|
28
|
-
this should allow (some day) to rails-like routing tables
|
29
|
-
+ made the tokens-method mandatory and added two interfaces for tokens.
|
30
|
-
this allows cross-type features like variable anaylisis
|
31
|
-
|
32
|
-
# 0.1.1 - 4.11.2011
|
33
|
-
+ added a bunch of useful helper methods
|
34
|
-
|
35
|
-
# 0.1.0 - 2.11.2011
|
36
|
-
- Removed Sections. They made too many headaches.
|
37
|
-
+ Made draft7 template concatenateable. This should replace sections.
|
38
|
-
* BUGFIX: multiline uris were matched
|
39
|
-
* BUGFIX: variablenames were decoded when this was not appreciated
|
40
|
-
|
41
|
-
# 0.0.2 - 1.11.2011
|
42
|
-
* BUGFIX: Concatenating empty sections no more leads to catch-all templates, when an emtpy template was appreciated.
|
43
|
-
+ The extracted variables now contains the keys :suffix and :prefix if the match didn't consume the whole uri.
|
44
|
-
|
45
|
-
# 0.0.1 - 30.10.2011
|
46
|
-
Initial version
|