]> git.openstreetmap.org Git - rails.git/blob - lib/tag2link.rb
Increase tag2link item leniency
[rails.git] / lib / tag2link.rb
1 # frozen_string_literal: true
2
3 module Tag2link
4   def self.load(path)
5     @dict = build_dict(JSON.parse(path.read)).freeze
6   end
7
8   def self.link(key, value)
9     # skip if it's a full URL
10     return nil if %r{\Ahttps?://}.match?(value)
11
12     url_template = @dict[key]
13     return nil unless url_template
14
15     url_template.gsub("$1", value)
16   end
17
18   def self.build_dict(data)
19     data
20       # exclude deprecated and third-party URLs
21       .reject { |item| item["rank"] == "deprecated" || item["source"] == "wikidata:P3303" }
22       .group_by { |item| item["key"].sub(/^Key:/, "") }
23       .transform_values { |items| choose_best_item(items) }
24       .compact
25       .transform_values { |items| items["url"] }
26   end
27
28   def self.choose_best_item(items)
29     return nil if items.blank?
30
31     return items.first if items.size == 1
32
33     # move preferred to the start of the array
34     ranked = items.sort_by { |item| item["rank"] == "preferred" ? 0 : 1 }.uniq { |item| item["url"] }
35     top_rank = ranked.first["rank"]
36     top_items = ranked.select { |i| i["rank"] == top_rank }
37
38     # if only one top-ranked item, prefer that
39     return top_items.first if top_items.size == 1
40
41     grouped = top_items.group_by { |i| i["source"] }
42     return nil if grouped.size > 2
43
44     # if both sources have exactly one preferred, prefer osmwiki
45     return grouped["osmwiki:P8"]&.first || grouped.values.flatten.first if grouped.all? { |_s, vals| vals.size == 1 }
46
47     # if one source has multiple preferreds and the other has one, prefer the single one
48     return grouped.min_by { |_s, vals| vals.size }.last.first if grouped.any? { |_s, vals| vals.size == 1 }
49
50     # exclude any that are ambiguous
51     nil
52   end
53   private_class_method :choose_best_item
54 end