File: ruby_data_source.rb

package info (click to toggle)
ruby-tzinfo 2.0.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,824 kB
  • sloc: ruby: 21,667; makefile: 6
file content (141 lines) | stat: -rw-r--r-- 4,860 bytes parent folder | download
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