tilia-uri 1.0.1
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.
- 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
|
+
[](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:
|