uniform_resource_identifier 0.1.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.
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