Module: Furi

Defined in:
lib/furi.rb,
lib/furi/uri.rb,
lib/furi/utils.rb,
lib/furi/version.rb,
lib/furi/query_token.rb

Defined Under Namespace

Classes: Error, FormattingError, ParseError, QueryParseError, QueryToken, Uri, Utils

Constant Summary collapse

ESSENTIAL_PARTS =
[
  :anchor, :protocol, :query_tokens,
  :path, :host, :port, :username, :password
]
COMBINED_PARTS =
[
  :hostinfo, :userinfo, :authority, :ssl, :domain, :domainname,
  :domainzone, :request, :location, :query,
  :directory, :extension, :file
]
PARTS =
ESSENTIAL_PARTS + COMBINED_PARTS
ALIASES =
{
  protocol: [:schema, :scheme],
  anchor: [:fragment],
  host: [:hostname],
  username: [:user],
  request: [:request_uri]
}
DELEGATES =
[:port!, :host!, :path!, :home_page?]
PROTOCOLS =
{
  "http" => {port: 80, ssl: false},
  "https" => {port: 443, ssl: true},
  "ftp" => {port: 21},
  "tftp" => {port: 69},
  "sftp" => {port: 22},
  "ssh" => {port: 22, ssl: true},
  "svn" => {port: 3690},
  "svn+ssh" => {port: 22, ssl: true},
  "telnet" => {port: 23},
  "nntp" => {port: 119},
  "gopher" => {port: 70},
  "wais" => {port: 210},
  "ldap" => {port: 389},
  "prospero" => {port: 1525},
  "file" => {port: nil},
  "postgres" => {port: 5432},
  "mysql" => {port: 3306},
  "mailto" => {port: nil}
}
SSL_MAPPING =
{
  'http' => 'https',
  'ftp' => 'sftp',
  'svn' => 'svn+ssh',
}
WEB_PROTOCOL =
['http', 'https']
ROOT =
'/'
VERSION =
"0.2.3"

Class Method Summary collapse

Class Method Details

.build(argument) ⇒ Object

Builds an URL from given parts

Furi.build(path: "/dashboard", host: 'example.com', protocol: "https")
  # => "https://example.com/dashboard"


73
74
75
# File 'lib/furi.rb', line 73

def self.build(argument)
  Uri.new(argument).to_s
end

.defaults(string, parts) ⇒ Object

Puts the default values for given URL that are not defined

Furi.defaults("gusiev.com/hello.html", protocol: 'http', path: '/index.html')
  # => "http://gusiev.com/hello.html"


100
101
102
# File 'lib/furi.rb', line 100

def self.defaults(string, parts)
  parse(string).defaults(parts).to_s
end

.join(*uris) ⇒ Object



172
173
174
175
176
177
178
# File 'lib/furi.rb', line 172

def self.join(*uris)
  uris.map do |uri|
    Furi.parse(uri)
  end.reduce do |memo, uri|
    memo.send(:join, uri)
  end
end

.parse(argument, parts = nil) ⇒ Object

Parses a given string and return an URL object Optionally accepts parts to update the parsed URL object



65
66
67
# File 'lib/furi.rb', line 65

def self.parse(argument, parts = nil)
  Uri.new(argument).update(parts)
end

.parse_query(query) ⇒ Object

Parses a query into nested paramters hash using a rack convension with square brackets.

Furi.parse_query("a[]=1&a[]=2")       # => {a: [1,2]}
Furi.parse_query("p[email]=a&a[two]=2") # => {a: {one: 1, two: 2}}
Furi.parse_query("p[one]=1&a[two]=2") # => {a: {one: 1, two: 2}}
Furi.serialize({p: {name: 'Bogdan Gusiev', email: '[email protected]', data: {one: 1, two: 2}}})
  # => "p%5Bname%5D=Bogdan&p%5Bemail%5D=bogdan%40example.com&p%5Bdata%5D%5Bone%5D=1&p%5Bdata%5D%5Btwo%5D=2"


124
125
126
127
128
129
130
131
132
133
# File 'lib/furi.rb', line 124

def self.parse_query(query)
  return Furi::Utils.stringify_keys(query) if query.is_a?(Hash)

  params = {}
  query_tokens(query).each do |token|
    parse_query_token(params, token.name, token.value)
  end

  return params
end

.query_tokens(query) ⇒ Object

Parses query key/value pairs from query string and returns them raw without organising them into hashes and without normalising them.

Furi.query_tokens("a=1&b=2").map {|k,v| "#{k} -> #{v}"}  # => ['a -> 1', 'b -> 2']
Furi.query_tokens("a=1&a=1&a=2").map {|k,v| "#{k} -> #{v}"}  # => ['a -> 1', 'a -> 1', 'a -> 2']
Furi.query_tokens("name=Bogdan&email=bogdan%40example.com") # => [name=Bogdan, [email protected]]
Furi.query_tokens("a[one]=1&a[two]=2") # => [a[one]=1, a[two]=2]


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/furi.rb', line 142

def self.query_tokens(query)
  case query
  when Enumerable, Enumerator
    query.map do |token|
      QueryToken.parse(token)
    end
  when nil, ''
    []
  when String
    query.gsub(/\A\?/, '').split(/[&;] */n, -1).map do |p|
      QueryToken.parse(p)
    end
  else
    raise QueryParseError, "can not parse #{query.inspect} query tokens"
  end
end

.replace(string, parts) ⇒ Object

Replaces a given URL string with given parts. Same as update but works different for URL query parameter: replaces newly specified parameters instead of merging to existing ones

Furi.update("/hello.html?a=1", host: 'gusiev.com', query: {b: 2})
  # => "gusiev.com/hello.html?a=1&b=2"


111
112
113
# File 'lib/furi.rb', line 111

def self.replace(string, parts)
  parse(string).replace(parts).to_s
end

.serialize(query, namespace = nil) ⇒ Object

Serializes query parameters into query string. Optionaly accepts a basic name space.

Furi.serialize({a: 1, b: 2}) # => "a=1&b=2"
Furi.serialize({a: [1,2]}) # => "a[]=1&a[]=2"
Furi.serialize({a: {b: 1, c:2}}) # => "a[b]=1&a[c]=2"
Furi.serialize({name: 'Bogdan', email: '[email protected]'}, "person")
  # => "person[name]=Bogdan&person[email]=bogdan%40example.com"


168
169
170
# File 'lib/furi.rb', line 168

def self.serialize(query, namespace = nil)
  serialize_tokens(query, namespace).join("&")
end

.update(string, parts) ⇒ Object Also known as: merge

Replaces a given URL string with given parts

Furi.update("http://gusiev.com", protocol: 'https', subdomain: 'www')
  # => "https://www.gusiev.com"


89
90
91
# File 'lib/furi.rb', line 89

def self.update(string, parts)
  parse(string).update(parts).to_s
end