Class: TzPickup::TzTree

Inherits:
Object
  • Object
show all
Defined in:
lib/tz_pickup/tz_tree.rb

Constant Summary collapse

DB_PATH =
'db'
ZONE_FILE =
'zone.tab'
TREE_FILE =
'zone.tree'
CITY_FILE =
'zone.cities'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ TzTree

Constructor that search for tree-file under path and either loads tree to memory or creates file and loads its contents to memory

Input: root-path for working directory Output: TzTree object



48
49
50
51
52
53
54
55
# File 'lib/tz_pickup/tz_tree.rb', line 48

def initialize(path)
  @path = path
  @tree, @cities = if File.exists?(tree_dst_path) && File.exists?(city_dst_path)
    TzPickup::TzTree.load(tree_dst_path, city_dst_path)
  else
    TzPickup::TzTree.create(src_path, tree_dst_path, city_dst_path)
  end
end

Class Method Details

.create(src, tree_dst, city_dst) ⇒ Object

Method creates tree structure from src zone-file and dumps tree to tree_dst file and dumps cities list to city_dst

It raises exception on error of file reading

Input: name of source zone-file, name of destination tree file, name of destination cities file, Output: list of tree structure for time-zones and cities list



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/tz_pickup/tz_tree.rb', line 91

def self.create(src, tree_dst, city_dst)
  points = []
  cities = []

  File.open(src, 'r').each do |line|
    timezone = TzPickup::TzTree.parse_line(line)
    
    next unless timezone

    cities << timezone[2]
    points << [timezone[0], timezone[1], (cities.size - 1)]
  end

  tree = Kdtree.new(points)

  File.open(tree_dst, 'w') { |f| tree.persist(f) }
  File.open(city_dst, 'w') { |f| f.puts cities }
  
  [tree, cities]
end

.get_tree(path) ⇒ Object

Method creates object of TzTree that is based on zone-file located under path directory

Input: root-path for working directory Output: TzTree object



15
16
17
# File 'lib/tz_pickup/tz_tree.rb', line 15

def self.get_tree(path)
  TzPickup::TzTree.new(path)
end

.load(zone_file, city_file) ⇒ Object

Method loads tree structure from existing zone_file and existiong city_file

Input: name of zone tree file and name of cities file Output: tree structure for time-zones and city list



121
122
123
124
125
126
127
128
129
130
131
# File 'lib/tz_pickup/tz_tree.rb', line 121

def self.load(zone_file, city_file)
  cities = []

  tree = File.open(zone_file) { |f| Kdtree.new(f) }

  File.open(city_file, 'r').each do |line|
    cities << line.chomp
  end

  [tree, cities]
end

.normalize(num) ⇒ Object



37
38
39
40
# File 'lib/tz_pickup/tz_tree.rb', line 37

def self.normalize(num)
  return num.to_i * 100 if num =~ /^[+\-]\d{4}\d?$/
  num.to_i
end

.parse_line(line) ⇒ Object

Method parses line of text to list of three params

Input: line of text Output: list of longitude, latitude and timezone name

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
# File 'lib/tz_pickup/tz_tree.rb', line 26

def self.parse_line(line)
  return nil if line =~ /^\s*#/ #drop off comments

  rx = %r|[A-Z]{2}\s+(?<latitude>[+\-]\d{4}(?:\d{2})?)(?<longitude>[+\-]\d{5}(?:\d{2})?)\s+(?<timezone>[\w/]+)|
  matches = line.match(rx)
  
  raise ArgumentError, "String should match tz database format (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)" unless matches

  [normalize(matches[:latitude]), normalize(matches[:longitude]), matches[:timezone]]
end

Instance Method Details

#city_dst_pathObject



65
66
67
# File 'lib/tz_pickup/tz_tree.rb', line 65

def city_dst_path
  File.join(@path, TzPickup::TzTree::DB_PATH, TzPickup::TzTree::CITY_FILE)
end

#find_tz(lat, lon) ⇒ Object

Method finds to the nearest dot to the dot specified by lat and lon

Input: latitude and longitude Output: conventional timezone name



75
76
77
78
# File 'lib/tz_pickup/tz_tree.rb', line 75

def find_tz(lat, lon)
  city_index = @tree.nearest(lat, lon)
  @cities.at(city_index)
end

#src_pathObject



57
58
59
# File 'lib/tz_pickup/tz_tree.rb', line 57

def src_path
  File.join(@path, TzPickup::TzTree::DB_PATH, TzPickup::TzTree::ZONE_FILE)
end

#tree_dst_pathObject



61
62
63
# File 'lib/tz_pickup/tz_tree.rb', line 61

def tree_dst_path
  File.join(@path, TzPickup::TzTree::DB_PATH, TzPickup::TzTree::TREE_FILE)
end