Class: Furi::Uri

Inherits:
Object
  • Object
show all
Defined in:
lib/furi/uri.rb

Instance Method Summary collapse

Constructor Details

#initialize(argument) ⇒ Uri

Returns a new instance of Uri.



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/furi/uri.rb', line 20

def initialize(argument)
  @query_tokens = []
  case argument
  when String
    parse_uri_string(argument)
  when Hash
    replace(argument)
  when ::URI::Generic
    parse_uri_string(argument.to_s)
  else
    raise ParseError, "wrong Uri argument"
  end
end

Instance Method Details

#==(other) ⇒ Object



467
468
469
# File 'lib/furi/uri.rb', line 467

def ==(other)
  to_s == other.to_s
end

#[](part) ⇒ Object



480
481
482
# File 'lib/furi/uri.rb', line 480

def [](part)
  send(part)
end

#[]=(part, value) ⇒ Object



484
485
486
# File 'lib/furi/uri.rb', line 484

def []=(part, value)
  send(:"#{part}=", value)
end

#abstract_protocol?Boolean

Returns:

  • (Boolean)


438
439
440
# File 'lib/furi/uri.rb', line 438

def abstract_protocol?
  protocol == ""
end

#anchor=(string) ⇒ Object



475
476
477
478
# File 'lib/furi/uri.rb', line 475

def anchor=(string)
  string = string.to_s
  @anchor = string.empty? ? nil : string
end

#authorityObject



169
170
171
172
# File 'lib/furi/uri.rb', line 169

def authority
  return hostinfo unless userinfo
  [userinfo, hostinfo].join("@")
end

#authority=(string) ⇒ Object



174
175
176
177
178
179
180
181
182
# File 'lib/furi/uri.rb', line 174

def authority=(string)
  if string.include?("@")
    userinfo, string = string.split("@", 2)
    self.userinfo = userinfo
  else
    self.userinfo = nil
  end
  self.hostinfo = string
end

#custom_port?Boolean

Returns:

  • (Boolean)


507
508
509
# File 'lib/furi/uri.rb', line 507

def custom_port?
  port && port != default_port
end

#default_portObject



403
404
405
# File 'lib/furi/uri.rb', line 403

def default_port
  Furi::PROTOCOLS.fetch(protocol, {})[:port]
end

#default_web_port?Boolean

Returns:

  • (Boolean)


428
429
430
431
432
# File 'lib/furi/uri.rb', line 428

def default_web_port?
  Furi::WEB_PROTOCOL.any? do |web_protocol|
    Furi::PROTOCOLS[web_protocol][:port] == port!
  end
end

#defaults(parts) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/furi/uri.rb', line 62

def defaults(parts)
  parts.each do |part, value|
    case part.to_sym
    when :query, :query_tokens
      Furi.parse_query(value).each do |key, default_value|
        unless query.key?(key)
          query[key] = default_value
        end
      end
    else
      unless self[part]
        self[part] = value
      end
    end
  end
  self
end

#directoryObject



318
319
320
# File 'lib/furi/uri.rb', line 318

def directory
  path_tokens[0..-2].join("/")
end

#directory=(string) ⇒ Object



322
323
324
325
326
327
328
# File 'lib/furi/uri.rb', line 322

def directory=(string)
  string ||= "/"
  if file && string !~ %r{/\z}
    string += '/'
  end
  self.path = string + file.to_s
end

#domainObject



132
133
134
# File 'lib/furi/uri.rb', line 132

def domain
  join_domain(parsed_host[1..2].flatten)
end

#domain=(new_domain) ⇒ Object



136
137
138
# File 'lib/furi/uri.rb', line 136

def domain=(new_domain)
  self.host= [subdomain, new_domain]
end

#domainnameObject



124
125
126
# File 'lib/furi/uri.rb', line 124

def domainname
  parsed_host[1]
end

#domainname=(new_domainname) ⇒ Object



128
129
130
# File 'lib/furi/uri.rb', line 128

def domainname=(new_domainname)
  self.domain = join_domain([subdomain, new_domainname, domainzone])
end

#domainzoneObject



116
117
118
# File 'lib/furi/uri.rb', line 116

def domainzone
  parsed_host.last
end

#domainzone=(new_zone) ⇒ Object



120
121
122
# File 'lib/furi/uri.rb', line 120

def domainzone=(new_zone)
  self.host = [subdomain, domainname, new_zone]
end

#emailObject



503
504
505
# File 'lib/furi/uri.rb', line 503

def email
  authority
end

#email=(email) ⇒ Object



498
499
500
501
# File 'lib/furi/uri.rb', line 498

def email=(email)
  self.protocol ||= "mailto"
  self.authority = email
end

#extensionObject



341
342
343
344
345
# File 'lib/furi/uri.rb', line 341

def extension
  return nil unless file
  tokens = file_tokens[1..-1]
  tokens.any? ? tokens.join(".") : nil
end

#extension=(string) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/furi/uri.rb', line 347

def extension=(string)
  tokens = file_tokens
  case tokens.size
  when 0
    raise Furi::FormattingError, "can not assign extension when there is no file"
  when 1
    tokens.push(string)
  else
    if string
      tokens = [tokens.first, string]
    else
      tokens.pop
    end
  end
  self.file = tokens.join(".")
end

#fileObject



419
420
421
422
# File 'lib/furi/uri.rb', line 419

def file
  result = path_tokens.last
  result == "" ? nil : result
end

#file!Object



424
425
426
# File 'lib/furi/uri.rb', line 424

def file!
  file || ''
end

#file=(name) ⇒ Object



364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/furi/uri.rb', line 364

def file=(name)
  unless name
    return unless path
  else
    name = name.gsub(%r{\A/}, "")
  end

  self.path = path_tokens.tap do |p|
    filename_index = [p.size-1, 0].max
    p[filename_index] = name
  end.join("/")
end

#filenameObject



330
331
332
333
# File 'lib/furi/uri.rb', line 330

def filename
  return nil unless file
  file_tokens.first
end

#filename=(value) ⇒ Object



335
336
337
338
339
# File 'lib/furi/uri.rb', line 335

def filename=(value)
  t = file_tokens
  t[0] = value
  self.file = t.join(".")
end

#home_page?Boolean

Returns:

  • (Boolean)


235
236
237
# File 'lib/furi/uri.rb', line 235

def home_page?
  path! == Furi::ROOT || path! == "/index.html"
end

#host!Object



463
464
465
# File 'lib/furi/uri.rb', line 463

def host!
  host || ""
end

#host=(host) ⇒ Object



105
106
107
108
109
110
111
112
113
114
# File 'lib/furi/uri.rb', line 105

def host=(host)
  @host = case host
          when Array
            join_domain(host)
          when "", nil
            nil
          else
            host.to_s.downcase
          end
end

#hostinfoObject



148
149
150
151
152
153
154
# File 'lib/furi/uri.rb', line 148

def hostinfo
  return host unless custom_port?
  if port && !host
    raise Furi::FormattingError, "can not build URI with port but without host"
  end
  [host, port].join(":")
end

#hostinfo=(string) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/furi/uri.rb', line 156

def hostinfo=(string)
  if string.match(%r{\A\[.+\]\z}) #ipv6 host
    self.host = string
  else
    if match = string.match(/\A(.+):(.*)\z/)
      self.host, self.port = match.captures
    else
      self.host = string
      self.port = nil
    end
  end
end

#inspectObject



471
472
473
# File 'lib/furi/uri.rb', line 471

def inspect
  "#<#{self.class} #{to_s.inspect}>"
end

#locationObject



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/furi/uri.rb', line 197

def location
  if protocol
    if !host && !mailto?
      raise Furi::FormattingError, "can not build URI with protocol but without host"
    end
    [
      protocol.empty? ? "" : "#{protocol}:", authority
    ].join(mailto? ? "" : "//")
  else
    authority
  end
end

#location=(string) ⇒ Object



210
211
212
213
214
215
216
# File 'lib/furi/uri.rb', line 210

def location=(string)
  string ||= ""
  string  = string.gsub(%r(/\Z), '')
  self.protocol = nil
  string = parse_protocol(string)
  self.authority = string
end

#mailto?Boolean

Returns:

  • (Boolean)


511
512
513
# File 'lib/furi/uri.rb', line 511

def mailto?
  protocol == "mailto"
end

#merge_query(query) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/furi/uri.rb', line 80

def merge_query(query)
  case query
  when Hash
    self.query = Furi::Utils.deep_merge(
      self.query,
      Furi::Utils.stringify_keys(query)
    )
  when String, Array
    self.query_tokens += Furi.query_tokens(query)
  when nil
  else
    raise QueryParseError, "#{query.inspect} can not be merged"
  end
end

#password=(password) ⇒ Object



293
294
295
# File 'lib/furi/uri.rb', line 293

def password=(password)
  @password = password.nil? ? nil : password.to_s
end

#path!Object



455
456
457
# File 'lib/furi/uri.rb', line 455

def path!
  path || Furi::ROOT
end

#path=(path) ⇒ Object



303
304
305
306
307
308
# File 'lib/furi/uri.rb', line 303

def path=(path)
  @path = path.to_s
  if !@path.empty? && !@path.start_with?("/")
    @path = "/" + @path
  end
end

#path_tokensObject



377
378
379
380
# File 'lib/furi/uri.rb', line 377

def path_tokens
  return [] unless path
  path.split("/", -1)
end

#port!Object



399
400
401
# File 'lib/furi/uri.rb', line 399

def port!
  port || default_port
end

#port=(port) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/furi/uri.rb', line 260

def port=(port)
  @port = case port
          when String
            if port.empty?
              nil
            else
              unless port =~ /\A\s*\d+\s*\z/
                raise ArgumentError, "port should be an Integer >= 0"
              end
              port.to_i
            end
          when Integer
            if port < 0
              raise ArgumentError, "port should be an Integer >= 0"
            end
            port
          when nil
            nil
          else
            raise ArgumentError, "can not parse port: #{port.inspect}"
          end
  @port
end

#protocol!Object



314
315
316
# File 'lib/furi/uri.rb', line 314

def protocol!
  protocol || default_protocol_for_port || 'http' # Web Rules Them All!
end

#protocol=(protocol) ⇒ Object



310
311
312
# File 'lib/furi/uri.rb', line 310

def protocol=(protocol)
  @protocol = protocol ? protocol.gsub(%r{:?/?/?\Z}, "").downcase : nil
end

#queryObject



239
240
241
242
# File 'lib/furi/uri.rb', line 239

def query
  return @query if query_level?
  @query = Furi.parse_query(query_tokens)
end

#query=(value) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/furi/uri.rb', line 245

def query=(value)
  case value
  when true
    # Assuming that current query needs to be parsed to Hash
    query
  when String, Array
    self.query_tokens = value
  when Hash
    self.query_tokens = value
  when nil
  else
    raise QueryParseError, 'Query can only be Hash or String'
  end
end

#query_stringObject



383
384
385
386
387
388
389
# File 'lib/furi/uri.rb', line 383

def query_string
  if query_level?
    Furi.serialize(query)
  else
    query_tokens.any? ? query_tokens.join("&") : nil
  end
end

#query_string!Object



391
392
393
# File 'lib/furi/uri.rb', line 391

def query_string!
  query_string || ""
end

#query_string=(string) ⇒ Object



395
396
397
# File 'lib/furi/uri.rb', line 395

def query_string=(string)
  self.query_tokens = string.to_s
end

#query_tokens=(tokens) ⇒ Object



284
285
286
287
# File 'lib/furi/uri.rb', line 284

def query_tokens=(tokens)
  @query = tokens.is_a?(Hash) ? tokens : nil
  @query_tokens = Furi.query_tokens(tokens)
end

#replace(parts) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/furi/uri.rb', line 34

def replace(parts)
  if parts
    parts.each do |part, value|
      self[part] = value
    end
  end
  self
end

#requestObject



218
219
220
221
222
223
224
# File 'lib/furi/uri.rb', line 218

def request
  return nil if !path && query_tokens.empty?
  result = []
  result << path!
  result << "?" << query_string if query_tokens.any?
  result.join
end

#request!Object



226
227
228
# File 'lib/furi/uri.rb', line 226

def request!
  request || path!
end

#request=(string) ⇒ Object



230
231
232
233
# File 'lib/furi/uri.rb', line 230

def request=(string)
  string = parse_anchor_and_query(string)
  self.path = string
end

#resourceObject



442
443
444
445
# File 'lib/furi/uri.rb', line 442

def resource
  return nil unless request
  request + encoded_anchor
end

#resource!Object



459
460
461
# File 'lib/furi/uri.rb', line 459

def resource!
  resource || request!
end

#resource=(value) ⇒ Object



447
448
449
450
451
452
453
# File 'lib/furi/uri.rb', line 447

def resource=(value)
  self.anchor = nil
  self.query_tokens = []
  self.path = nil
  value = parse_anchor_and_query(value)
  self.path = value
end

#rfc3986?Boolean

Returns:

  • (Boolean)


492
493
494
495
496
# File 'lib/furi/uri.rb', line 492

def rfc3986?
  uri = to_s
  !!(uri.match(URI::RFC3986_Parser::RFC3986_URI) ||
     uri.match(URI::RFC3986_Parser::RFC3986_relative_ref))
end

#rfc?Boolean

Returns:

  • (Boolean)


488
489
490
# File 'lib/furi/uri.rb', line 488

def rfc?
  rfc3986?
end

#sslObject



411
412
413
# File 'lib/furi/uri.rb', line 411

def ssl
  ssl?
end

#ssl=(ssl) ⇒ Object



415
416
417
# File 'lib/furi/uri.rb', line 415

def ssl=(ssl)
  self.protocol = find_protocol_for_ssl(ssl)
end

#ssl?Boolean

Returns:

  • (Boolean)


407
408
409
# File 'lib/furi/uri.rb', line 407

def ssl?
  !!(Furi::PROTOCOLS.fetch(protocol, {})[:ssl])
end

#subdomainObject



140
141
142
# File 'lib/furi/uri.rb', line 140

def subdomain
  parsed_host.first
end

#subdomain=(new_subdomain) ⇒ Object



144
145
146
# File 'lib/furi/uri.rb', line 144

def subdomain=(new_subdomain)
  self.host = [new_subdomain, domain]
end

#to_sObject



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/furi/uri.rb', line 184

def to_s
  result = []
  result << location
  result << (host || mailto? ? path : path!)
  if query_tokens.any?
    result << "?" << query_string
  end
  if anchor
    result << encoded_anchor
  end
  result.join
end

#update(parts) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/furi/uri.rb', line 43

def update(parts)
  return self unless parts
  parts.each do |part, value|
    case part.to_sym
    when :query, :query_tokens, :query_string
      merge_query(value)
    when :path
      if value && self[part]
        self[part] = Pathname.new(self[part]).join(value).to_s
      else
        self[part] = value
      end
    else
      self[part] = value
    end
  end
  self
end

#userinfoObject



95
96
97
98
99
100
101
102
103
# File 'lib/furi/uri.rb', line 95

def userinfo
  if username
    [username, password].compact.join(":")
  elsif password
    raise Furi::FormattingError, "can not build URI with password but without username"
  else
    nil
  end
end

#userinfo=(userinfo) ⇒ Object



297
298
299
300
301
# File 'lib/furi/uri.rb', line 297

def userinfo=(userinfo)
  username, password = (userinfo || "").split(":", 2)
  self.username = username
  self.password = password
end

#username=(username) ⇒ Object



289
290
291
# File 'lib/furi/uri.rb', line 289

def username=(username)
  @username = username.nil? ? nil : username.to_s
end

#web_protocol?Boolean

Returns:

  • (Boolean)


434
435
436
# File 'lib/furi/uri.rb', line 434

def web_protocol?
  Furi::WEB_PROTOCOL.include?(protocol)
end