Class: Clickwrap::IpGeolocation::Location

Inherits:
Data
  • Object
show all
Defined in:
lib/clickwrap/ip_geolocation/location.rb

Overview

One provider's estimate about ONE IP address, at one moment.

Read that sentence literally, because the whole design follows from it. This object never describes where a person was. It describes what a provider's database or edge network said about a network address, with enough provenance attached that someone reading it in four years can tell how much weight it deserves. That is why provider name, source, estimated state, resolution time, and any database or accuracy metadata are members of the same value object as the country code: a country without the provider that guessed it, or coordinates without an accuracy radius, read as far more certain than they are.

Every member defaults to nil so a resolver fills in only what it actually has. A resolver must NEVER substitute a placeholder — "Unknown", "XX", "N/A" — for a field it could not determine. A placeholder is indistinguishable from a real provider answer once it is written down, and Clickwrap keeps "we did not collect this", "the provider had no value", "the lookup failed", and "the provider answered" as four different states. nil is the honest answer; unavailable_reason is how a resolver explains a failure.

to_h exists because this is a Data object. It is not a persistence format: the extractor copies out exactly the fields the server-owned policy authorized, one at a time, and a resolver that gains a new field upstream never widens what Clickwrap stores by accident.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(country_code: nil, country_name: nil, region_name: nil, region_code: nil, city_name: nil, postal_code: nil, latitude: nil, longitude: nil, timezone: nil, continent_code: nil, metro_code: nil, provider_name: nil, provider_source: nil, database_version: nil, database_sha256: nil, accuracy_radius_in_kilometers: nil, accuracy_radius_confidence_percentage: nil, estimated: true, source_was_verified_by_host: false, resolved_at: nil, unavailable_reason: nil) ⇒ Location

estimated defaults to true and source_was_verified_by_host to false because those are the answers that overclaim least. A resolver has to say something deliberate to move either one, and moving source_was_verified_by_host requires a host decision about its own network path — never the mere presence of a provider's headers.



58
59
60
61
62
63
64
65
66
67
# File 'lib/clickwrap/ip_geolocation/location.rb', line 58

def initialize(country_code: nil, country_name: nil, region_name: nil, region_code: nil,
               city_name: nil, postal_code: nil, latitude: nil, longitude: nil,
               timezone: nil, continent_code: nil, metro_code: nil,
               provider_name: nil, provider_source: nil, database_version: nil,
               database_sha256: nil, accuracy_radius_in_kilometers: nil,
               accuracy_radius_confidence_percentage: nil, estimated: true,
               source_was_verified_by_host: false, resolved_at: nil,
               unavailable_reason: nil)
  super
end

Instance Attribute Details

#accuracy_radius_confidence_percentageObject (readonly)

Returns the value of attribute accuracy_radius_confidence_percentage

Returns:

  • (Object)

    the current value of accuracy_radius_confidence_percentage



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def accuracy_radius_confidence_percentage
  @accuracy_radius_confidence_percentage
end

#accuracy_radius_in_kilometersObject (readonly)

Returns the value of attribute accuracy_radius_in_kilometers

Returns:

  • (Object)

    the current value of accuracy_radius_in_kilometers



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def accuracy_radius_in_kilometers
  @accuracy_radius_in_kilometers
end

#city_nameObject (readonly)

Returns the value of attribute city_name

Returns:

  • (Object)

    the current value of city_name



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def city_name
  @city_name
end

#continent_codeObject (readonly)

Returns the value of attribute continent_code

Returns:

  • (Object)

    the current value of continent_code



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def continent_code
  @continent_code
end

#country_codeObject (readonly)

Returns the value of attribute country_code

Returns:

  • (Object)

    the current value of country_code



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def country_code
  @country_code
end

#country_nameObject (readonly)

Returns the value of attribute country_name

Returns:

  • (Object)

    the current value of country_name



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def country_name
  @country_name
end

#database_sha256Object (readonly)

Returns the value of attribute database_sha256

Returns:

  • (Object)

    the current value of database_sha256



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def database_sha256
  @database_sha256
end

#database_versionObject (readonly)

Returns the value of attribute database_version

Returns:

  • (Object)

    the current value of database_version



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def database_version
  @database_version
end

#estimatedObject (readonly)

Returns the value of attribute estimated

Returns:

  • (Object)

    the current value of estimated



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def estimated
  @estimated
end

#latitudeObject (readonly)

Returns the value of attribute latitude

Returns:

  • (Object)

    the current value of latitude



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def latitude
  @latitude
end

#longitudeObject (readonly)

Returns the value of attribute longitude

Returns:

  • (Object)

    the current value of longitude



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def longitude
  @longitude
end

#metro_codeObject (readonly)

Returns the value of attribute metro_code

Returns:

  • (Object)

    the current value of metro_code



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def metro_code
  @metro_code
end

#postal_codeObject (readonly)

Returns the value of attribute postal_code

Returns:

  • (Object)

    the current value of postal_code



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def postal_code
  @postal_code
end

#provider_nameObject (readonly)

Returns the value of attribute provider_name

Returns:

  • (Object)

    the current value of provider_name



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def provider_name
  @provider_name
end

#provider_sourceObject (readonly)

Returns the value of attribute provider_source

Returns:

  • (Object)

    the current value of provider_source



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def provider_source
  @provider_source
end

#region_codeObject (readonly)

Returns the value of attribute region_code

Returns:

  • (Object)

    the current value of region_code



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def region_code
  @region_code
end

#region_nameObject (readonly)

Returns the value of attribute region_name

Returns:

  • (Object)

    the current value of region_name



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def region_name
  @region_name
end

#resolved_atObject (readonly)

Returns the value of attribute resolved_at

Returns:

  • (Object)

    the current value of resolved_at



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def resolved_at
  @resolved_at
end

#source_was_verified_by_hostObject (readonly)

Returns the value of attribute source_was_verified_by_host

Returns:

  • (Object)

    the current value of source_was_verified_by_host



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def source_was_verified_by_host
  @source_was_verified_by_host
end

#timezoneObject (readonly)

Returns the value of attribute timezone

Returns:

  • (Object)

    the current value of timezone



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def timezone
  @timezone
end

#unavailable_reasonObject (readonly)

Returns the value of attribute unavailable_reason

Returns:

  • (Object)

    the current value of unavailable_reason



30
31
32
# File 'lib/clickwrap/ip_geolocation/location.rb', line 30

def unavailable_reason
  @unavailable_reason
end

Class Method Details

.unavailable(reason:, provider_name: nil, **provenance) ⇒ Object

The answer a resolver returns when it has nothing to report. It still names the provider that was asked, because "MaxMind had no row for this address" and "no resolver was configured at all" are different facts and a receipt has to be able to tell them apart.



73
74
75
# File 'lib/clickwrap/ip_geolocation/location.rb', line 73

def self.unavailable(reason:, provider_name: nil, **provenance)
  new(unavailable_reason: reason.to_s, provider_name:, **provenance)
end

Instance Method Details

#accuracy_radius?Boolean

Returns:

  • (Boolean)


98
# File 'lib/clickwrap/ip_geolocation/location.rb', line 98

def accuracy_radius? = !accuracy_radius_in_kilometers.nil?

#any_data_field?Boolean

True when the provider actually reported something about the address, as opposed to handing back a row of blanks. An adapter uses this to turn an empty answer into an explicit unavailable result with a reason, which is the whole point of refusing to write "Unknown" into a name column: an empty result and a real one must never look the same.

Returns:

  • (Boolean)


105
106
107
108
109
# File 'lib/clickwrap/ip_geolocation/location.rb', line 105

def any_data_field?
  [country_code, country_name, region_name, region_code, city_name, postal_code,
   latitude, longitude, timezone, continent_code, metro_code,
   accuracy_radius_in_kilometers].any? { |value| !value.nil? }
end

#coordinates?Boolean

Latitude and longitude are one coupled answer. Half a coordinate is not a result, so nothing downstream is allowed to store one without the other.

Returns:

  • (Boolean)


96
# File 'lib/clickwrap/ip_geolocation/location.rb', line 96

def coordinates? = !latitude.nil? && !longitude.nil?

#estimated?Boolean

An IP-geolocation result is an estimate about an address. This reader reports what the resolver said about its own result rather than hard-coding the answer, but a resolver claiming otherwise still does not turn an observation about a network address into a statement about where anyone was, and the receipt goes on labeling the value provider-reported either way.

Returns:

  • (Boolean)


85
# File 'lib/clickwrap/ip_geolocation/location.rb', line 85

def estimated? = estimated != false

#source_was_verified_by_host?Boolean

True only when the HOST told Clickwrap that this result arrived over a path it has verified. No adapter may set it from the presence of a provider's own headers: headers are attacker-supplied until the deployment proves otherwise.

Returns:

  • (Boolean)


91
# File 'lib/clickwrap/ip_geolocation/location.rb', line 91

def source_was_verified_by_host? = source_was_verified_by_host == true

#unavailable?Boolean

Returns:

  • (Boolean)


77
# File 'lib/clickwrap/ip_geolocation/location.rb', line 77

def unavailable? = !unavailable_reason.to_s.strip.empty?