pax_global_header00006660000000000000000000000064127344500730014517gustar00rootroot0000000000000052 comment=9c4afe8fceaef35f0fdfad619a913478cc0e026e fuzzyurl.rb-0.9.0/000077500000000000000000000000001273445007300140415ustar00rootroot00000000000000fuzzyurl.rb-0.9.0/.gitignore000066400000000000000000000000431273445007300160260ustar00rootroot00000000000000*.gem Gemfile.lock .coveralls.yml fuzzyurl.rb-0.9.0/.travis.yml000066400000000000000000000001071273445007300161500ustar00rootroot00000000000000language: ruby rvm: - 2.3.0 - 2.2.4 - 2.1.8 - 2.0.0 - 1.9.3 fuzzyurl.rb-0.9.0/.yardopts000066400000000000000000000000571273445007300157110ustar00rootroot00000000000000--markup-provider=redcarpet --markup=markdown fuzzyurl.rb-0.9.0/Gemfile000066400000000000000000000000471273445007300153350ustar00rootroot00000000000000source 'https://rubygems.org' gemspec fuzzyurl.rb-0.9.0/LICENSE.txt000066400000000000000000000020421273445007300156620ustar00rootroot00000000000000Copyright (c) 2015 Pete Gamache. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. fuzzyurl.rb-0.9.0/README.md000066400000000000000000000065331273445007300153270ustar00rootroot00000000000000# Fuzzyurl [![Build Status](https://travis-ci.org/gamache/fuzzyurl.rb.svg?branch=master)](https://travis-ci.org/gamache/fuzzyurl.rb) [![Coverage Status](https://coveralls.io/repos/gamache/fuzzyurl.rb/badge.svg?branch=master&service=github)](https://coveralls.io/github/gamache/fuzzyurl.rb?branch=master) Non-strict parsing, composition, and wildcard matching of URLs in Ruby. ## Introduction 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. ## Installation Put the following in your `Gemfile`: gem 'fuzzyurl', '~> 0.9.0' ## Parsing URLs irb> Fuzzyurl.from_string("https://api.example.com/users/123?full=true") #=> # ## 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 #=> # 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://jen@example.com/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 ## Authorship and License Fuzzyurl is copyright 2014-2015, Pete Gamache. Fuzzyurl is released under the MIT License. See LICENSE.txt. If you got this far, you should probably follow me on Twitter. [@gamache](https://twitter.com/gamache) fuzzyurl.rb-0.9.0/Rakefile000066400000000000000000000007641273445007300155150ustar00rootroot00000000000000require 'rake/testtask' task :default => [:test] Rake::TestTask.new do |t| t.libs << 'test' t.libs << 'test/lib' t.test_files = FileList['test/**/*_test.rb'] #t.warning = true t.verbose = true end task :release do system(<<-EOT) git add lib/fuzzyurl/version.rb git commit -m 'release v#{Fuzzyurl::VERSION}' git push origin git tag v#{Fuzzyurl::VERSION} git push --tags origin gem build fuzzyurl.gemspec gem push fuzzyurl-#{Fuzzyurl::VERSION}.gem EOT end fuzzyurl.rb-0.9.0/fuzzyurl.gemspec000066400000000000000000000013521273445007300173210ustar00rootroot00000000000000require './lib/fuzzyurl/version' Gem::Specification.new do |s| s.name = 'fuzzyurl' s.version = Fuzzyurl::VERSION s.date = Fuzzyurl::VERSION_DATE s.summary = 'A library for non-strict parsing, construction, and wildcard-matching of URLs.' s.homepage = 'https://github.com/gamache/fuzzyurl.rb' s.authors = ['Pete Gamache'] s.email = 'pete@gamache.org' s.files = Dir['lib/**/*'] s.license = 'MIT' s.has_rdoc = true s.require_path = 'lib' s.required_ruby_version = '>= 1.9.3' s.add_development_dependency 'rake', '~> 10.0' s.add_development_dependency 'minitest', '~> 4.7.0' s.add_development_dependency 'mocha' s.add_development_dependency 'pry' s.add_development_dependency 'coveralls' end fuzzyurl.rb-0.9.0/lib/000077500000000000000000000000001273445007300146075ustar00rootroot00000000000000fuzzyurl.rb-0.9.0/lib/fuzzyurl.rb000066400000000000000000000224611273445007300170530ustar00rootroot00000000000000require 'fuzzyurl/version' require 'fuzzyurl/fields' require 'fuzzyurl/protocols' require 'fuzzyurl/match' require 'fuzzyurl/strings' # 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") # #=> # # # # ## 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 # #=> # # # 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://jen@example.com/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 # class Fuzzyurl FIELDS.each {|f| attr_accessor f} # Creates a new Fuzzyurl object from the given params or URL string. # Keys of `params` should be symbols. # # @param params [Hash|String|nil] URL string or parameter hash. # @return [Fuzzyurl] New Fuzzyurl object. 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 # Returns a hash representation of this Fuzzyurl, with one key/value pair # for each of `Fuzzyurl::FIELDS`. # # @return [Hash] Hash representation of this Fuzzyurl. def to_hash FIELDS.reduce({}) do |hash, f| val = self.send(f) val = val.to_s if val hash[f] = val hash end end # Returns a new copy of this Fuzzyurl, with the given params changed. # # @param params [Hash|nil] New parameter values. # @return [Fuzzyurl] Copy of `self` with the given parameters changed. def with(params={}) fu = Fuzzyurl.new(self.to_hash) (FIELDS & params.keys).each do |f| fu.send("#{f}=", params[f].to_s) end fu end # Returns a string representation of this Fuzzyurl. # # @return [String] String representation of this Fuzzyurl. def to_s Fuzzyurl::Strings.to_string(self) end # @private def ==(other) self.to_hash == other.to_hash end class << self # Returns a Fuzzyurl suitable for use as a URL mask, with the given # values optionally set from `params` (Hash or String). # # @param params [Hash|String|nil] Parameters to set. # @return [Fuzzyurl] Fuzzyurl mask object. 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 # Returns a string representation of `fuzzyurl`. # # @param fuzzyurl [Fuzzyurl] Fuzzyurl to convert to string. # @return [String] String representation of `fuzzyurl`. def to_string(fuzzyurl) Fuzzyurl::Strings.to_string(fuzzyurl) end # Returns a Fuzzyurl representation of the given URL string. # Any fields not present in `str` will be assigned the value # of `opts[:default]` (defaults to nil). # # @param str [String] String URL to convert to Fuzzyurl. # @param opts [Hash|nil] Options. # @return [Fuzzyurl] Fuzzyurl representation of `str`. def from_string(str, opts={}) Fuzzyurl::Strings.from_string(str, opts) end # 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. # # @param mask [Fuzzyurl|String] URL mask. # @param url [Fuzzyurl|String] URL. # @return [Integer|nil] 0 for wildcard match, 1 for perfect match, or nil. 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 # Returns true if `mask` matches `url`, false otherwise. # # `mask` and `url` may each be Fuzzyurl or String format. # # @param mask [Fuzzyurl|String] URL mask. # @param url [Fuzzyurl|String] URL. # @return [Boolean] Whether `mask` matches `url`. 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 # 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. # # @param mask [Fuzzyurl|String] URL mask. # @param url [Fuzzyurl|String] URL. 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 # 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. # # @param masks [Array] Array of URL masks. # @param url [Fuzzyurl|String] URL. # @return [Integer|nil] Array index of best-matching mask, or nil for no match. 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 # 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. # # @param masks [Array] Array of URL masks. # @param url [Fuzzyurl|String] URL. # @return [Integer|nil] Best-matching given mask, or nil for no match. def best_match(masks, url) index = best_match_index(masks, url) index && masks[index] end # 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. # # @param mask [String] String mask to match with (may contain wildcards). # @param value [String] String value to match. # @returns [Integer|nil] 0 for wildcard match, 1 for perfect match, else nil. def fuzzy_match(mask, value) Fuzzyurl::Match.fuzzy_match(mask, value) end end # class << self end fuzzyurl.rb-0.9.0/lib/fuzzyurl/000077500000000000000000000000001273445007300165215ustar00rootroot00000000000000fuzzyurl.rb-0.9.0/lib/fuzzyurl/fields.rb000066400000000000000000000002211273445007300203070ustar00rootroot00000000000000class Fuzzyurl FIELDS = [ :protocol, :username, :password, :hostname, :port, :path, :query, :fragment ] end fuzzyurl.rb-0.9.0/lib/fuzzyurl/match.rb000066400000000000000000000104631273445007300201460ustar00rootroot00000000000000require 'fuzzyurl/protocols' class Fuzzyurl::Match class << self # If `mask` (which may contain * wildcards) matches `url` (which may not), # returns an integer representing how closely they match (higher is closer). # If `mask` does not match `url`, returns null. # # @param mask [Fuzzyurl] Fuzzyurl mask to match with # @param url [Fuzzyurl] Fuzzyurl URL to match # @returns [Fuzzyurl] Fuzzyurl-like object containing match scores def match(mask, url) scores = match_scores(mask, url) return nil if scores.values.include?(nil) scores.values.reduce(:+) end # If `mask` (which may contain * wildcards) matches `url` (which may not), # returns true; otherwise returns false. # # @param mask [Fuzzyurl] Fuzzyurl mask to match with # @param url [Fuzzyurl] Fuzzyurl URL to match # @returns [Fuzzyurl] Fuzzyurl-like object containing match scores def matches?(mask, url) match(mask, url) != nil end # Returns a Fuzzyurl-like object containing values representing how well # different parts of `mask` and `url` match. Values are integers for # matches or null for no match; higher integers indicate a better match. # # @param mask [Fuzzyurl] Fuzzyurl mask to match with # @param url [Fuzzyurl] Fuzzyurl URL to match # @returns [Hash] Hash containing match scores for each field def match_scores(mask, url) url_protocol = url.protocol || Fuzzyurl::Protocols.get_protocol(url.port) url_port = url.port || Fuzzyurl::Protocols.get_port(url.protocol) { protocol: fuzzy_match(mask.protocol, url_protocol), username: fuzzy_match(mask.username, url.username), password: fuzzy_match(mask.password, url.password), hostname: fuzzy_match(mask.hostname, url.hostname), port: fuzzy_match(mask.port, url_port), path: fuzzy_match(mask.path, url.path), query: fuzzy_match(mask.query, url.query), fragment: fuzzy_match(mask.fragment, url.fragment) } end # From a list of Fuzzyurl `masks`, returns the index of the one which best # matches `url`. Returns null if none of `masks` match. # # @param [Array] Array of Fuzzyurl URL mask objects to match with. # @param [Fuzzyurl] Fuzzyurl URL to match. # @returns [Integer|nil] Index of best matching mask, or null if none match. def best_match_index(masks, url) best_index = nil best_score = -1 masks.each_with_index do |mask, i| score = match(mask, url) if score && score > best_score best_score = score best_index = i end end best_index end # 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. # # @param mask [String] String mask to match with (may contain wildcards). # @param value [String] String value to match. # @returns [Integer|nil] 0 for wildcard match, 1 for perfect match, else nil. def fuzzy_match(mask, value) return 0 if mask == "*" return 1 if mask == value return nil if !mask || !value if mask.index("**.") == 0 mask_value = mask[3..-1] return 0 if value.end_with?(".#{mask_value}") return 0 if mask_value == value return nil end if mask.index("*") == 0 return 0 if value.end_with?(mask[1..-1]) return nil end rev_mask = mask.reverse rev_value = value.reverse if rev_mask.index("**/") == 0 rev_mask_value = rev_mask[3..-1] return 0 if rev_value.end_with?("/#{rev_mask_value}") return 0 if rev_mask_value == rev_value return nil end if rev_mask.index("*") == 0 return 0 if rev_value.end_with?(rev_mask[1..-1]) return nil end nil end end end fuzzyurl.rb-0.9.0/lib/fuzzyurl/protocols.rb000066400000000000000000000007151273445007300210750ustar00rootroot00000000000000class Fuzzyurl::Protocols PORTS_BY_PROTOCOL = { 'ssh' => '22', 'http' => '80', 'https' => '443' } PROTOCOLS_BY_PORT = { '22' => 'ssh', '80' => 'http', '443' => 'https' } class << self def get_port(protocol) return nil unless protocol base_protocol = protocol.split('+').last PORTS_BY_PROTOCOL[base_protocol.to_s] end def get_protocol(port) PROTOCOLS_BY_PORT[port.to_s] end end end fuzzyurl.rb-0.9.0/lib/fuzzyurl/strings.rb000066400000000000000000000026321273445007300205420ustar00rootroot00000000000000require 'fuzzyurl/fields' class Fuzzyurl::Strings REGEX = %r{ ^ (?: (? \* | [a-zA-Z][A-Za-z+.-]+) ://)? (?: (? \* | [a-zA-Z0-9%_.!~*'();&=+$,-]+) (?: : (? \* | [a-zA-Z0-9%_.!~*'();&=+$,-]*))? @ )? (? [a-zA-Z0-9\.\*\-_]+?)? (?: : (? \* | \d+))? (? / [^\?\#]*)? ## captures leading / (?: \? (? [^\#]*) )? (?: \# (? .*) )? $ }x class << self def from_string(str, opts={}) return nil unless str.kind_of?(String) default = opts[:default] if m = REGEX.match(str) fu = Fuzzyurl.new Fuzzyurl::FIELDS.each do |f| fu.send("#{f}=", m[f] || default) end fu else raise ArgumentError, "Couldn't parse url string: #{str}" end end def to_string(fuzzyurl) if !fuzzyurl.kind_of?(Fuzzyurl) raise ArgumentError, "`fuzzyurl` must be a Fuzzyurl" end fu = fuzzyurl str = "" str << "#{fu.protocol}://" if fu.protocol str << "#{fu.username}" if fu.username str << ":#{fu.password}" if fu.password str << "@" if fu.username str << "#{fu.hostname}" if fu.hostname str << ":#{fu.port}" if fu.port str << "#{fu.path}" if fu.path str << "?#{fu.query}" if fu.query str << "##{fu.fragment}" if fu.fragment str end end end fuzzyurl.rb-0.9.0/lib/fuzzyurl/version.rb000066400000000000000000000001061273445007300205300ustar00rootroot00000000000000class Fuzzyurl VERSION = "0.9.0" VERSION_DATE = "2016-06-28" end fuzzyurl.rb-0.9.0/test/000077500000000000000000000000001273445007300150205ustar00rootroot00000000000000fuzzyurl.rb-0.9.0/test/fuzzyurl/000077500000000000000000000000001273445007300167325ustar00rootroot00000000000000fuzzyurl.rb-0.9.0/test/fuzzyurl/match_test.rb000066400000000000000000000071441273445007300214200ustar00rootroot00000000000000require 'test_helper' describe Fuzzyurl::Match do describe 'fuzzy_match' do it 'returns 0 for full wildcard' do assert_equal(0, Fuzzyurl::Match.fuzzy_match("*", "lol")) assert_equal(0, Fuzzyurl::Match.fuzzy_match("*", "*")) assert_equal(0, Fuzzyurl::Match.fuzzy_match("*", nil)) end it 'returns 1 for exact match' do assert_equal(1, Fuzzyurl::Match.fuzzy_match('asdf', 'asdf')) end it 'handles *.example.com' do assert_equal(0, Fuzzyurl::Match.fuzzy_match( '*.example.com', 'api.v1.example.com')) assert_equal(nil, Fuzzyurl::Match.fuzzy_match( '*.example.com', 'example.com')) end it 'handles **.example.com' do assert_equal(0, Fuzzyurl::Match.fuzzy_match( '**.example.com', 'api.v1.example.com')) assert_equal(0, Fuzzyurl::Match.fuzzy_match( '**.example.com', 'example.com')) assert_equal(nil, Fuzzyurl::Match.fuzzy_match( '**.example.com', 'zzzexample.com')) end it 'handles path/*' do assert_equal(0, Fuzzyurl::Match.fuzzy_match('path/*', 'path/a/b/c')) assert_equal(nil, Fuzzyurl::Match.fuzzy_match('path/*', 'path')) end it 'handles path/**' do assert_equal(0, Fuzzyurl::Match.fuzzy_match('path/**', 'path/a/b/c')) assert_equal(0, Fuzzyurl::Match.fuzzy_match('path/**', 'path')) assert_equal(nil, Fuzzyurl::Match.fuzzy_match('path/*', 'pathzzz')) end it 'returns nil for bad matches with no wildcards' do assert_equal(nil, Fuzzyurl::Match.fuzzy_match("asdf", "not quite")) end end describe 'match' do fu = Fuzzyurl.new(protocol: "a", username: "b", password: "c", hostname: "d", port: "e", path: "f", query: "g") it 'returns 0 for full wildcard' do assert_equal(0, Fuzzyurl::Match.match(Fuzzyurl.mask, Fuzzyurl.new)) end it 'returns 8 for full exact match' do assert_equal(8, Fuzzyurl::Match.match(fu, fu)) end it 'returns 1 for one exact match' do mask = Fuzzyurl.mask(protocol: "a") assert_equal(1, Fuzzyurl::Match.match(mask, fu)) end it 'infers protocol from port' do mask = Fuzzyurl.mask(port: 80) url = Fuzzyurl.new(protocol: 'http') assert_equal(1, Fuzzyurl::Match.match(mask, url)) url.port = '443' assert_equal(nil, Fuzzyurl::Match.match(mask, url)) end it 'infers port from protocol' do mask = Fuzzyurl.mask(protocol: 'https') url = Fuzzyurl.new(port: '443') assert_equal(1, Fuzzyurl::Match.match(mask, url)) url.protocol = 'http' assert_equal(nil, Fuzzyurl::Match.match(mask, url)) end end describe 'matches?' do it 'returns true for matches' do assert_equal(true, Fuzzyurl::Match.matches?( Fuzzyurl.mask, Fuzzyurl.new)) assert_equal(true, Fuzzyurl::Match.matches?( Fuzzyurl.mask(hostname: "yes"), Fuzzyurl.new(hostname: "yes"))) end it 'returns false for non-matches' do assert_equal(false, Fuzzyurl::Match.matches?( Fuzzyurl.mask(hostname: "yes"), Fuzzyurl.new(hostname: "no"))) end end describe 'match_scores' do it 'has all Fuzzyurl fields' do scores = Fuzzyurl::Match.match_scores(Fuzzyurl.mask, Fuzzyurl.new) assert_equal(scores.keys.sort, Fuzzyurl::FIELDS.sort) end end describe 'best_match_index' do it 'returns the index of the best match' do best = Fuzzyurl.mask("example.com:8888") no_match = Fuzzyurl.mask("example.com:80") url = Fuzzyurl.from_string("http://example.com:8888") assert_equal(1, Fuzzyurl::Match.best_match_index( [Fuzzyurl.mask, best, no_match], url)) end end end fuzzyurl.rb-0.9.0/test/fuzzyurl/protocols_test.rb000066400000000000000000000014221273445007300223410ustar00rootroot00000000000000require 'test_helper' describe Fuzzyurl::Protocols do describe 'get_port' do it 'gets port by protocol' do assert_equal('80', Fuzzyurl::Protocols.get_port('http')) assert_equal('443', Fuzzyurl::Protocols.get_port('https')) assert_equal('22', Fuzzyurl::Protocols.get_port('git+ssh')) assert_equal(nil, Fuzzyurl::Protocols.get_port('hi mom')) assert_equal(nil, Fuzzyurl::Protocols.get_port(nil)) end end describe 'get_protocol' do it 'gets protocol by port' do assert_equal('http', Fuzzyurl::Protocols.get_protocol('80')) assert_equal('http', Fuzzyurl::Protocols.get_protocol(80)) assert_equal(nil, Fuzzyurl::Protocols.get_protocol(nil)) assert_equal(nil, Fuzzyurl::Protocols.get_protocol(-22)) end end end fuzzyurl.rb-0.9.0/test/fuzzyurl/strings_test.rb000066400000000000000000000036301273445007300220110ustar00rootroot00000000000000require 'test_helper' describe Fuzzyurl::Strings do describe 'from_string' do it 'handles simple URLs' do assert(Fuzzyurl::Strings.from_string("http://example.com")) assert(Fuzzyurl::Strings.from_string("ssh://user:pass@host")) assert(Fuzzyurl::Strings.from_string("https://example.com:443/omg/lol")) end it 'rejects bullshit' do assert_equal(nil, Fuzzyurl::Strings.from_string(nil)) assert_equal(nil, Fuzzyurl::Strings.from_string(22)) end it 'handles rich URLs' do fu = Fuzzyurl::Strings.from_string("http://user_1:pass%20word@foo.example.com:8000/some/path?awesome=true&encoding=ebcdic#/hi/mom") assert_equal("http", fu.protocol) assert_equal("user_1", fu.username) assert_equal("pass%20word", fu.password) assert_equal("foo.example.com", fu.hostname) assert_equal("8000", fu.port) assert_equal("/some/path", fu.path) assert_equal("awesome=true&encoding=ebcdic", fu.query) assert_equal("/hi/mom", fu.fragment) end end describe 'to_string' do it 'handles simple URLs' do assert_equal('example.com', Fuzzyurl::Strings.to_string( Fuzzyurl.new(hostname: 'example.com'))) assert_equal('http://example.com', Fuzzyurl::Strings.to_string( Fuzzyurl.new(protocol: 'http', hostname: 'example.com'))) assert_equal('http://example.com/oh/yeah', Fuzzyurl::Strings.to_string( Fuzzyurl.new(path: '/oh/yeah', protocol: 'http', hostname: 'example.com'))) end it 'handles rich URLs' do fu = Fuzzyurl.new( protocol: "https", username: "u", password: "p", hostname: "api.example.com", port: "443", path: "/secret/endpoint", query: "admin=true", fragment: "index" ) assert_equal(Fuzzyurl::Strings.to_string(fu), "https://u:p@api.example.com:443/secret/endpoint?admin=true#index") end end end fuzzyurl.rb-0.9.0/test/fuzzyurl_test.rb000066400000000000000000000056751273445007300203330ustar00rootroot00000000000000require 'test_helper' describe Fuzzyurl do describe 'class methods' do describe 'new' do it 'accepts strings or hashes' do assert_equal(Fuzzyurl.new("example.com:80"), Fuzzyurl.new(hostname: 'example.com', port: '80')) end end describe 'mask' do it 'accepts strings or hashes' do assert_equal(Fuzzyurl.mask("example.com:80"), Fuzzyurl.mask(hostname: 'example.com', port: '80')) end end describe 'to_string' do it 'is delegated' do assert_equal("example.com", Fuzzyurl.to_string(Fuzzyurl.new(hostname: "example.com"))) end end describe 'from_string' do it 'is delegated' do assert_equal(Fuzzyurl.new(hostname: "example.com"), Fuzzyurl.from_string("example.com")) end end describe 'match' do it 'accepts strings or Fuzzyurls' do assert_equal(0, Fuzzyurl.match(Fuzzyurl.mask, "example.com")) end end describe 'matches?' do it 'accepts strings or Fuzzyurls' do assert(Fuzzyurl.matches?(Fuzzyurl.mask, "example.com")) end end describe 'match_scores' do it 'accepts strings or Fuzzyurls' do scores = Fuzzyurl.match_scores(Fuzzyurl.mask, "example.com") assert_equal(8, scores.count) assert_equal(0, scores.values.reduce(:+)) end end describe 'best_match_index' do it 'accepts strings or Fuzzyurls' do assert_equal(1, Fuzzyurl.best_match_index( [Fuzzyurl.mask, "example.com:80", "example.com"], "http://example.com")) end end describe 'best_match' do it 'returns the input object, not always a Fuzzyurl' do assert_equal("example.com:80", Fuzzyurl.best_match( [Fuzzyurl.mask, "example.com:80", "example.com"], "http://example.com")) end end describe 'fuzzy_match' do it 'is delegated' do assert_equal(1, Fuzzyurl.fuzzy_match("a", "a")) end end end # class methods describe 'instance methods' do describe 'to_hash' do it 'works' do assert_equal(Fuzzyurl.new("example.com:8888").to_hash, {protocol: nil, username: nil, password: nil, hostname: 'example.com', port: '8888', path: nil, query: nil, fragment: nil}) end end describe 'with' do it 'creates a new Fuzzyurl object' do fu1 = Fuzzyurl.new(hostname: 'example.com', port: '80') fu2 = fu1.with(port: '8888') assert(fu1 != fu2) assert_equal('example.com', fu1.hostname) assert_equal('example.com', fu2.hostname) assert_equal('80', fu1.port) assert_equal('8888', fu2.port) end end describe 'to_s' do it 'is delegated' do assert_equal("http://example.com", Fuzzyurl.new(protocol: 'http', hostname: 'example.com').to_s) end end end # instance methods end fuzzyurl.rb-0.9.0/test/matches.json000066400000000000000000000052221273445007300173400ustar00rootroot00000000000000{ "version": "0.1.0", "positive_matches": [ [ "*", "http://example.com" ], [ "*", "http://example.com/" ], [ "*", "https://example.com/" ], [ "*", "http://username:password@api.example.com/v1" ], [ "*", "http://example.com/Q@(@*&%&!" ], [ "*", "http://example.com" ], [ "*", "http://user:pass@example.com:12345/some/path%20?query=true&foo=bar#frag" ], [ "http://*", "http://example.com" ], [ "http://*", "http://example.com:80" ], [ "http://*", "http://example.com:8080" ], [ "http://*", "http://example.com/some/path?args=1" ], [ "example.com", "example.com" ], [ "ex_ample.com", "ex_ample.com" ], [ "example.com", "example.com:80" ], [ "example.com", "example.com/a/b/c" ], [ "example.com", "example.com:80/a/b/c" ], [ "example.com", "http://example.com" ], [ "example.com", "http://example.com/some/path?args=1" ], [ "example.com", "http://example.com:80/" ], [ "example.com", "http://example.com" ], [ "example.com/a/*", "example.com/a/b/c" ], [ "https://example.com", "example.com:443" ], [ "http://example.com", "example.com:80" ], [ "*.example.com", "api.example.com" ], [ "*.example.com", "xxx.yyy.example.com" ], [ "example.com:8080", "example.com:8080" ], [ "localhost:12345", "localhost:12345" ], [ "user:pass@host", "http://user:pass@host/some/path?q=1" ], [ "*.example.com:80", "http://www.example.com/index.html" ], [ "example.com:443", "https://example.com/" ], [ "svn+ssh://user@example.com", "svn+ssh://user:pass@example.com/some/path" ] ], "negative_matches": [ [ "http://*", "https://example.com" ], [ "https://*", "http://example.com" ], [ "http://example.com", "http://www.example.com" ], [ "*.example.com", "example.com" ], [ "example.com/a/*", "example.com/b/a/b/c" ], [ "example.com/a/*", "foobar.com/a/b/c" ], [ "example.com:888", "example.com:8888" ], [ "user:pass@host", "http://user:@host/some/path?q=1" ], [ "user:pass@host", "http://user@host/some/path?q=1" ] ] } fuzzyurl.rb-0.9.0/test/test_helper.rb000066400000000000000000000002451273445007300176640ustar00rootroot00000000000000require 'coveralls' Coveralls.wear!('rails') require 'minitest/autorun' require 'minitest/pride' require 'mocha/setup' require 'pp' require 'pry' require 'fuzzyurl' fuzzyurl.rb-0.9.0/test/url_suite_test.rb000066400000000000000000000010531273445007300204160ustar00rootroot00000000000000require 'test_helper' require 'json' MATCHES = JSON.parse(File.read(File.expand_path("../matches.json", __FILE__))) describe 'URL test suite' do describe 'positive matches' do MATCHES['positive_matches'].each do |(mask, url)| it "'#{mask}' matches '#{url}'" do assert(Fuzzyurl.matches?(mask, url)) end end end describe 'negative matches' do MATCHES['negative_matches'].each do |(mask, url)| it "'#{mask}' does not match '#{url}'" do assert(!Fuzzyurl.matches?(mask, url)) end end end end