uniform_resource_identifier 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Ryan Scott Lewis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,214 @@
1
+ require 'uniform_resource_identifier/authority'
2
+ require 'uniform_resource_identifier/relative'
3
+
4
+ class UniformResourceIdentifier
5
+ extend Parsable
6
+
7
+ def initialize(uri=nil)
8
+ if uri.respond_to?(:to_str)
9
+ parsed_uri = Parser.parse(uri)
10
+
11
+ @protocol = parsed_uri[:protocol]
12
+
13
+ @authority = Authority.new(
14
+ :user_info => {
15
+ :username => parsed_uri[:username],
16
+ :password => parsed_uri[:password]
17
+ },
18
+ :host => parsed_uri[:host],
19
+ :port => parsed_uri[:port]
20
+ )
21
+
22
+ @relative = Relative.new(
23
+ :path => {
24
+ :directory => parsed_uri[:directory],
25
+ :file => parsed_uri[:file]
26
+ },
27
+ :query => parsed_uri[:query],
28
+ :anchor => parsed_uri[:anchor]
29
+ )
30
+ elsif uri.respond_to?(:to_hash)
31
+ uri = uri.to_hash.symbolize_keys
32
+
33
+ @protocol = uri[:protocol].to_s if uri.has_key?(:protocol)
34
+ @authority = Authority.parse(uri[:authority]) if uri.has_key?(:authority)
35
+ @relative = Relative.parse(uri[:relative]) if uri.has_key?(:relative)
36
+ else
37
+ raise(TypeError, "uri must either be a String or a Hash") unless uri.nil?
38
+ end
39
+ end
40
+
41
+ def to_s
42
+ protocol = "#{@protocol}://" unless @protocol.nil?
43
+ "#{protocol}#{@authority}#{@relative}"
44
+ end
45
+
46
+ def to_h
47
+ {
48
+ :protocol => @protocol,
49
+ :authority => @authority.nil? ? nil : @authority.to_h,
50
+ :relative => @relative.nil? ? nil : @relative.to_h
51
+ }
52
+ end
53
+
54
+ # ======================================================================= #
55
+ # = Attributes = #
56
+ # ======================================================================= #
57
+
58
+ attr_reader :protocol
59
+
60
+ def protocol=(protocol)
61
+ @protocol = protocol.nil? ? nil : protocol.to_s
62
+ end
63
+
64
+ alias_method :scheme, :protocol
65
+ alias_method :scheme=, :protocol=
66
+
67
+ def authority
68
+ @authority ||= Authority.new
69
+ end
70
+
71
+ def authority=(authority)
72
+ @authority = Authority.parse(authority)
73
+ end
74
+
75
+ def relative
76
+ @relative ||= Relative.new
77
+ end
78
+
79
+ def relative=(relative)
80
+ @relative = Relative.parse(relative)
81
+ end
82
+
83
+ # ======================================================================= #
84
+ # = Delegates = #
85
+ # ======================================================================= #
86
+
87
+ def user_info
88
+ self.authority.user_info
89
+ end
90
+
91
+ def user_info=(user_info)
92
+ self.authority.user_info = user_info
93
+ end
94
+
95
+ def username
96
+ self.authority.user_info.username
97
+ end
98
+
99
+ def username=(username)
100
+ self.authority.user_info.username = username
101
+ end
102
+
103
+ def password
104
+ self.authority.user_info.password
105
+ end
106
+
107
+ def password=(password)
108
+ self.authority.user_info.password = password
109
+ end
110
+
111
+ def host
112
+ self.authority.host
113
+ end
114
+
115
+ def host=(host)
116
+ self.authority.host = host
117
+ end
118
+
119
+ def subdomain
120
+ self.authority.host.subdomain
121
+ end
122
+
123
+ def subdomain=(subdomain)
124
+ self.authority.host.subdomain = subdomain
125
+ end
126
+
127
+ def domain
128
+ self.authority.host.domain ||= Domain.new
129
+ end
130
+
131
+ def domain=(domain)
132
+ self.authority.host.domain = Domain.parse(domain)
133
+ end
134
+
135
+ def sld
136
+ self.authority.host.domain.sld
137
+ end
138
+
139
+ def sld=(sld)
140
+ self.authority.host.domain.sld = sld
141
+ end
142
+
143
+ def tld
144
+ self.authority.host.domain.tld
145
+ end
146
+
147
+ def tld=(sld)
148
+ self.authority.host.domain.tld = tld
149
+ end
150
+
151
+ def port
152
+ self.authority.port
153
+ end
154
+
155
+ def port=(port)
156
+ self.authority.port = port
157
+ end
158
+
159
+ def path
160
+ self.relative.path
161
+ end
162
+
163
+ def path=(path)
164
+ self.relative.path = path
165
+ end
166
+
167
+ def directory
168
+ self.relative.path.directory
169
+ end
170
+
171
+ def directory=(directory)
172
+ self.relative.path.directory = directory
173
+ end
174
+
175
+ def file
176
+ self.relative.path.file
177
+ end
178
+
179
+ def file=(file)
180
+ self.relative.path.file = file
181
+ end
182
+
183
+ def query
184
+ self.relative.query
185
+ end
186
+
187
+ def query=(query)
188
+ self.relative.query = query
189
+ end
190
+
191
+ def anchor
192
+ self.relative.anchor
193
+ end
194
+
195
+ def anchor=(anchor)
196
+ self.relative.anchor = anchor
197
+ end
198
+
199
+ # ======================================================================= #
200
+ # = Extras = #
201
+ # ======================================================================= #
202
+
203
+ def relative?
204
+ self.host.nil?
205
+ end
206
+
207
+ def absolute?
208
+ !relative?
209
+ end
210
+
211
+ def localhost?
212
+ !!(self.host =~ /^localhost$/i)
213
+ end
214
+ end
@@ -0,0 +1,121 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'uniform_resource_identifier/parser'
3
+ require 'uniform_resource_identifier/host'
4
+ require 'uniform_resource_identifier/user_info'
5
+ require 'active_support/core_ext/hash'
6
+
7
+ class UniformResourceIdentifier
8
+ class Authority
9
+ extend Parsable
10
+
11
+ def initialize(authority=nil)
12
+ if authority.respond_to?(:to_str)
13
+ authority = Parser.parse(authority)
14
+
15
+ @user_info = UserInfo.parse(authority[:user_info]) if authority.has_key?(:user_info)
16
+ @host = Host.parse(authority[:host]) if authority.has_key?(:host)
17
+ @port = authority[:port].to_i if authority.has_key?(:port)
18
+ elsif authority.respond_to?(:to_hash)
19
+ authority = authority.to_hash.symbolize_keys
20
+
21
+ @user_info = UserInfo.parse(authority[:user_info]) if authority.has_key?(:user_info)
22
+ @host = Host.parse(authority[:host]) if authority.has_key?(:host)
23
+ @port = authority[:port].to_i if authority.has_key?(:port)
24
+ else
25
+ raise(TypeError, "authority must either be a String or a Hash") unless authority.nil?
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ user_info = "#{@user_info}@" unless @user_info.nil?
31
+ port = ":#{@port}" unless @port.nil?
32
+ "#{user_info}#{@host}#{port}"
33
+ end
34
+
35
+ def to_h
36
+ {
37
+ :user_info => user_info.nil? ? nil : @user_info.to_h,
38
+ :host => host.nil? ? nil : @host.to_h,
39
+ :port => @port
40
+ }
41
+ end
42
+
43
+ # ======================================================================= #
44
+ # = Attributes = #
45
+ # ======================================================================= #
46
+
47
+ def user_info
48
+ @user_info ||= UserInfo.new
49
+ end
50
+
51
+ def user_info=(user_info)
52
+ @user_info = UserInfo.parse(user_info)
53
+ end
54
+
55
+ def host
56
+ @host ||= Host.new
57
+ end
58
+
59
+ def host=(host)
60
+ @host = Host.parse(user_info)
61
+ end
62
+
63
+ attr_reader :port
64
+
65
+ def port=(port)
66
+ @port = port.to_i
67
+ end
68
+
69
+ # ======================================================================= #
70
+ # = Delegates = #
71
+ # ======================================================================= #
72
+
73
+ def username
74
+ self.user_info.username
75
+ end
76
+
77
+ def username=(username)
78
+ self.user_info.username = username
79
+ end
80
+
81
+ def password
82
+ self.user_info.password
83
+ end
84
+
85
+ def password=(password)
86
+ self.user_info.password = password
87
+ end
88
+
89
+ def subdomain
90
+ self.host.subdomain
91
+ end
92
+
93
+ def subdomain=(subdomain)
94
+ self.host.subdomain = subdomain
95
+ end
96
+
97
+ def domain
98
+ self.host.domain ||= Domain.new
99
+ end
100
+
101
+ def domain=(domain)
102
+ self.host.domain = Domain.parse(domain)
103
+ end
104
+
105
+ def sld
106
+ self.host.domain.sld
107
+ end
108
+
109
+ def sld=(sld)
110
+ self.host.domain.sld = sld
111
+ end
112
+
113
+ def tld
114
+ self.host.domain.tld
115
+ end
116
+
117
+ def tld=(sld)
118
+ self.host.domain.tld = tld
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,50 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'active_support/core_ext/hash'
3
+ require 'public_suffix_service'
4
+
5
+ class UniformResourceIdentifier
6
+ class Domain
7
+ extend Parsable
8
+
9
+ def initialize(domain)
10
+ if domain.respond_to?(:to_str)
11
+ begin
12
+ pss = PublicSuffixService.parse(domain)
13
+
14
+ @sld, @tld = pss.sld, pss.tld
15
+ rescue PublicSuffixService::DomainInvalid
16
+ # We couldn't parse your tld (public suffix) =(
17
+ @tld = domain
18
+ end
19
+ elsif domain.respond_to?(:to_hash)
20
+ domain.to_hash.symbolize_keys
21
+ @sld, @tld = domain.values_at(:sld, :tld)
22
+ else
23
+ raise(TypeError, "domain must either be a String or a Hash") unless domain.nil?
24
+ end
25
+ end
26
+
27
+ def to_s
28
+ sld = "#{@sld}." unless @sld.nil?
29
+ "#{sld}#{@tld}"
30
+ end
31
+
32
+ def to_h
33
+ { :sld => @sld, :tld => @tld }
34
+ end
35
+ # ======================================================================= #
36
+ # = Attributes = #
37
+ # ======================================================================= #
38
+
39
+ attr_reader :sld
40
+ attr_reader :tld
41
+
42
+ def sld=(sld)
43
+ @sld = sld.nil? ? nil : sld.to_s
44
+ end
45
+
46
+ def tld=(tld)
47
+ @tld = tld.nil? ? nil : tld.to_s
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,81 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'uniform_resource_identifier/domain'
3
+ require 'active_support/core_ext/hash'
4
+ require 'public_suffix_service'
5
+
6
+ class UniformResourceIdentifier
7
+ class Host
8
+ extend Parsable
9
+
10
+ def initialize(host=nil)
11
+ if host.respond_to?(:to_str)
12
+ begin
13
+ pss = PublicSuffixService.parse(host)
14
+
15
+ @subdomain = pss.trd
16
+ @domain = Domain.new(:sld => pss.sld, :tld => pss.tld)
17
+ rescue PublicSuffixService::DomainInvalid
18
+ # We couldn't parse your tld (public suffix) =(
19
+ @domain = Domain.new(:sld => nil, :tld => host) # TODO: is this proper? see Domain#to_s
20
+ end
21
+ elsif host.respond_to?(:to_hash)
22
+ host = host.to_hash.symbolize_keys
23
+
24
+ @subdomain = host[:subdomain]
25
+ @domain = Domain.new(host[:domain])
26
+ else
27
+ raise(TypeError, "host must either be a String or a Hash") unless host.nil?
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ subdomain = "#{@subdomain}." unless @subdomain.nil?
33
+ "#{subdomain}#{@domain}"
34
+ end
35
+
36
+ def to_h
37
+ {
38
+ :subdomain => @subdomain,
39
+ :domain => @domain.nil? ? nil : @domain.to_h
40
+ }
41
+ end
42
+
43
+ # ======================================================================= #
44
+ # = Attributes = #
45
+ # ======================================================================= #
46
+
47
+ attr_reader :subdomain
48
+
49
+ def subdomain=(subdomain)
50
+ @subdomain = subdomain.nil? ? subdomain : subdomain.to_s
51
+ end
52
+
53
+ def domain
54
+ @domain ||= Domain.new
55
+ end
56
+
57
+ def domain=(domain)
58
+ @domain = Domain.parse(domain)
59
+ end
60
+
61
+ # ======================================================================= #
62
+ # = Delegates = #
63
+ # ======================================================================= #
64
+
65
+ def sld
66
+ self.domain.sld
67
+ end
68
+
69
+ def sld=(sld)
70
+ self.domain.sld = sld
71
+ end
72
+
73
+ def tld
74
+ self.domain.tld
75
+ end
76
+
77
+ def tld=(sld)
78
+ self.domain.tld = tld
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,7 @@
1
+ class UniformResourceIdentifier
2
+ module Parsable
3
+ def parse(input)
4
+ input.is_a?(self) ? input : new(input)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ class UniformResourceIdentifier
2
+ module Parser
3
+ STRICT = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/
4
+ LOOSE = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
5
+
6
+ # Simply returns a Hash containing the captures
7
+ # mode can either be :strict or :loose
8
+ def self.parse(uri, mode=:loose)
9
+ raise(ArgumentError, "mode must either be :loose or :strict") unless [:loose, :strict].include?(mode)
10
+
11
+ regexp = mode == :loose ? LOOSE : STRICT
12
+ match = uri.match(regexp)
13
+ keys = [:protocol, :authority, :user_info, :username, :password, :host,
14
+ :port, :relative, :path, :directory, :file, :query, :anchor]
15
+
16
+ keys.each.with_index.inject({}) do |memo, (key, index)|
17
+ memo[key] = match.captures[index]
18
+ memo
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'uniform_resource_identifier/parser'
3
+ require 'active_support/core_ext/hash'
4
+
5
+ class UniformResourceIdentifier
6
+ class Path
7
+ extend Parsable
8
+
9
+ def initialize(path)
10
+ if path.respond_to?(:to_str)
11
+ parsed_uri = Parser.parse(path)
12
+ @directory, @file = parsed_uri.values_at(:directory, :file)
13
+ elsif path.respond_to?(:to_hash)
14
+ path.to_hash.symbolize_keys
15
+ @directory, @file = path.values_at(:directory, :file)
16
+ else
17
+ raise(TypeError, "path must either be a String or a Hash") unless path.nil?
18
+ end
19
+ end
20
+
21
+ def to_s
22
+ "#{@directory}#{@file}"
23
+ end
24
+
25
+ def to_h
26
+ {
27
+ :directory => @directory,
28
+ :file => @file
29
+ }
30
+ end
31
+ # ======================================================================= #
32
+ # = Attributes = #
33
+ # ======================================================================= #
34
+
35
+ attr_reader :directory
36
+ attr_reader :file
37
+
38
+ def directory=(directory)
39
+ @directory = directory.nil? ? nil : directory.to_s
40
+ end
41
+
42
+ def file=(file)
43
+ @file = file.nil? ? nil : file.to_s
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,28 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'active_support/core_ext/object/to_query'
3
+ require 'addressable/uri'
4
+
5
+ class UniformResourceIdentifier
6
+ class Query
7
+ extend Parsable
8
+
9
+ def initialize(query)
10
+ if query.respond_to?(:to_str)
11
+ query = "#{query =~ /^\?/ ? nil : '?'}#{query.to_str}" # Prepend a question mark if needed
12
+ @query = Addressable::URI.parse(query).query_values
13
+ elsif query.respond_to?(:to_hash)
14
+ @query = query.to_hash
15
+ else
16
+ raise(TypeError, "query must either be a String or a Hash") unless query.nil?
17
+ end
18
+ end
19
+
20
+ def to_s
21
+ @query.to_query
22
+ end
23
+
24
+ def to_h
25
+ @query
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,86 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'uniform_resource_identifier/parser'
3
+ require 'uniform_resource_identifier/path'
4
+ require 'uniform_resource_identifier/query'
5
+ require 'active_support/core_ext/hash'
6
+
7
+ class UniformResourceIdentifier
8
+ class Relative
9
+ extend Parsable
10
+
11
+ def initialize(relative=nil)
12
+ if relative.respond_to?(:to_str)
13
+ parsed_uri = Parser.parse(relative)
14
+ # TODO
15
+ elsif relative.respond_to?(:to_hash)
16
+ relative = relative.to_hash.symbolize_keys
17
+
18
+ @path = Path.parse(relative[:path]) if relative.has_key?(:path)
19
+ @query = Query.parse(relative[:query]) if relative.has_key?(:query)
20
+ @anchor = relative[:anchor].to_s.gsub(/^#/, '') if relative.has_key?(:anchor)
21
+ else
22
+ raise(TypeError, "relative must either be a String or a Hash") unless relative.nil?
23
+ end
24
+ end
25
+
26
+ def to_s
27
+ query = "?#{@query}" unless @query.nil?
28
+ anchor = "##{@anchor}" unless @anchor.nil?
29
+ "#{@path}#{query}#{anchor}"
30
+ end
31
+
32
+ def to_h
33
+ {
34
+ :path => path.nil? ? nil : @path.to_h,
35
+ :query => query.nil? ? nil : @query.to_h,
36
+ :anchor => @anchor
37
+ }
38
+ end
39
+
40
+ # ======================================================================= #
41
+ # = Attributes = #
42
+ # ======================================================================= #
43
+
44
+ def path
45
+ @path ||= Path.new
46
+ end
47
+
48
+ def path=(path)
49
+ @path = Path.parse(path)
50
+ end
51
+
52
+ def query
53
+ @query ||= Query.new
54
+ end
55
+
56
+ def query=(query)
57
+ @query = Query.parse(query)
58
+ end
59
+
60
+ attr_reader :anchor
61
+
62
+ def anchor=(anchor)
63
+ @anchor = anchor.nil? ? nil : anchor.to_s
64
+ end
65
+
66
+ # ======================================================================= #
67
+ # = Delegates = #
68
+ # ======================================================================= #
69
+
70
+ def directory
71
+ self.path.directory
72
+ end
73
+
74
+ def directory=(directory)
75
+ self.path.directory = directory
76
+ end
77
+
78
+ def file
79
+ self.path.file
80
+ end
81
+
82
+ def file=(file)
83
+ self.path.file = file
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,114 @@
1
+ RSpec::Matchers.define(:have_uri_specification) do |uri_specification|
2
+ match do |uri_string|
3
+ url = UniformResourceIdentifier.parse(uri_string)
4
+
5
+ # ======================================================================= #
6
+ # = Protocol/Scheme = #
7
+ # ======================================================================= #
8
+
9
+ url.protocol.class.should == String
10
+ url.protocol.to_s.should == uri_specification[:protocol]
11
+ url.scheme.class.should == String # Alias
12
+ url.scheme.to_s.should == uri_specification[:protocol] # Alias
13
+
14
+ # ======================================================================= #
15
+ # = Authority = #
16
+ # ======================================================================= #
17
+
18
+ url.authority.class.should == UniformResourceIdentifier::Authority
19
+ url.authority.to_s.should == uri_specification[:authority]
20
+
21
+ url.authority.user_info.class.should == UniformResourceIdentifier::UserInfo
22
+ url.authority.user_info.to_s.should == uri_specification[:user_info]
23
+ url.user_info.class.should == UniformResourceIdentifier::UserInfo # Delegate
24
+ url.user_info.to_s.should == uri_specification[:user_info] # Delegate
25
+
26
+ url.authority.user_info.username.class.should == String
27
+ url.authority.user_info.username.to_s.should == uri_specification[:username]
28
+ url.user_info.username.class.should == String # Delegate
29
+ url.user_info.username.to_s.should == uri_specification[:username] # Delegate
30
+ url.username.class.should == String # Delegate
31
+ url.username.to_s.should == uri_specification[:username] # Delegate
32
+
33
+ url.authority.user_info.password.class.should == String
34
+ url.authority.user_info.password.to_s.should == uri_specification[:password]
35
+ url.user_info.password.class.should == String # Delegate
36
+ url.user_info.password.to_s.should == uri_specification[:password] # Delegate
37
+ url.password.class.should == String # Delegate
38
+ url.password.to_s.should == uri_specification[:password] # Delegate
39
+
40
+ url.authority.host.class.should == UniformResourceIdentifier::Host
41
+ url.authority.host.to_s.should == uri_specification[:host]
42
+ url.host.class.should == UniformResourceIdentifier::Host # Delegate
43
+ url.host.to_s.should == uri_specification[:host] # Delegate
44
+
45
+ url.authority.host.subdomain.class.should == String
46
+ url.authority.host.subdomain.to_s.should == uri_specification[:subdomain]
47
+ url.host.subdomain.class.should == String # Delegate
48
+ url.host.subdomain.to_s.should == uri_specification[:subdomain] # Delegate
49
+ url.subdomain.class.should == String # Delegate
50
+ url.subdomain.to_s.should == uri_specification[:subdomain] # Delegate
51
+
52
+ url.authority.host.domain.class.should == UniformResourceIdentifier::Domain
53
+ url.authority.host.domain.to_s.should == uri_specification[:domain]
54
+ url.host.domain.class.should == UniformResourceIdentifier::Domain # Delegate
55
+ url.host.domain.to_s.should == uri_specification[:domain] # Delegate
56
+ url.domain.class.should == UniformResourceIdentifier::Domain # Delegate
57
+ url.domain.to_s.should == uri_specification[:domain] # Delegate
58
+
59
+ url.authority.host.domain.sld.class.should == String
60
+ url.authority.host.sld.to_s.should == uri_specification[:sld]
61
+ url.host.sld.class.should == String # Delegate
62
+ url.host.sld.to_s.should == uri_specification[:sld] # Delegate
63
+ url.sld.class.should == String # Delegate
64
+ url.sld.to_s.should == uri_specification[:sld] # Delegate
65
+
66
+ url.authority.host.domain.tld.class.should == String
67
+ url.authority.host.tld.to_s.should == uri_specification[:tld]
68
+ url.host.tld.class.should == String # Delegate
69
+ url.host.tld.to_s.should == uri_specification[:tld] # Delegate
70
+ url.tld.class.should == String # Delegate
71
+ url.tld.to_s.should == uri_specification[:tld] # Delegate
72
+
73
+ url.authority.port.class.should == Fixnum
74
+ url.authority.port.to_s.should == uri_specification[:port]
75
+ url.port.class.should == Fixnum # Delegate
76
+ url.port.to_s.should == uri_specification[:port] # Delegate
77
+
78
+ # ======================================================================= #
79
+ # = Relative = #
80
+ # ======================================================================= #
81
+
82
+ url.relative.class.should == UniformResourceIdentifier::Relative
83
+ url.relative.to_s.should == uri_specification[:relative]
84
+
85
+ url.relative.path.class.should == UniformResourceIdentifier::Path
86
+ url.relative.path.to_s.should == uri_specification[:path]
87
+ url.path.class.should == UniformResourceIdentifier::Path # Delegate
88
+ url.path.to_s.should == uri_specification[:path] # Delegate
89
+
90
+ url.relative.path.directory.class.should == String
91
+ url.relative.path.directory.to_s.should == uri_specification[:directory]
92
+ url.relative.directory.class.should == String # Delegate
93
+ url.relative.directory.to_s.should == uri_specification[:directory] # Delegate
94
+ url.directory.class.should == String # Delegate
95
+ url.directory.to_s.should == uri_specification[:directory] # Delegate
96
+
97
+ url.relative.path.file.class.should == String
98
+ url.relative.path.file.to_s.should == uri_specification[:file]
99
+ url.relative.file.class.should == String # Delegate
100
+ url.relative.file.to_s.should == uri_specification[:file] # Delegate
101
+ url.file.class.should == String # Delegate
102
+ url.file.to_s.should == uri_specification[:file] # Delegate
103
+
104
+ url.relative.query.class.should == UniformResourceIdentifier::Query
105
+ url.relative.query.to_s.should == uri_specification[:query]
106
+ url.query.class.should == UniformResourceIdentifier::Query # Delegate
107
+ url.query.to_s.should == uri_specification[:query] # Delegate
108
+
109
+ url.relative.anchor.class.should == String
110
+ url.relative.anchor.to_s.should == uri_specification[:anchor]
111
+ url.anchor.class.should == String # Delegate
112
+ url.anchor.to_s.should == uri_specification[:anchor] # Delegate
113
+ end
114
+ end
@@ -0,0 +1,44 @@
1
+ require 'uniform_resource_identifier/parsable'
2
+ require 'active_support/core_ext/hash'
3
+
4
+ class UniformResourceIdentifier
5
+ class UserInfo
6
+ extend Parsable
7
+
8
+ def initialize(user_info=nil)
9
+ if user_info.respond_to?(:to_str)
10
+ @username, @password = user_info.to_str.split(":")
11
+ elsif user_info.respond_to?(:to_hash)
12
+ user_info.to_hash.symbolize_keys
13
+ @username, @password = user_info.values_at(:username, :password)
14
+ else
15
+ raise(TypeError, "user_info must either be a String or a Hash") unless user_info.nil?
16
+ end
17
+ end
18
+
19
+ def to_s
20
+ "#{@username}:#{@password}"
21
+ end
22
+
23
+ def to_h
24
+ {
25
+ :username => @username,
26
+ :password => @password
27
+ }
28
+ end
29
+ # ======================================================================= #
30
+ # = Attributes = #
31
+ # ======================================================================= #
32
+
33
+ attr_reader :username
34
+ attr_reader :password
35
+
36
+ def username=(username)
37
+ @username = username.nil? ? username : username.to_s
38
+ end
39
+
40
+ def password=(password)
41
+ @password = password.nil? ? password : password.to_s
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'uniform_resource_identifier'
4
+ require 'uniform_resource_identifier/rspec_matcher'
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe UniformResourceIdentifier::Parser do
4
+ subject { UniformResourceIdentifier::Parser }
5
+
6
+ describe "#parse" do
7
+ it "should return a Hash containing the correct results" do
8
+ url = "http://usr:pwd@www.test.com:81/dir/dir.2/foo/bar/index.htm?q1=0&&test1&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3#top"
9
+
10
+ result_hash = {
11
+ :protocol => "http",
12
+ :authority => "usr:pwd@www.test.com:81",
13
+ :user_info => "usr:pwd",
14
+ :username => "usr",
15
+ :password => "pwd",
16
+ :host => "www.test.com",
17
+ :port => "81",
18
+ :relative => "/dir/dir.2/foo/bar/index.htm?q1=0&&test1&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3#top",
19
+ :path => "/dir/dir.2/foo/bar/index.htm",
20
+ :directory => "/dir/dir.2/foo/bar/",
21
+ :file => "index.htm",
22
+ :query => "q1=0&&test1&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3",
23
+ :anchor => "top"
24
+ }
25
+
26
+ subject.parse(url, :loose).should == result_hash
27
+ subject.parse(url, :strict).should == result_hash
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+
3
+ # Example URIs:
4
+ # ftp://ftp.is.co.za/rfc/rfc1808.txt
5
+ # http://www.ietf.org/rfc/rfc2396.txt
6
+ # ldap://[2001:db8::7]/c=GB?objectClass?one
7
+ # mailto:John.Doe@example.com
8
+ # news:comp.infosystems.www.servers.unix
9
+ # tel:+1-816-555-1212
10
+ # telnet://192.0.2.16:80/
11
+ # urn:oasis:names:specification:docbook:dtd:xml:4.1.2
12
+ # http://www.foobar.com/test/bar?q=some+thing
13
+ # www.foobar.com/
14
+ # foobar.com/contact_us
15
+ # admin.foobar.com/task/123
16
+ # admin.testpage.com
17
+ # /about
18
+ # index.htm
19
+ # awesome-things.org/thing/42
20
+ # foo-bar.org/mist
21
+ # water.com
22
+ # https://www.water.org/ice
23
+ # http://example.org/absolute/URI/with/absolute/path/to/resource.txt
24
+ # ftp://example.org/resource.txt
25
+ # http://en.wikipedia.org/wiki/URI#Examples_of_URI_references
26
+ # http://example.org/absolute/URI/with/absolute/path/to/resource.txt
27
+ # //example.org/scheme-relative/URI/with/absolute/path/to/resource.txt
28
+ # /relative/URI/with/absolute/path/to/resource.txt
29
+ # relative/path/to/resource.txt
30
+ # ../../../resource.txt
31
+ # ./resource.txt#frag01
32
+ # resource.txt
33
+ # #frag01
34
+ # http://en.wikipedia.org/wiki/Uniform_Resource_Identifier
35
+ # http://the_english_dept.tripod.com/north.html
36
+
37
+ describe UniformResourceIdentifier do
38
+ subject { UniformResourceIdentifier }
39
+
40
+ let(:url) do
41
+ "http://usr:pwd@www.test.com:81/dir/dir.2/foo/bar/index.htm?q1=0&&test1&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3#top"
42
+ end
43
+
44
+ describe "#parse" do
45
+ it "should correctly parse the given URL" do
46
+ url.should have_uri_specification(
47
+ :protocol => "http",
48
+ :authority => "usr:pwd@www.test.com:81",
49
+ :user_info => "usr:pwd",
50
+ :username => "usr",
51
+ :password => "pwd",
52
+ :host => "www.test.com",
53
+ :subdomain => "www",
54
+ :domain => "test.com",
55
+ :sld => "test",
56
+ :tld => "com",
57
+ :port => "81",
58
+ :relative => "/dir/dir.2/foo/bar/index.htm?q1=0&test1=true&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3#top",
59
+ :path => "/dir/dir.2/foo/bar/index.htm",
60
+ :directory => "/dir/dir.2/foo/bar/",
61
+ :file => "index.htm",
62
+ :query => "q1=0&test1=true&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3",
63
+ :anchor => "top"
64
+ )
65
+ end
66
+ end
67
+
68
+ describe "#to_s" do
69
+ it "should return the normalized URI" do
70
+ subject.parse(url).to_s.should == "http://usr:pwd@www.test.com:81/dir/dir.2/foo/bar/index.htm?q1=0&test1=true&test2=value&arr[]=one&arr[]=two&hsh[foo]=bar&test3=val3#top"
71
+ end
72
+ end
73
+
74
+ describe "#to_h" do
75
+ it "should return the correct Hash result" do
76
+ subject.parse(url).to_h.should == {
77
+ :protocol =>"http",
78
+ :authority => {
79
+ :user_info => {
80
+ :username => "usr",
81
+ :password => "pwd"
82
+ },
83
+ :host => {
84
+ :subdomain => "www",
85
+ :domain => {
86
+ :sld => "test",
87
+ :tld => "com"
88
+ }
89
+ },
90
+ :port => 81
91
+ },
92
+ :relative => {
93
+ :path => {
94
+ :directory => "/dir/dir.2/foo/bar/",
95
+ :file => "index.htm"
96
+ },
97
+ :query => { # TODO: Should the query_values be strings?
98
+ "q1" => "0",
99
+ "test1" => true,
100
+ "test2" => "value",
101
+ "arr" => ["one", "two"],
102
+ "hsh" => {
103
+ "foo" => "bar"
104
+ },
105
+ "test3" => "val3"
106
+ },
107
+ :anchor=>"top"
108
+ }
109
+ }
110
+ end
111
+ end
112
+
113
+ describe "The example from the README" do
114
+ it "should be correct, to say the least." do
115
+ url = "foo://usr:pwd@www.example.co.uk:8042/over/there.htm?name=ferret#nose"
116
+ uri = UniformResourceIdentifier.parse(url)
117
+
118
+ uri.protocol.should == "foo"
119
+
120
+ uri.authority.to_s.should == "usr:pwd@www.example.co.uk:8042"
121
+
122
+ uri.authority.user_info.to_s.should == "usr:pwd"
123
+ uri.user_info.to_s.should == "usr:pwd"
124
+
125
+ uri.authority.user_info.username.should == "usr"
126
+ uri.authority.user_info.password.should == "pwd"
127
+ uri.user_info.username.should == "usr"
128
+ uri.user_info.password.should == "pwd"
129
+ uri.username.should == "usr"
130
+ uri.password.should == "pwd"
131
+
132
+ uri.authority.host.to_s.should == "www.example.co.uk"
133
+ uri.host.to_s.should == "www.example.co.uk"
134
+
135
+ uri.authority.host.subdomain.should == "www"
136
+ uri.authority.subdomain.should == "www"
137
+ uri.subdomain.should == "www"
138
+
139
+ uri.authority.host.domain.to_s.should == "example.co.uk"
140
+ uri.authority.domain.to_s.should == "example.co.uk"
141
+ uri.domain.to_s.should == "example.co.uk"
142
+
143
+ uri.authority.host.domain.sld.should == "example"
144
+ uri.authority.domain.sld.should == "example"
145
+ uri.domain.sld.should == "example"
146
+ uri.sld.should == "example"
147
+
148
+ uri.authority.host.domain.tld.should == "co.uk"
149
+ uri.authority.domain.tld.should == "co.uk"
150
+ uri.domain.tld.should == "co.uk"
151
+ uri.tld.should == "co.uk"
152
+
153
+ uri.authority.port.should == 8042
154
+ uri.port.should == 8042
155
+
156
+ uri.relative.to_s.should == "/over/there.htm?name=ferret#nose"
157
+
158
+ uri.relative.path.to_s.should == "/over/there.htm"
159
+ uri.path.to_s.should == "/over/there.htm"
160
+
161
+ uri.relative.path.directory.to_s.should == "/over/"
162
+ uri.relative.directory.to_s.should == "/over/"
163
+ uri.directory.to_s.should == "/over/"
164
+
165
+ uri.relative.path.file.to_s.should == "there.htm"
166
+ uri.relative.file.to_s.should == "there.htm"
167
+ uri.file.to_s.should == "there.htm"
168
+
169
+ uri.relative.query.to_h.should == { "name" => "ferret" }
170
+ uri.relative.query.to_s.should == "name=ferret"
171
+ uri.query.to_h.should == { "name" => "ferret" }
172
+ uri.query.to_s.should == "name=ferret"
173
+
174
+ uri.relative.anchor.should == "nose"
175
+ uri.anchor.should == "nose"
176
+ end
177
+ end
178
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uniform_resource_identifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Scott Lewis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-31 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: public_suffix_service
16
+ requirement: &70216311725500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70216311725500
25
+ - !ruby/object:Gem::Dependency
26
+ name: active_support
27
+ requirement: &70216311725020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70216311725020
36
+ - !ruby/object:Gem::Dependency
37
+ name: addressable
38
+ requirement: &70216311724560 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.2.6
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70216311724560
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: &70216311724100 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70216311724100
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70216311723640 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 2.6.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70216311723640
69
+ - !ruby/object:Gem::Dependency
70
+ name: fuubar
71
+ requirement: &70216311723180 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.0.6
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70216311723180
80
+ - !ruby/object:Gem::Dependency
81
+ name: watchr
82
+ requirement: &70216311722720 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: 0.7.0
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70216311722720
91
+ description: ! '`uniform_resource_identifier` splits URIs according to RFC 3986 using
92
+ regexp, attempts to check the public suffix using `public_suffix_service`, and serializes
93
+ the query string using `active_support` and `addressable`'
94
+ email: c00lryguy@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files:
98
+ - LICENSE
99
+ - VERSION
100
+ files:
101
+ - LICENSE
102
+ - VERSION
103
+ - lib/uniform_resource_identifier/authority.rb
104
+ - lib/uniform_resource_identifier/domain.rb
105
+ - lib/uniform_resource_identifier/host.rb
106
+ - lib/uniform_resource_identifier/parsable.rb
107
+ - lib/uniform_resource_identifier/parser.rb
108
+ - lib/uniform_resource_identifier/path.rb
109
+ - lib/uniform_resource_identifier/query.rb
110
+ - lib/uniform_resource_identifier/relative.rb
111
+ - lib/uniform_resource_identifier/rspec_matcher.rb
112
+ - lib/uniform_resource_identifier/user_info.rb
113
+ - lib/uniform_resource_identifier.rb
114
+ - spec/spec_helper.rb
115
+ - spec/uniform_resource_identifier/parser_spec.rb
116
+ - spec/uniform_resource_identifier_spec.rb
117
+ homepage: http://github.com/c00lryguy/uniform_resource_identifier
118
+ licenses: []
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 1.8.10
138
+ signing_key:
139
+ specification_version: 3
140
+ summary: A library to split URIs according to RFC 3986 as closely as possible.
141
+ test_files:
142
+ - spec/spec_helper.rb
143
+ - spec/uniform_resource_identifier/parser_spec.rb
144
+ - spec/uniform_resource_identifier_spec.rb