tilia-uri 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +32 -0
- data/.simplecov +4 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.sabre.md +26 -0
- data/CONTRIBUTING.md +25 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +27 -0
- data/LICENSE.sabre +27 -0
- data/README.md +44 -0
- data/Rakefile +17 -0
- data/lib/tilia/uri.rb +231 -0
- data/lib/tilia/uri/version.rb +9 -0
- data/test/build_test.rb +25 -0
- data/test/normalize_test.rb +24 -0
- data/test/resolve_test.rb +69 -0
- data/test/split_test.rb +29 -0
- data/test/test_helper.rb +4 -0
- data/tilia-uri.gemspec +13 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d05aacc9eb7c559b01f9845a5baf5fff2f92f0c4
|
4
|
+
data.tar.gz: 1242281c7936522ba63c1ce8e2130ad6522bc2b9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7bbe25462c7a574ba32b8e579fa4edddda7c086fcc97325f38c2b25bffc6e2836fdc03b6aeb98f8460f8502650ade09052917c389ce51afdbb96cb1d999857f2
|
7
|
+
data.tar.gz: 3afe6f78cd198ba2b8fc24d86cf2a12d20f09fbd0ca6b2b270e25eec98341d02aa6b0f8ca349568b02846a0dc46ba758bde26020b02492e4a579721a437357f8
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Disable metrics - we stick to the sabre coding
|
2
|
+
Metrics/AbcSize:
|
3
|
+
Enabled: false
|
4
|
+
|
5
|
+
Metrics/BlockNesting:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Metrics/ClassLength:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Metrics/ModuleLength:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Metrics/CyclomaticComplexity:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Metrics/LineLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/MethodLength:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Metrics/ParameterLists:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/PerceivedComplexity:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
# ['word', 'array'] looks better when aligned with other arrays that can't use
|
30
|
+
# %w() syntax
|
31
|
+
Style/WordArray:
|
32
|
+
Enabled: false
|
data/.simplecov
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.sabre.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
ChangeLog
|
2
|
+
=========
|
3
|
+
|
4
|
+
1.0.1 (2015-04-28)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* #4: Using php-cs-fixer to automatically enforce conding standards.
|
8
|
+
* #5: Resolving to and building `mailto:` urls were not correctly handled.
|
9
|
+
|
10
|
+
|
11
|
+
1.0.0 (2015-01-27)
|
12
|
+
------------------
|
13
|
+
|
14
|
+
* Added a `normalize` function.
|
15
|
+
* Added a `buildUri` function.
|
16
|
+
* Fixed a bug in the `resolve` when only a new fragment is specified.
|
17
|
+
|
18
|
+
San José, CalConnect XXXII release!
|
19
|
+
|
20
|
+
0.0.1 (2014-11-17)
|
21
|
+
------------------
|
22
|
+
|
23
|
+
* First version!
|
24
|
+
* Source was lifted from sabre/http package.
|
25
|
+
* Provides a `resolve` and a `split` function.
|
26
|
+
* Requires PHP 5.4.8 and up.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code.
|
4
|
+
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#tilia-uri/tilia@jakobsack.de
|
5
|
+
|
6
|
+
This library is a port of [sabre/uri](http://github.com/fruux/sabre-uri). The ruby code should match the php code as good as possible. For more information refer to the [coding guidelines](https://tilia.github.io/coding_guidelines).
|
7
|
+
|
8
|
+
If you are having an issue [search the open issues](https://github.com/tilia/tilia-uri/issues) or create an issue and we'll help point you in the right direction.
|
9
|
+
|
10
|
+
## Submitting a Pull Request
|
11
|
+
|
12
|
+
* Fork the project on Github
|
13
|
+
* Install development dependencies (`bundle install`)
|
14
|
+
* Create a topic branch for your changes
|
15
|
+
* Ensure that you provide *documentation* and *test coverage* for your changes (patches won't be accepted without)
|
16
|
+
* Ensure that all tests pass (`bundle exec rake`)
|
17
|
+
* Create a [pull request](https://github.com/tilia/tilia-uri/pulls) on Github (these are also a great place to start a conversation around a patch as early as possible)
|
18
|
+
|
19
|
+
## Testing
|
20
|
+
|
21
|
+
To run the tests:
|
22
|
+
|
23
|
+
$ rake
|
24
|
+
|
25
|
+
If nothing complains, congratulations!
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (4.2.4)
|
5
|
+
i18n (~> 0.7)
|
6
|
+
json (~> 1.7, >= 1.7.7)
|
7
|
+
minitest (~> 5.1)
|
8
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
9
|
+
tzinfo (~> 1.1)
|
10
|
+
ast (2.1.0)
|
11
|
+
astrolabe (1.3.1)
|
12
|
+
parser (~> 2.2)
|
13
|
+
docile (1.1.5)
|
14
|
+
i18n (0.7.0)
|
15
|
+
json (1.8.3)
|
16
|
+
minitest (5.8.1)
|
17
|
+
parser (2.2.3.0)
|
18
|
+
ast (>= 1.1, < 3.0)
|
19
|
+
powerpack (0.1.1)
|
20
|
+
rainbow (2.0.0)
|
21
|
+
rake (10.4.2)
|
22
|
+
rubocop (0.34.2)
|
23
|
+
astrolabe (~> 1.3)
|
24
|
+
parser (>= 2.2.2.5, < 3.0)
|
25
|
+
powerpack (~> 0.1)
|
26
|
+
rainbow (>= 1.99.1, < 3.0)
|
27
|
+
ruby-progressbar (~> 1.4)
|
28
|
+
ruby-progressbar (1.7.5)
|
29
|
+
simplecov (0.10.0)
|
30
|
+
docile (~> 1.1.0)
|
31
|
+
json (~> 1.8)
|
32
|
+
simplecov-html (~> 0.10.0)
|
33
|
+
simplecov-html (0.10.0)
|
34
|
+
thread_safe (0.3.5)
|
35
|
+
tzinfo (1.2.2)
|
36
|
+
thread_safe (~> 0.1)
|
37
|
+
yard (0.8.7.6)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
activesupport (~> 4.2)
|
44
|
+
minitest (~> 5.8)
|
45
|
+
rake
|
46
|
+
rubocop (~> 0.34)
|
47
|
+
simplecov (~> 0.10)
|
48
|
+
yard (~> 0.8)
|
49
|
+
|
50
|
+
BUNDLED WITH
|
51
|
+
1.10.6
|
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (C) 2015 Jakob Sack (tilia@jakobsack.de)
|
2
|
+
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
* Neither the name Tilia nor the names of its contributors
|
14
|
+
may be used to endorse or promote products derived from this software
|
15
|
+
without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27
|
+
POSSIBILITY OF SUCH DAMAGE.
|
data/LICENSE.sabre
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (C) 2014-2015 fruux GmbH (https://fruux.com/)
|
2
|
+
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
* Neither the name Sabre nor the names of its contributors
|
14
|
+
may be used to endorse or promote products derived from this software
|
15
|
+
without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27
|
+
POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
tilia/uri
|
2
|
+
=========
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/tilia/tilia-uri.svg?branch=master)](https://travis-ci.org/tilia/tilia-uri)
|
5
|
+
|
6
|
+
**tilia/uri is a port of [sabre/uri](https://github.com/fruux/sabre-uri)**
|
7
|
+
|
8
|
+
sabre/uri is a lightweight library that provides several functions for working
|
9
|
+
with URIs, staying true to the rules of [RFC3986](https://tools.ietf.org/html/rfc3986/).
|
10
|
+
|
11
|
+
Partially inspired by [Node.js URL library](http://nodejs.org/api/url.html), and created to solve real
|
12
|
+
problems in PHP applications. 100% unitested and many tests are based on
|
13
|
+
examples from RFC3986.
|
14
|
+
|
15
|
+
The library provides the following functions:
|
16
|
+
|
17
|
+
1. `resolve` to resolve relative urls.
|
18
|
+
2. `normalize` to aid in comparing urls.
|
19
|
+
3. `parse`, which works like PHP's [parse_url](http://php.net/manual/en/function.parse-url.php)
|
20
|
+
4. `build` to do the exact opposite of `parse`.
|
21
|
+
5. `split` to easily get the 'dirname' and 'basename' of a URL without all the
|
22
|
+
problems those two functions have.
|
23
|
+
|
24
|
+
|
25
|
+
Installation
|
26
|
+
------------
|
27
|
+
|
28
|
+
Simply add tilia-uri to your Gemfile and bundle it up:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'tilia-uri', '~> 1.0'
|
32
|
+
```
|
33
|
+
|
34
|
+
|
35
|
+
Contributing
|
36
|
+
------------
|
37
|
+
|
38
|
+
See [Contributing](CONTRIBUTING.md)
|
39
|
+
|
40
|
+
|
41
|
+
License
|
42
|
+
-------
|
43
|
+
|
44
|
+
tilia-uri is licensed under the terms of the [three-clause BSD-license](LICENSE).
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'yard'
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.test_files = Dir.glob('test/**/*_test.rb')
|
8
|
+
t.libs << 'test'
|
9
|
+
end
|
10
|
+
RuboCop::RakeTask.new do |t|
|
11
|
+
t.options = ['--format', 'html', '--out', 'coverage/rubocop.html']
|
12
|
+
end
|
13
|
+
YARD::Rake::YardocTask.new do |t|
|
14
|
+
t.files = ['lib/**/*.rb', '-', 'README.md']
|
15
|
+
end
|
16
|
+
|
17
|
+
task(default: :test)
|
data/lib/tilia/uri.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
# Namespace for tilia project
|
2
|
+
module Tilia
|
3
|
+
# Load active support core extensions
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/core_ext'
|
6
|
+
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
# Namespace of tilia-uri library
|
10
|
+
module Uri
|
11
|
+
require 'tilia/uri/version'
|
12
|
+
|
13
|
+
# Resolves relative urls, like a browser would.
|
14
|
+
#
|
15
|
+
# This function takes a basePath, which itself _may_ also be relative, and
|
16
|
+
# then applies the relative path on top of it.
|
17
|
+
#
|
18
|
+
# @param [String] base_path
|
19
|
+
# @param [String] new_path
|
20
|
+
# @return [String]
|
21
|
+
def self.resolve(base_path, new_path)
|
22
|
+
base = parse(base_path)
|
23
|
+
delta = parse(new_path)
|
24
|
+
|
25
|
+
pick = lambda do |part|
|
26
|
+
if delta[part]
|
27
|
+
delta[part]
|
28
|
+
elsif base[part]
|
29
|
+
base[part]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# If the new path defines a scheme, it's absolute and we can just return
|
34
|
+
# that.
|
35
|
+
return build(delta) if delta['scheme']
|
36
|
+
|
37
|
+
new_parts = {}
|
38
|
+
|
39
|
+
new_parts['scheme'] = pick.call('scheme')
|
40
|
+
new_parts['host'] = pick.call('host')
|
41
|
+
new_parts['port'] = pick.call('port')
|
42
|
+
|
43
|
+
path = ''
|
44
|
+
if !delta['path'].blank?
|
45
|
+
# If the path starts with a slash
|
46
|
+
if delta['path'][0] == '/'
|
47
|
+
path = delta['path']
|
48
|
+
else
|
49
|
+
# Removing last component from base path.
|
50
|
+
path = base['path']
|
51
|
+
path = path[0...path.rindex('/')] if path.index '/'
|
52
|
+
path += '/' + delta['path']
|
53
|
+
end
|
54
|
+
else
|
55
|
+
path = base['path'].blank? ? '/' : base['path']
|
56
|
+
end
|
57
|
+
|
58
|
+
# Removing .. and .
|
59
|
+
path_parts = path.split(%r{/})
|
60
|
+
if path_parts.empty? # RUBY
|
61
|
+
path_parts = (path + ' ').split(%r{/})
|
62
|
+
path_parts[-1] = ''
|
63
|
+
elsif path[-1] == '/'
|
64
|
+
path_parts << ''
|
65
|
+
end
|
66
|
+
new_path_parts = []
|
67
|
+
|
68
|
+
path_parts.each do |path_part|
|
69
|
+
case path_part
|
70
|
+
when '.'
|
71
|
+
# noop
|
72
|
+
when '..'
|
73
|
+
new_path_parts.pop
|
74
|
+
else
|
75
|
+
new_path_parts << path_part
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
path = new_path_parts.join '/'
|
80
|
+
|
81
|
+
# If the source url ended with a /, we want to preserve that.
|
82
|
+
new_parts['path'] = path
|
83
|
+
if delta['query']
|
84
|
+
new_parts['query'] = delta['query']
|
85
|
+
elsif !base['query'].blank? && delta['host'].blank? && delta['path'].blank?
|
86
|
+
# Keep the old query if host and path didn't change
|
87
|
+
new_parts['query'] = base['query']
|
88
|
+
end
|
89
|
+
|
90
|
+
new_parts['fragment'] = delta['fragment'] if delta['fragment']
|
91
|
+
build(new_parts)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Takes a URI or partial URI as its argument, and normalizes it.
|
95
|
+
#
|
96
|
+
# After normalizing a URI, you can safely compare it to other URIs.
|
97
|
+
# This function will for instance convert a %7E into a tilde, according to
|
98
|
+
# rfc3986.
|
99
|
+
#
|
100
|
+
# It will also change a %3a into a %3A.
|
101
|
+
#
|
102
|
+
# @param [String] uri
|
103
|
+
# @return [String]
|
104
|
+
def self.normalize(uri)
|
105
|
+
parts = parse(uri)
|
106
|
+
|
107
|
+
unless parts['path'].blank?
|
108
|
+
path_parts = parts['path'].gsub(%r{^/+}, '').split(%r{/})
|
109
|
+
|
110
|
+
new_path_parts = []
|
111
|
+
path_parts.each do |path_part|
|
112
|
+
case path_part
|
113
|
+
when '.'
|
114
|
+
# skip
|
115
|
+
when '..'
|
116
|
+
# One level up in the hierarchy
|
117
|
+
new_path_parts.pop
|
118
|
+
else
|
119
|
+
# Ensuring that everything is correctly percent-encoded.
|
120
|
+
new_path_parts << URI.escape(URI.unescape(path_part), Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
parts['path'] = '/' + new_path_parts.join('/')
|
124
|
+
end
|
125
|
+
|
126
|
+
if parts['scheme']
|
127
|
+
parts['scheme'] = parts['scheme'].downcase
|
128
|
+
default_ports = {
|
129
|
+
'http' => '80',
|
130
|
+
'https' => '443'
|
131
|
+
}
|
132
|
+
|
133
|
+
if !parts['port'].blank? && default_ports.key?(parts['scheme']) && default_ports[parts['scheme']] == parts['port']
|
134
|
+
# Removing default ports.
|
135
|
+
parts['port'] = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
# A few HTTP specific rules.
|
139
|
+
case parts['scheme']
|
140
|
+
when 'http', 'https'
|
141
|
+
if parts['path'].blank?
|
142
|
+
# An empty path is equivalent to / in http.
|
143
|
+
parts['path'] = '/'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
parts['host'] = parts['host'].downcase if parts['host']
|
149
|
+
|
150
|
+
build(parts)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Parses a URI and returns its individual components.
|
154
|
+
#
|
155
|
+
# This method largely behaves the same as PHP's parse_url, except that it will
|
156
|
+
# return an array with all the array keys, including the ones that are not
|
157
|
+
# set by parse_url, which makes it a bit easier to work with.
|
158
|
+
#
|
159
|
+
# @param [String] uri
|
160
|
+
# @return [Hash]
|
161
|
+
def self.parse(uri)
|
162
|
+
u = ::URI.split(uri)
|
163
|
+
{
|
164
|
+
'scheme' => u[0],
|
165
|
+
'user' => u[1],
|
166
|
+
'host' => u[2],
|
167
|
+
'port' => u[3],
|
168
|
+
'path' => u[5] || u[6], # 6 = mailto, opaque
|
169
|
+
'query' => u[7],
|
170
|
+
'fragment' => u[8]
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
# This function takes the components returned from PHP's parse_url, and uses
|
175
|
+
# it to generate a new uri.
|
176
|
+
#
|
177
|
+
# @param [Hash] parts
|
178
|
+
# @return [String]
|
179
|
+
def self.build(parts)
|
180
|
+
uri = ''
|
181
|
+
|
182
|
+
authority = ''
|
183
|
+
unless parts['host'].blank?
|
184
|
+
authority = parts['host']
|
185
|
+
|
186
|
+
authority = parts['user'] + '@' + authority unless parts['user'].blank?
|
187
|
+
authority = authority + ':' + parts['port'].to_s unless parts['port'].blank?
|
188
|
+
end
|
189
|
+
|
190
|
+
unless parts['scheme'].blank?
|
191
|
+
# If there's a scheme, there's also a host.
|
192
|
+
uri = parts['scheme'] + ':'
|
193
|
+
end
|
194
|
+
|
195
|
+
unless authority.blank?
|
196
|
+
# No scheme, but there is a host.
|
197
|
+
uri += '//' + authority
|
198
|
+
end
|
199
|
+
|
200
|
+
uri += parts['path'] unless parts['path'].blank?
|
201
|
+
uri += '?' + parts['query'] unless parts['query'].blank?
|
202
|
+
uri += '#' + parts['fragment'] unless parts['fragment'].blank?
|
203
|
+
|
204
|
+
uri
|
205
|
+
end
|
206
|
+
|
207
|
+
# Returns the 'dirname' and 'basename' for a path.
|
208
|
+
#
|
209
|
+
# The reason there is a custom function for this purpose, is because
|
210
|
+
# basename() is locale aware (behaviour changes if C locale or a UTF-8 locale
|
211
|
+
# is used) and we need a method that just operates on UTF-8 characters.
|
212
|
+
#
|
213
|
+
# In addition basename and dirname are platform aware, and will treat
|
214
|
+
# backslash (\) as a directory separator on windows.
|
215
|
+
#
|
216
|
+
# This method returns the 2 components as an array.
|
217
|
+
#
|
218
|
+
# If there is no dirname, it will return an empty string. Any / appearing at
|
219
|
+
# the end of the string is stripped off.
|
220
|
+
#
|
221
|
+
# @param [String] path
|
222
|
+
# @return [Array]
|
223
|
+
def self.split(path)
|
224
|
+
if path =~ %r{^(?:(?:(.*)(?:\/+))?([^\/]+))(?:\/?)$}u
|
225
|
+
[Regexp.last_match[1] || '', Regexp.last_match[2] || '']
|
226
|
+
else
|
227
|
+
[nil, nil]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
data/test/build_test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tilia
|
4
|
+
class BuildTest < Minitest::Test
|
5
|
+
def test_build
|
6
|
+
[
|
7
|
+
'http://example.org/',
|
8
|
+
'http://example.org/foo/bar',
|
9
|
+
'//example.org/foo/bar',
|
10
|
+
'/foo/bar',
|
11
|
+
'http://example.org:81/',
|
12
|
+
'http://user@example.org:81/',
|
13
|
+
'http://example.org:81/hi?a=b',
|
14
|
+
'http://example.org:81/hi?a=b#c=d',
|
15
|
+
# '//example.org:81/hi?a=b#c=d', Currently fails due to a
|
16
|
+
# PHP bug.
|
17
|
+
'/hi?a=b#c=d',
|
18
|
+
'?a=b#c=d',
|
19
|
+
'#c=d'
|
20
|
+
].each do |value|
|
21
|
+
assert_equal(value, Uri.build(Uri.parse(value)))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tilia
|
4
|
+
class NormalizeTest < Minitest::Test
|
5
|
+
def test_normalize
|
6
|
+
{
|
7
|
+
'http://example.org/' => 'http://example.org/',
|
8
|
+
'HTTP://www.EXAMPLE.com/' => 'http://www.example.com/',
|
9
|
+
'http://example.org/%7Eevert' => 'http://example.org/~evert',
|
10
|
+
'http://example.org/./evert' => 'http://example.org/evert',
|
11
|
+
'http://example.org/../evert' => 'http://example.org/evert',
|
12
|
+
'http://example.org/foo/../evert' => 'http://example.org/evert',
|
13
|
+
'/%41' => '/A',
|
14
|
+
'/%3F' => '/%3F',
|
15
|
+
'/%3f' => '/%3F',
|
16
|
+
'http://example.org' => 'http://example.org/',
|
17
|
+
'http://example.org:/' => 'http://example.org/',
|
18
|
+
'http://example.org:80/' => 'http://example.org/'
|
19
|
+
}.each do |input, output|
|
20
|
+
assert_equal(output, Uri.normalize(input))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tilia
|
4
|
+
class ResolveTest < Minitest::Test
|
5
|
+
def test_resolve
|
6
|
+
[
|
7
|
+
[
|
8
|
+
'http://example.org/foo/baz',
|
9
|
+
'/bar',
|
10
|
+
'http://example.org/bar'
|
11
|
+
],
|
12
|
+
[
|
13
|
+
'https://example.org/foo',
|
14
|
+
'//example.net/',
|
15
|
+
'https://example.net/'
|
16
|
+
],
|
17
|
+
[
|
18
|
+
'https://example.org/foo',
|
19
|
+
'?a=b',
|
20
|
+
'https://example.org/foo?a=b'
|
21
|
+
],
|
22
|
+
[
|
23
|
+
'//example.org/foo',
|
24
|
+
'?a=b',
|
25
|
+
'//example.org/foo?a=b'
|
26
|
+
],
|
27
|
+
# Ports and fragments
|
28
|
+
[
|
29
|
+
'https://example.org:81/foo#hey',
|
30
|
+
'?a=b#c=d',
|
31
|
+
'https://example.org:81/foo?a=b#c=d'
|
32
|
+
],
|
33
|
+
# Relative.. in-directory paths
|
34
|
+
[
|
35
|
+
'http://example.org/foo/bar',
|
36
|
+
'bar2',
|
37
|
+
'http://example.org/foo/bar2'
|
38
|
+
],
|
39
|
+
# Now the base path ended with a slash
|
40
|
+
[
|
41
|
+
'http://example.org/foo/bar/',
|
42
|
+
'bar2/bar3',
|
43
|
+
'http://example.org/foo/bar/bar2/bar3'
|
44
|
+
],
|
45
|
+
# .. and .
|
46
|
+
[
|
47
|
+
'http://example.org/foo/bar/',
|
48
|
+
'../bar2/.././/bar3/',
|
49
|
+
'http://example.org/foo//bar3/'
|
50
|
+
],
|
51
|
+
# Only updating the fragment
|
52
|
+
[
|
53
|
+
'https://example.org/foo?a=b',
|
54
|
+
'#comments',
|
55
|
+
'https://example.org/foo?a=b#comments'
|
56
|
+
],
|
57
|
+
# Switching to mailto!
|
58
|
+
[
|
59
|
+
'https://example.org/foo?a=b',
|
60
|
+
'mailto:foo@example.org',
|
61
|
+
'mailto:foo@example.org'
|
62
|
+
]
|
63
|
+
].each do |data|
|
64
|
+
(base, update, expected) = data
|
65
|
+
assert_equal(expected, Uri.resolve(base, update))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/test/split_test.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tilia
|
4
|
+
class SplitTest < Minitest::Test
|
5
|
+
def test_split
|
6
|
+
{
|
7
|
+
# input expected result
|
8
|
+
'/foo/bar' => ['/foo', 'bar'],
|
9
|
+
'/foo/bar/' => ['/foo', 'bar'],
|
10
|
+
'foo/bar/' => ['foo', 'bar'],
|
11
|
+
'foo/bar' => ['foo', 'bar'],
|
12
|
+
'foo/bar/baz' => ['foo/bar', 'baz'],
|
13
|
+
'foo/bar/baz/' => ['foo/bar', 'baz'],
|
14
|
+
'foo' => ['', 'foo'],
|
15
|
+
'foo/' => ['', 'foo'],
|
16
|
+
'/foo/' => ['', 'foo'],
|
17
|
+
'/foo' => ['', 'foo'],
|
18
|
+
'' => [nil, nil],
|
19
|
+
|
20
|
+
# UTF-8
|
21
|
+
"/\xC3\xA0fo\xC3\xB3/bar" => ["/\xC3\xA0fo\xC3\xB3", 'bar'],
|
22
|
+
"/\xC3\xA0foo/b\xC3\xBCr/" => ["/\xC3\xA0foo", "b\xC3\xBCr"],
|
23
|
+
"foo/\xC3\xA0\xC3\xBCr" => ['foo', "\xC3\xA0\xC3\xBCr"]
|
24
|
+
}.each do |input, expected|
|
25
|
+
assert_equal(expected, Uri.split(input))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/test/test_helper.rb
ADDED
data/tilia-uri.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'lib', 'tilia', 'uri', 'version')
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'tilia-uri'
|
4
|
+
s.version = Tilia::Uri::Version::VERSION
|
5
|
+
s.licenses = ['BSD-3-Clause']
|
6
|
+
s.summary = 'Port of the sabre-uri library to ruby'
|
7
|
+
s.description = 'Functions for making sense out of URIs.'
|
8
|
+
s.author = 'Jakob Sack'
|
9
|
+
s.email = 'tilia@jakobsack.de'
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.homepage = 'https://github.com/tilia/tilia-uri'
|
12
|
+
s.add_runtime_dependency 'activesupport', '~> 4.2'
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tilia-uri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakob Sack
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
description: Functions for making sense out of URIs.
|
28
|
+
email: tilia@jakobsack.de
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- ".gitignore"
|
34
|
+
- ".rubocop.yml"
|
35
|
+
- ".simplecov"
|
36
|
+
- ".travis.yml"
|
37
|
+
- CHANGELOG.sabre.md
|
38
|
+
- CONTRIBUTING.md
|
39
|
+
- Gemfile
|
40
|
+
- Gemfile.lock
|
41
|
+
- LICENSE
|
42
|
+
- LICENSE.sabre
|
43
|
+
- README.md
|
44
|
+
- Rakefile
|
45
|
+
- lib/tilia/uri.rb
|
46
|
+
- lib/tilia/uri/version.rb
|
47
|
+
- test/build_test.rb
|
48
|
+
- test/normalize_test.rb
|
49
|
+
- test/resolve_test.rb
|
50
|
+
- test/split_test.rb
|
51
|
+
- test/test_helper.rb
|
52
|
+
- tilia-uri.gemspec
|
53
|
+
homepage: https://github.com/tilia/tilia-uri
|
54
|
+
licenses:
|
55
|
+
- BSD-3-Clause
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 2.2.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Port of the sabre-uri library to ruby
|
77
|
+
test_files: []
|
78
|
+
has_rdoc:
|