country.rb 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #--
  2. # Copyright (c) 2005-2010 Philip Ross
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in all
  12. # copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. # THE SOFTWARE.
  21. #++
  22. module TZInfo
  23. # Thrown by Country#get if the code given is not valid.
  24. class InvalidCountryCode < StandardError
  25. end
  26. # An ISO 3166 country. Can be used to get a list of Timezones for a country.
  27. # For example:
  28. #
  29. # us = Country.get('US')
  30. # us.zone_identifiers
  31. # us.zones
  32. # us.zone_info
  33. class Country
  34. include Comparable
  35. # Defined countries.
  36. @@countries = {}
  37. # Whether the countries index has been loaded yet.
  38. @@index_loaded = false
  39. # Gets a Country by its ISO 3166 code. Raises an InvalidCountryCode
  40. # exception if it couldn't be found.
  41. def self.get(identifier)
  42. instance = @@countries[identifier]
  43. unless instance
  44. load_index
  45. info = Indexes::Countries.countries[identifier]
  46. raise InvalidCountryCode.new, 'Invalid identifier' unless info
  47. instance = Country.new(info)
  48. @@countries[identifier] = instance
  49. end
  50. instance
  51. end
  52. # If identifier is a CountryInfo object, initializes the Country instance,
  53. # otherwise calls get(identifier).
  54. def self.new(identifier)
  55. if identifier.kind_of?(CountryInfo)
  56. instance = super()
  57. instance.send :setup, identifier
  58. instance
  59. else
  60. get(identifier)
  61. end
  62. end
  63. # Returns an Array of all the valid country codes.
  64. def self.all_codes
  65. load_index
  66. Indexes::Countries.countries.keys
  67. end
  68. # Returns an Array of all the defined Countries.
  69. def self.all
  70. load_index
  71. Indexes::Countries.countries.keys.collect {|code| get(code)}
  72. end
  73. # The ISO 3166 country code.
  74. def code
  75. @info.code
  76. end
  77. # The name of the country.
  78. def name
  79. @info.name
  80. end
  81. # Alias for name.
  82. def to_s
  83. name
  84. end
  85. # Returns internal object state as a programmer-readable string.
  86. def inspect
  87. "#<#{self.class}: #{@info.code}>"
  88. end
  89. # Returns a frozen array of all the zone identifiers for the country. These
  90. # are in an order that
  91. # (1) makes some geographical sense, and
  92. # (2) puts the most populous zones first, where that does not contradict (1).
  93. def zone_identifiers
  94. @info.zone_identifiers
  95. end
  96. alias zone_names zone_identifiers
  97. # An array of all the Timezones for this country. Returns TimezoneProxy
  98. # objects to avoid the overhead of loading Timezone definitions until
  99. # a conversion is actually required. The Timezones are returned in an order
  100. # that
  101. # (1) makes some geographical sense, and
  102. # (2) puts the most populous zones first, where that does not contradict (1).
  103. def zones
  104. zone_identifiers.collect {|id|
  105. Timezone.get_proxy(id)
  106. }
  107. end
  108. # Returns a frozen array of all the timezones for the for the country as
  109. # CountryTimezone instances (containing extra information about each zone).
  110. # These are in an order that
  111. # (1) makes some geographical sense, and
  112. # (2) puts the most populous zones first, where that does not contradict (1).
  113. def zone_info
  114. @info.zones
  115. end
  116. # Compare two Countries based on their code. Returns -1 if c is less
  117. # than self, 0 if c is equal to self and +1 if c is greater than self.
  118. def <=>(c)
  119. code <=> c.code
  120. end
  121. # Returns true if and only if the code of c is equal to the code of this
  122. # Country.
  123. def eql?(c)
  124. self == c
  125. end
  126. # Returns a hash value for this Country.
  127. def hash
  128. code.hash
  129. end
  130. # Dumps this Country for marshalling.
  131. def _dump(limit)
  132. code
  133. end
  134. # Loads a marshalled Country.
  135. def self._load(data)
  136. Country.get(data)
  137. end
  138. private
  139. # Loads in the index of countries if it hasn't already been loaded.
  140. def self.load_index
  141. unless @@index_loaded
  142. require 'tzinfo/indexes/countries'
  143. @@index_loaded = true
  144. end
  145. end
  146. # Called by Country.new to initialize a new Country instance. The info
  147. # parameter is a CountryInfo that defines the country.
  148. def setup(info)
  149. @info = info
  150. end
  151. end
  152. end