Class: Fuzzyurl
- Inherits:
-
Object
- Object
- Fuzzyurl
- Defined in:
- lib/fuzzyurl.rb,
lib/fuzzyurl/fields.rb,
lib/fuzzyurl/version.rb
Overview
Fuzzyurl provides two related functions: non-strict parsing of URLs or URL-like strings into their component pieces (protocol, username, password, hostname, port, path, query, and fragment), and fuzzy matching of URLs and URL patterns.
Specifically, URLs that look like this:
[protocol ://] [username [: password] @] [hostname] [: port] [/ path] [? query] [# fragment]
Fuzzyurls can be constructed using some or all of the above fields, optionally replacing some or all of those fields with a ‘*` wildcard if you wish to use the Fuzzyurl as a URL mask.
## Parsing URLs
irb> Fuzzyurl.from_string("https://api.example.com/users/123?full=true")
#=> #<Fuzzyurl:0x007ff55b914f58 @protocol="https", @username=nil, @password=nil, @hostname="api.example.com", @port=nil, @path="/users/123", @query="full=true", @fragment=nil>
## Constructing URLs
irb> f = Fuzzyurl.new(hostname: "example.com", protocol: "http", port: "8080")
irb> f.to_s
#=> "http://example.com:8080"
## Matching URLs
Fuzzyurl supports wildcard matching:
-
‘*` matches anything, including `null`.
-
‘foo*` matches `foo`, `foobar`, `foo/bar`, etc.
-
‘*bar` matches `bar`, `foobar`, `foo/bar`, etc.
Path and hostname matching allows the use of a greedier wildcard ‘**` in addition to the naive wildcard `*`:
-
‘*.example.com` matches `filsrv-01.corp.example.com` but not `example.com`.
-
‘**.example.com` matches `filsrv-01.corp.example.com` and `example.com`.
-
‘/some/path/*` matches `/some/path/foo/bar` and `/some/path/`
but not `/some/path`
-
‘/some/path/**` matches `/some/path/foo/bar` and `/some/path/`
and `/some/path`
The ‘Fuzzyurl.mask` function aids in the creation of URL masks.
irb> Fuzzyurl.mask
#=> #<Fuzzyurl:0x007ff55b039578 @protocol="*", @username="*", @password="*", @hostname="*", @port="*", @path="*", @query="*", @fragment="*">
irb> Fuzzyurl.matches?(Fuzzyurl.mask, "http://example.com:8080/foo/bar")
#=> true
irb> mask = Fuzzyurl.mask(path: "/a/b/**")
irb> Fuzzyurl.matches?(mask, "https://example.com/a/b/")
#=> true
irb> Fuzzyurl.matches?(mask, "git+ssh://[email protected]/a/b/")
#=> true
irb> Fuzzyurl.matches?(mask, "https://example.com/a/bar")
#=> false
‘Fuzzyurl.bestMatch`, given a list of URL masks and a URL, will return the given mask which most closely matches the URL:
irb> masks = ["/foo/*", "/foo/bar", Fuzzyurl.mask]
irb> Fuzzyurl.best_match(masks, "http://example.com/foo/bar")
#=> "/foo/bar"
If you’d prefer the array index instead of the matching mask itself, use ‘Fuzzyurl.best_match_index` instead:
irb> Fuzzyurl.best_match_index(masks, "http://example.com/foo/bar")
#=> 1
Defined Under Namespace
Classes: Match, Protocols, Strings
Constant Summary collapse
- FIELDS =
[ :protocol, :username, :password, :hostname, :port, :path, :query, :fragment ]
- VERSION =
"0.9.0"
- VERSION_DATE =
"2016-06-28"
Class Method Summary collapse
-
.best_match(masks, url) ⇒ Integer|nil
Given an array of URL masks, returns the one which most closely matches ‘url`, or nil if none match.
-
.best_match_index(masks, url) ⇒ Integer|nil
Given an array of URL masks, returns the array index of the one which most closely matches ‘url`, or nil if none match.
-
.from_string(str, opts = {}) ⇒ Fuzzyurl
Returns a Fuzzyurl representation of the given URL string.
-
.fuzzy_match(mask, value) ⇒ Object
If ‘mask` (which may contain * wildcards) matches `url` (which may not), returns 1 if `mask` and `url` match perfectly, 0 if `mask` and `url` are a wildcard match, or null otherwise.
-
.mask(params = {}) ⇒ Fuzzyurl
Returns a Fuzzyurl suitable for use as a URL mask, with the given values optionally set from ‘params` (Hash or String).
-
.match(mask, url) ⇒ Integer|nil
Returns an integer representing how closely ‘mask` matches `url` (0 means wildcard match, higher is closer), or nil for no match.
-
.match_scores(mask, url) ⇒ Object
Returns a Hash of match scores for each field of ‘mask` and `url`, indicating the closeness of the match.
-
.matches?(mask, url) ⇒ Boolean
Returns true if ‘mask` matches `url`, false otherwise.
-
.to_string(fuzzyurl) ⇒ String
Returns a string representation of ‘fuzzyurl`.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#initialize(params = {}) ⇒ Fuzzyurl
constructor
Creates a new Fuzzyurl object from the given params or URL string.
-
#to_hash ⇒ Hash
Returns a hash representation of this Fuzzyurl, with one key/value pair for each of ‘Fuzzyurl::FIELDS`.
-
#to_s ⇒ String
Returns a string representation of this Fuzzyurl.
-
#with(params = {}) ⇒ Fuzzyurl
Returns a new copy of this Fuzzyurl, with the given params changed.
Constructor Details
#initialize(params = {}) ⇒ Fuzzyurl
Creates a new Fuzzyurl object from the given params or URL string. Keys of ‘params` should be symbols.
90 91 92 93 94 95 |
# File 'lib/fuzzyurl.rb', line 90 def initialize(params={}) p = params.kind_of?(String) ? Fuzzyurl.from_string(params).to_hash : params (FIELDS & p.keys).each do |f| self.send("#{f}=", p[f]) end end |
Class Method Details
.best_match(masks, url) ⇒ Integer|nil
Given an array of URL masks, returns the one which most closely matches ‘url`, or nil if none match.
‘url` and each element of `masks` may be Fuzzyurl or String format.
240 241 242 243 |
# File 'lib/fuzzyurl.rb', line 240 def best_match(masks, url) index = best_match_index(masks, url) index && masks[index] end |
.best_match_index(masks, url) ⇒ Integer|nil
Given an array of URL masks, returns the array index of the one which most closely matches ‘url`, or nil if none match.
‘url` and each element of `masks` may be Fuzzyurl or String format.
226 227 228 229 230 |
# File 'lib/fuzzyurl.rb', line 226 def best_match_index(masks, url) ms = masks.map {|m| m.kind_of?(Fuzzyurl) ? m : Fuzzyurl.mask(m)} u = url.kind_of?(Fuzzyurl) ? url : Fuzzyurl.from_string(url) Fuzzyurl::Match.best_match_index(ms, u) end |
.from_string(str, opts = {}) ⇒ Fuzzyurl
Returns a Fuzzyurl representation of the given URL string. Any fields not present in ‘str` will be assigned the value of `opts` (defaults to nil).
168 169 170 |
# File 'lib/fuzzyurl.rb', line 168 def from_string(str, opts={}) Fuzzyurl::Strings.from_string(str, opts) end |
.fuzzy_match(mask, value) ⇒ Object
If ‘mask` (which may contain * wildcards) matches `url` (which may not), returns 1 if `mask` and `url` match perfectly, 0 if `mask` and `url` are a wildcard match, or null otherwise.
Wildcard language:
* matches anything
foo/* matches "foo/" and "foo/bar/baz" but not "foo"
foo/** matches "foo/" and "foo/bar/baz" and "foo"
*.example.com matches "api.v1.example.com" but not "example.com"
**.example.com matches "api.v1.example.com" and "example.com"
Any other form is treated as a literal match.
262 263 264 |
# File 'lib/fuzzyurl.rb', line 262 def fuzzy_match(mask, value) Fuzzyurl::Match.fuzzy_match(mask, value) end |
.mask(params = {}) ⇒ Fuzzyurl
Returns a Fuzzyurl suitable for use as a URL mask, with the given values optionally set from ‘params` (Hash or String).
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/fuzzyurl.rb', line 142 def mask(params={}) params ||= {} return from_string(params, default: "*") if params.kind_of?(String) m = Fuzzyurl.new FIELDS.each do |f| m.send("#{f}=", params.has_key?(f) ? params[f].to_s : "*") end m end |
.match(mask, url) ⇒ Integer|nil
Returns an integer representing how closely ‘mask` matches `url` (0 means wildcard match, higher is closer), or nil for no match.
‘mask` and `url` may each be Fuzzyurl or String format.
180 181 182 183 184 |
# File 'lib/fuzzyurl.rb', line 180 def match(mask, url) m = mask.kind_of?(Fuzzyurl) ? mask : Fuzzyurl.mask(mask) u = url.kind_of?(Fuzzyurl) ? url : Fuzzyurl.from_string(url) Fuzzyurl::Match.match(m, u) end |
.match_scores(mask, url) ⇒ Object
Returns a Hash of match scores for each field of ‘mask` and `url`, indicating the closeness of the match. Values are from `fuzzy_match`: 0 indicates wildcard match, 1 indicates perfect match, and nil indicates no match.
‘mask` and `url` may each be Fuzzyurl or String format.
210 211 212 213 214 215 216 |
# File 'lib/fuzzyurl.rb', line 210 def match_scores(mask, url) m = mask.kind_of?(Fuzzyurl) ? m : Fuzzyurl.mask(m) u = url.kind_of?(Fuzzyurl) ? u : Fuzzyurl.from_string(u) m = mask.kind_of?(Fuzzyurl) ? mask : Fuzzyurl.mask(mask) u = url.kind_of?(Fuzzyurl) ? url : Fuzzyurl.from_string(url) Fuzzyurl::Match.match_scores(m, u) end |
.matches?(mask, url) ⇒ Boolean
Returns true if ‘mask` matches `url`, false otherwise.
‘mask` and `url` may each be Fuzzyurl or String format.
193 194 195 196 197 198 199 |
# File 'lib/fuzzyurl.rb', line 193 def matches?(mask, url) m = mask.kind_of?(Fuzzyurl) ? m : Fuzzyurl.mask(m) u = url.kind_of?(Fuzzyurl) ? u : Fuzzyurl.from_string(u) m = mask.kind_of?(Fuzzyurl) ? mask : Fuzzyurl.mask(mask) u = url.kind_of?(Fuzzyurl) ? url : Fuzzyurl.from_string(url) Fuzzyurl::Match.matches?(m, u) end |
Instance Method Details
#==(other) ⇒ Object
130 131 132 |
# File 'lib/fuzzyurl.rb', line 130 def ==(other) self.to_hash == other.to_hash end |
#to_hash ⇒ Hash
Returns a hash representation of this Fuzzyurl, with one key/value pair for each of ‘Fuzzyurl::FIELDS`.
101 102 103 104 105 106 107 108 |
# File 'lib/fuzzyurl.rb', line 101 def to_hash FIELDS.reduce({}) do |hash, f| val = self.send(f) val = val.to_s if val hash[f] = val hash end end |