-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use semantic versioning for dependencies. Take a more object oriented approach, rather than using a bunch of module functions. Add some badges. Use Curb and Oj instead of HTTPClient and JSON. See the changelog for more information.
- Loading branch information
Showing
8 changed files
with
169 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
source 'https://rubygems.org' | ||
|
||
gem('httpclient', '2.7.1') | ||
gem('rainbow', '2.0.0') | ||
gem('string-utility', '2.5.0') | ||
gem('curb', '~> 0.9.x') | ||
gem('data_types', '~> 1.x') | ||
gem('oj', '~> 2.x') | ||
gem('rainbow', '~> 2.x') | ||
gem('string-utility', '~> 2.x') | ||
|
||
ruby '2.3.0' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,21 @@ | ||
GEM | ||
remote: https://rubygems.org/ | ||
specs: | ||
httpclient (2.7.1) | ||
curb (0.9.1) | ||
data_types (1.1.0) | ||
oj (2.15.0) | ||
rainbow (2.0.0) | ||
string-utility (2.5.0) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
httpclient (= 2.7.1) | ||
rainbow (= 2.0.0) | ||
string-utility (= 2.5.0) | ||
curb (~> 0.9.x) | ||
data_types (~> 1.x) | ||
oj (~> 2.x) | ||
rainbow (~> 2.x) | ||
string-utility (~> 2.5.x) | ||
|
||
BUNDLED WITH | ||
1.11.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,188 +1,24 @@ | ||
require 'httpclient' | ||
require 'json' | ||
require 'curb' | ||
require 'oj' | ||
require 'data_types/pair' | ||
require_relative 'simple_geolocator/ipapi_response' | ||
|
||
module SimpleGeolocator | ||
extend self | ||
module_function | ||
|
||
@client = HTTPClient.new | ||
@cache = {} | ||
|
||
# Gets the full JSON response, useful for getting multiple pieces of data in | ||
# a single request. | ||
# @param ip [String] The IP to get data for. | ||
# @return [JSON] A parsed JSON object containing the response. | ||
def get_full_response(ip) | ||
return @cache[ip] unless @cache[ip].nil? | ||
url = "http://ip-api.com/json/#{ip}?fields=258047" | ||
uri = URI.parse(url) | ||
response = @client.get(uri) | ||
@cache[ip] = JSON.parse(response.body) | ||
end | ||
|
||
# Gets whether the request failed or not. | ||
# @param response [JSON] The parsed response body (#get_full_response) to | ||
# check. | ||
# @return [Boolean] True if successful, false if errored. | ||
def request_successful?(response) | ||
case response['status'] | ||
when 'success' | ||
true | ||
when 'fail' | ||
false | ||
end | ||
end | ||
|
||
# Gets the country data for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [Hash] A hash containing data formatted as | ||
# { :name => 'United States', :code => 'US' } | ||
# @return [String] A string containing the error message. | ||
def country(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
ret = { | ||
name: response['country'], | ||
code: response['countryCode'] | ||
} | ||
ret | ||
end | ||
|
||
# Gets the region data for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [Hash] A hash containing data formatted as | ||
# { :name => 'Oregon', :code => 'OR'} | ||
# @return [String] A string containing the error message. | ||
def region(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
ret = { | ||
name: response['regionName'], | ||
code: response['region'] | ||
} | ||
ret | ||
end | ||
|
||
# Gets the city name for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [String] The name of the city that the IP is located in. | ||
# @return [String] A string containing the error message. | ||
def city(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
|
||
response['city'] | ||
end | ||
|
||
# Gets the zip code for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [Int] The zip code that the IP is located in. | ||
# @return [String] A string containing the error message. | ||
def zip(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
|
||
response['zip'].to_i | ||
end | ||
|
||
# Gets the latitude, longitude for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [Array] An array of Floats formatted as lat, lon | ||
# @return [String] A string containing the error message. | ||
def ll(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
|
||
ret = [response['lat'], response['lon']] | ||
ret | ||
end | ||
|
||
# Gets the timezone for the IP. | ||
# @param ip [String] See #get_full_response | ||
# @return [String] The timezone (UTC, PST, etc.) that the IP is in. | ||
# @return [String] A string containing the error message. | ||
def timezone(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
|
||
response['timezone'] | ||
end | ||
|
||
# Gets the name of the IP's Internet Service Provider. | ||
# @param ip [String] See #get_full_response | ||
# @return [String] The ISP name, such as Comcast Cable. | ||
# @return [String] A string containing the error message. | ||
def isp_name(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
|
||
response['isp'] | ||
end | ||
|
||
# Gets the name of the IP's organization. For most people, this is identical | ||
# to their ISP name. | ||
# @param ip [String] See #get_full_response | ||
# @return [String] The organization name, such as Google. | ||
# @return [String] A string containing the error message. | ||
def organization_name(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
URL_FORMAT = 'http://ip-api.com/json/%s?fields=258047'.freeze | ||
|
||
response['org'] | ||
end | ||
|
||
# Gets the IP connection attributes - if it's a mobile and/or a proxy | ||
# connection. | ||
# @param ip [String] See #get_full_response | ||
# @return [Hash] A hash containing data formatted as | ||
# { :mobile => true, :proxy => true} | ||
# @return [String] A string containing the error message. | ||
def connection(ip) | ||
response = get_full_response(ip) | ||
err = error(response) | ||
return err unless err.nil? | ||
ret = { | ||
mobile: response['mobile'], | ||
proxy: response['proxy'] | ||
} | ||
ret | ||
end | ||
|
||
# Gets the according description for the semi-ambiguous error returned by the | ||
# API. | ||
# @param error [String] The error message returned by #error | ||
# @return [String] The error description. | ||
# @return [Nil] If you provided an invalid error message. | ||
def get_error_description(error) | ||
case error | ||
when 'private range' | ||
return 'The IP address is part of a private range.' | ||
when 'reserved range' | ||
return 'The IP address is part of a reserved range.' | ||
when 'invalid query' | ||
return 'The IP address or domain name is invalid.' | ||
when 'quota' | ||
return 'You have reached the quota.' | ||
else | ||
return nil | ||
end | ||
end | ||
|
||
private | ||
|
||
# Gets the error message from a response. | ||
# @param response [JSON] See #request_successful? | ||
# @return [String] The error message. | ||
# @return [Nil] If there was no error message to begin with. | ||
def error(response) | ||
return response['message'] unless request_successful?(response) | ||
nil | ||
# Gets the full response. From here, all the data related to the IP can be accessed. Caches the result in order to | ||
# prevent reaching the rate limit. | ||
# @param ip [String] The IP to get data for. | ||
# @return [IPAPIResponse] The full parsed response object. | ||
def get(ip) | ||
return @cache[ip] if @cache.key?(ip) | ||
url = format(URL_FORMAT, ip) | ||
response = Curl.get(url).body_str | ||
ipapi = SimpleGeolocator::IPAPIResponse.new(Oj.load(response)) | ||
@cache[ip] = ipapi | ||
end | ||
end |
Oops, something went wrong.