1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
# encoding: UTF-8
# frozen_string_literal: true
module TZInfo
module DataSources
# A {TZInfoDataNotFound} exception is raised if the tzinfo-data gem could
# not be found (i.e. `require 'tzinfo/data'` failed) when selecting the Ruby
# data source.
class TZInfoDataNotFound < StandardError
end
# A DataSource implementation that loads data from the set of Ruby modules
# included in the tzinfo-data gem.
#
# TZInfo will use {RubyDataSource} by default if the tzinfo-data gem
# is available on the load path. It can also be selected by calling
# {DataSource.set} as follows:
#
# TZInfo::DataSource.set(:ruby)
class RubyDataSource < DataSource
# (see DataSource#data_timezone_identifiers)
attr_reader :data_timezone_identifiers
# (see DataSource#linked_timezone_identifiers)
attr_reader :linked_timezone_identifiers
# (see DataSource#country_codes)
attr_reader :country_codes
# Initializes a new {RubyDataSource} instance.
#
# @raise [TZInfoDataNotFound] if the tzinfo-data gem could not be found
# (i.e. `require 'tzinfo/data'` failed).
def initialize
super
begin
require('tzinfo/data')
rescue LoadError
raise TZInfoDataNotFound, "The tzinfo-data gem could not be found (require 'tzinfo/data' failed)."
end
if TZInfo::Data.const_defined?(:LOCATION)
# Format 2
@base_path = File.join(TZInfo::Data::LOCATION, 'tzinfo', 'data')
else
# Format 1
data_file = File.join('', 'tzinfo', 'data.rb')
path = $".reverse_each.detect {|p| p.end_with?(data_file) }
if path
@base_path = RubyCoreSupport.untaint(File.join(File.dirname(path), 'data'))
else
@base_path = 'tzinfo/data'
end
end
require_index('timezones')
require_index('countries')
@data_timezone_identifiers = Data::Indexes::Timezones.data_timezones
@linked_timezone_identifiers = Data::Indexes::Timezones.linked_timezones
@countries = Data::Indexes::Countries.countries
@country_codes = @countries.keys.sort!.freeze
end
# (see DataSource#to_s)
def to_s
"Ruby DataSource: #{version_info}"
end
# (see DataSource#inspect)
def inspect
"#<TZInfo::DataSources::RubyDataSource: #{version_info}>"
end
protected
# Returns a {TimezoneInfo} instance for the given time zone identifier.
# The result will either be a {ConstantOffsetDataTimezoneInfo}, a
# {TransitionsDataTimezoneInfo} or a {LinkedTimezoneInfo} depending on the
# type of time zone.
#
# @param identifier [String] A time zone identifier.
# @return [TimezoneInfo] a {TimezoneInfo} instance for the given time zone
# identifier.
# @raise [InvalidTimezoneIdentifier] if the time zone is not found or the
# identifier is invalid.
def load_timezone_info(identifier)
valid_identifier = validate_timezone_identifier(identifier)
split_identifier = valid_identifier.gsub(/-/, '__m__').gsub(/\+/, '__p__').split('/')
begin
require_definition(split_identifier)
m = Data::Definitions
split_identifier.each {|part| m = m.const_get(part) }
m.get
rescue LoadError, NameError => e
raise InvalidTimezoneIdentifier, "#{e.message.encode(Encoding::UTF_8)} (loading #{valid_identifier})"
end
end
# (see DataSource#load_country_info)
def load_country_info(code)
lookup_country_info(@countries, code)
end
private
# Requires a zone definition by its identifier (split on /).
#
# @param identifier [Array<string>] the component parts of a time zone
# identifier (split on /). This must have already been validated.
def require_definition(identifier)
require_data('definitions', *identifier)
end
# Requires an index by its name.
#
# @param name [String] an index name.
def require_index(name)
require_data('indexes', name)
end
# Requires a file from tzinfo/data.
#
# @param file [Array<String>] a relative path to a file to be required.
def require_data(*file)
require(File.join(@base_path, *file))
end
# @return [String] a `String` containing TZInfo::Data version infomation
# for inclusion in the #to_s and #inspect output.
def version_info
# The TZInfo::Data::VERSION constant is only available from v1.2014.8
# onwards.
"tzdb v#{TZInfo::Data::Version::TZDATA}#{TZInfo::Data.const_defined?(:VERSION) ? ", tzinfo-data v#{TZInfo::Data::VERSION}" : ''}"
end
end
end
end
|