atlasq 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/exe/atlasq +14 -0
- data/lib/atlasq/command/any.rb +23 -0
- data/lib/atlasq/command/base.rb +30 -0
- data/lib/atlasq/command/country.rb +28 -0
- data/lib/atlasq/command/help.rb +74 -0
- data/lib/atlasq/command/money.rb +27 -0
- data/lib/atlasq/command/region.rb +27 -0
- data/lib/atlasq/command/usage.rb +32 -0
- data/lib/atlasq/command/version.rb +19 -0
- data/lib/atlasq/command.rb +43 -0
- data/lib/atlasq/data/currency.rb +20 -0
- data/lib/atlasq/data/region.rb +24 -0
- data/lib/atlasq/data.rb +113 -0
- data/lib/atlasq/format.rb +223 -0
- data/lib/atlasq/shell.rb +33 -0
- data/lib/atlasq/util/string.rb +17 -0
- data/lib/atlasq/util.rb +7 -0
- data/lib/atlasq/version.rb +5 -0
- data/lib/atlasq.rb +22 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bd73be0c020537a173190c8f4c4578405f082230a9de1364e50abcaf84807d25
|
4
|
+
data.tar.gz: bd5cef4f2fb398bd86e402564ffe3c7853e8f3ec37330925cd9ca386c0636687
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c508e56e7b5329c15a819ca5061c17cfc7f6887d4753c26f023d33d3c04548fdecb027ace154449969b36473a1b06a004c31474bd1b5c080ec03bcd71a7d71aa
|
7
|
+
data.tar.gz: 838990550b22eeb3d2b2268c1a80aa3bfb2035ae4d482cb1a86d681af31252c8f2b6a2edefbfd95ae62cad950e93ad3115128013102daaffd76a5481b7078ff3
|
data/exe/atlasq
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
debug = true if ARGV.delete("-d")
|
5
|
+
debug = true if ARGV.delete("--debug")
|
6
|
+
ENV["ATLASQ_DEBUG"] = "1" if debug
|
7
|
+
|
8
|
+
# Avoid warnings on Ruby 2.7 related to pattern matching.
|
9
|
+
Warning[:experimental] = false
|
10
|
+
|
11
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
12
|
+
require "atlasq"
|
13
|
+
|
14
|
+
Atlasq::Shell.start!
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Any < Base
|
8
|
+
def content
|
9
|
+
search_terms.map do |term|
|
10
|
+
data = Data.any(term)
|
11
|
+
empty = data.empty? if data.respond_to?(:empty?)
|
12
|
+
|
13
|
+
if data && !empty
|
14
|
+
Format.any(data, term)
|
15
|
+
else
|
16
|
+
Atlasq.failed!
|
17
|
+
"Unknown search term: #{term}"
|
18
|
+
end
|
19
|
+
end.join("\n\n")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Command
|
5
|
+
class Base
|
6
|
+
attr_reader :search_terms
|
7
|
+
|
8
|
+
# @param term [Array<String>]
|
9
|
+
# @return [String]
|
10
|
+
def self.run(terms)
|
11
|
+
new(terms).content
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Boolean]
|
15
|
+
def self.to_pager?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param search_terms [Array<String>]
|
20
|
+
def initialize(search_terms)
|
21
|
+
@search_terms = search_terms
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String]
|
25
|
+
def content
|
26
|
+
NotImplementedError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Country < Base
|
8
|
+
# @return [String]
|
9
|
+
def content
|
10
|
+
if search_terms.empty?
|
11
|
+
countries = Data.all_countries
|
12
|
+
Format.countries(countries, title: "All Countries")
|
13
|
+
else
|
14
|
+
search_terms.map do |term|
|
15
|
+
country = Data.country(term)
|
16
|
+
|
17
|
+
if country
|
18
|
+
Format.country(country, term)
|
19
|
+
else
|
20
|
+
Atlasq.failed!
|
21
|
+
"Unknown country: #{term}"
|
22
|
+
end
|
23
|
+
end.join("\n\n")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Help < Base
|
8
|
+
# @return [String]
|
9
|
+
def content
|
10
|
+
<<~HELP
|
11
|
+
NAME
|
12
|
+
atlasq -- a utility to query country info
|
13
|
+
|
14
|
+
SYNOPSIS:
|
15
|
+
atlasq [query ...]
|
16
|
+
atlasq [option]
|
17
|
+
atlasq [option] [query ...]
|
18
|
+
|
19
|
+
DESCRIPTIONS
|
20
|
+
Atlas Query aims to be the the simplest way to query for country
|
21
|
+
info at the command line. It includes logic to not only find
|
22
|
+
countries by name but also by region and currency.
|
23
|
+
|
24
|
+
To do this we take advantage of a myriad of different ISO standards:
|
25
|
+
- ISO3166 : Alpha and numeric codes for countries and subdivisions
|
26
|
+
- ISO4217 : Alpha and numeric codes for currencies
|
27
|
+
- ISO639 : Alpha and numeric codes for languages
|
28
|
+
|
29
|
+
OPTIONS
|
30
|
+
[none]
|
31
|
+
: Search for countries by the following criteria
|
32
|
+
1. country (like --country)
|
33
|
+
2. region (like --region)
|
34
|
+
3. currency (like --money)
|
35
|
+
|
36
|
+
-c/--country
|
37
|
+
: Display all countries
|
38
|
+
-c/--country [query ...]
|
39
|
+
: Search for countries by the following criteria
|
40
|
+
1. alpha2 (ISO3166 standard 2 letter code)
|
41
|
+
2. alpha3 (ISO3166 standard 3 letter code)
|
42
|
+
3. number (ISO3166 standard 3 digit code)
|
43
|
+
4. name (common, localized, unofficial)
|
44
|
+
|
45
|
+
-r/--region
|
46
|
+
: Display all countries by subregion
|
47
|
+
-r/--region [query ...]
|
48
|
+
: Search for countries by the following criteria
|
49
|
+
1. region
|
50
|
+
2. subregion
|
51
|
+
3. world region (4 letter code)
|
52
|
+
4. continent
|
53
|
+
|
54
|
+
-m/--money
|
55
|
+
: Display all countries by currency
|
56
|
+
-m/--money [query ...]
|
57
|
+
: Search for countries by the following criteria
|
58
|
+
1. code (ISO4127 standard 3 letter code)
|
59
|
+
2. name (ISO4127 standard name)
|
60
|
+
3. symbol
|
61
|
+
|
62
|
+
-h/--help
|
63
|
+
: Display this page
|
64
|
+
|
65
|
+
-v/--version
|
66
|
+
: Display the version (#{VERSION})
|
67
|
+
|
68
|
+
-d/--debug
|
69
|
+
: Display debug output
|
70
|
+
HELP
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Money < Base
|
8
|
+
def content
|
9
|
+
if search_terms.empty?
|
10
|
+
currencies = Data.all_currencies
|
11
|
+
Format.currencies(currencies)
|
12
|
+
else
|
13
|
+
search_terms.map do |term|
|
14
|
+
currencies = Data.currencies(term)
|
15
|
+
|
16
|
+
if currencies.empty?
|
17
|
+
Atlasq.failed!
|
18
|
+
"Unknown currency: #{term}"
|
19
|
+
else
|
20
|
+
Format.currencies(currencies)
|
21
|
+
end
|
22
|
+
end.join("\n\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Region < Base
|
8
|
+
def content
|
9
|
+
if search_terms.empty?
|
10
|
+
subregions = Data.all_subregions
|
11
|
+
Format.subregions(subregions)
|
12
|
+
else
|
13
|
+
search_terms.map do |term|
|
14
|
+
region = Data.region(term)
|
15
|
+
|
16
|
+
if region
|
17
|
+
Format.region(region)
|
18
|
+
else
|
19
|
+
Atlasq.failed!
|
20
|
+
"Unknown region: #{term}"
|
21
|
+
end
|
22
|
+
end.join("\n\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Usage < Base
|
8
|
+
# @return [Boolean]
|
9
|
+
def self.to_pager?
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
def content
|
15
|
+
<<~USAGE
|
16
|
+
atlasq -- a utility to query country info
|
17
|
+
|
18
|
+
usage:
|
19
|
+
atlasq query...
|
20
|
+
atlasq [command] query...
|
21
|
+
atlasq -h/--help
|
22
|
+
atlasq -v/--version
|
23
|
+
|
24
|
+
commands:
|
25
|
+
-c/--country : find countries
|
26
|
+
-r/--region : find countries by region
|
27
|
+
-m/--money : find countries by currency
|
28
|
+
USAGE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
module Command
|
7
|
+
class Version < Base
|
8
|
+
# @return [Boolean]
|
9
|
+
def self.to_pager?
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
def content
|
15
|
+
VERSION
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Command
|
5
|
+
autoload :Any, "atlasq/command/any"
|
6
|
+
autoload :Country, "atlasq/command/country"
|
7
|
+
autoload :Region, "atlasq/command/region"
|
8
|
+
autoload :Money, "atlasq/command/money"
|
9
|
+
autoload :Version, "atlasq/command/version"
|
10
|
+
autoload :Help, "atlasq/command/help"
|
11
|
+
autoload :Usage, "atlasq/command/usage"
|
12
|
+
|
13
|
+
# @param command [Atlasq::Command::Base]
|
14
|
+
# @param args [Array<String>]
|
15
|
+
Options = Struct.new(:command, :args, keyword_init: true)
|
16
|
+
|
17
|
+
def self.parse(args)
|
18
|
+
command = parse_command(args.first)
|
19
|
+
args.shift unless command.to_s == "Atlasq::Command::Any"
|
20
|
+
|
21
|
+
Options.new(command: command, args: args).freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_command(command)
|
25
|
+
case command
|
26
|
+
when "-c", "--country", "--countries"
|
27
|
+
Country
|
28
|
+
when "-r", "--region", "--regions"
|
29
|
+
Region
|
30
|
+
when "-m", "--money"
|
31
|
+
Money
|
32
|
+
when "-v", "--version"
|
33
|
+
Version
|
34
|
+
when "-h", "--help"
|
35
|
+
Help
|
36
|
+
when nil
|
37
|
+
Usage
|
38
|
+
else
|
39
|
+
Any
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Data
|
5
|
+
class Currency
|
6
|
+
# @return [String]
|
7
|
+
attr_reader :currency_code
|
8
|
+
|
9
|
+
# @return [Array<Hash>]
|
10
|
+
attr_reader :countries
|
11
|
+
|
12
|
+
# @param countries [Array<Hash>]
|
13
|
+
# @param currency_code [String] ISO4217 currency code
|
14
|
+
def initialize(countries:, currency_code:)
|
15
|
+
@countries = countries
|
16
|
+
@currency_code = currency_code
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Data
|
5
|
+
class Region
|
6
|
+
# @return [Symbol]
|
7
|
+
attr_reader :type
|
8
|
+
|
9
|
+
# @return [String, nil]
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [Array<Hash>]
|
13
|
+
attr_reader :countries
|
14
|
+
|
15
|
+
# @param countries [Array<Hash>]
|
16
|
+
# @param type [Symbol] in Atlasq::Data::REGION_TYPES
|
17
|
+
def initialize(countries:, type:)
|
18
|
+
@type = type
|
19
|
+
@name = countries.dig(0, @type.to_s)
|
20
|
+
@countries = countries
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/atlasq/data.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "countries"
|
4
|
+
require "iso-639"
|
5
|
+
require "money"
|
6
|
+
require "money-heuristics"
|
7
|
+
|
8
|
+
ISO3166.configure do |config|
|
9
|
+
# Needed to allow us to access the `ISO3166::Country#currency`
|
10
|
+
# object which ends up being an instance of `Money::Currency`.
|
11
|
+
config.enable_currency_extension!
|
12
|
+
|
13
|
+
# Needed to allow us to search by localized country name.
|
14
|
+
config.locales = %i[
|
15
|
+
af am ar as az be bg bn br bs
|
16
|
+
ca cs cy da de dz el en eo es
|
17
|
+
et eu fa fi fo fr ga gl gu he
|
18
|
+
hi hr hu hy ia id is it ja ka
|
19
|
+
kk km kn ko ku lt lv mi mk ml
|
20
|
+
mn mr ms mt nb ne nl nn oc or
|
21
|
+
pa pl ps pt ro ru rw si sk sl
|
22
|
+
so sq sr sv sw ta te th ti tk
|
23
|
+
tl tr tt ug uk ve vi wa wo xh
|
24
|
+
zh zu
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
module Atlasq
|
29
|
+
module Data
|
30
|
+
autoload :Currency, "atlasq/data/currency"
|
31
|
+
autoload :Region, "atlasq/data/region"
|
32
|
+
|
33
|
+
# @param term [String]
|
34
|
+
# @return [ISO3166::Country, Atlasq::Data::Region, Atlasq::Data::Currency, nil]
|
35
|
+
def self.any(term)
|
36
|
+
Data.country(term) ||
|
37
|
+
Data.region(term) ||
|
38
|
+
Data.currencies(term)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param term [String]
|
42
|
+
# @return [ISO3166::Country|nil]
|
43
|
+
def self.country(term)
|
44
|
+
ISO3166::Country.find_country_by_alpha2(term) ||
|
45
|
+
ISO3166::Country.find_country_by_alpha3(term) ||
|
46
|
+
ISO3166::Country.find_country_by_number(term) ||
|
47
|
+
ISO3166::Country.find_country_by_any_name(term)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Array<ISO3166::Country>]
|
51
|
+
def self.all_countries
|
52
|
+
@all_countries ||= ISO3166::Country.all
|
53
|
+
end
|
54
|
+
|
55
|
+
# Region types for querying ISO3166::Country
|
56
|
+
REGION_TYPES = %i[region subregion world_region continent].freeze
|
57
|
+
|
58
|
+
# @return [Atlasq::Data::Region|nil]
|
59
|
+
def self.region(term)
|
60
|
+
REGION_TYPES.each do |region_type|
|
61
|
+
countries = ISO3166::Country.find_all_by(region_type, term)
|
62
|
+
next if countries.empty?
|
63
|
+
|
64
|
+
return Region.new(countries: countries.values, type: region_type)
|
65
|
+
end
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Hash<String, Array<ISO3166::Country>>] Ex. { "Central Asia" => [...], ... }
|
70
|
+
def self.all_subregions
|
71
|
+
all_countries
|
72
|
+
.group_by(&:subregion)
|
73
|
+
.tap do |subregions|
|
74
|
+
# Multiple countries do not have a valid subregion so shouldn't be shown.
|
75
|
+
# (010 | AQ | ATA | Antarctica)
|
76
|
+
# (074 | BV | BVT | Bouvet Island)
|
77
|
+
# (334 | HM | HMD | Heard Island and McDonald Islands)
|
78
|
+
subregions.delete("")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param term [String]
|
83
|
+
# @return [Array<Atlasq::Data::Currency>]
|
84
|
+
def self.currencies(term)
|
85
|
+
currency_codes = Money::Currency.analyze(term)
|
86
|
+
currency_codes.filter_map do |currency_code|
|
87
|
+
countries = ISO3166::Country.find_all_by(:currency_code, currency_code)
|
88
|
+
next if countries.empty?
|
89
|
+
|
90
|
+
Currency.new(countries: countries.values, currency_code: currency_code)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Array<Atlasq::Data::Currency>]
|
95
|
+
def self.all_currencies
|
96
|
+
all_countries
|
97
|
+
.group_by(&:currency_code)
|
98
|
+
.map do |currency_code, countries|
|
99
|
+
Currency.new(countries: countries, currency_code: currency_code)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @param number [String] ISO3166-1 numeric country code
|
104
|
+
# @return [String, nil]
|
105
|
+
def self.emoji_flag(iso_number)
|
106
|
+
@emoji_flag ||= all_countries
|
107
|
+
.to_h { |country| [country.number, country.emoji_flag] }
|
108
|
+
.freeze
|
109
|
+
|
110
|
+
@emoji_flag[iso_number]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Format
|
5
|
+
# @example
|
6
|
+
# *
|
7
|
+
# * Title
|
8
|
+
# * * * * *
|
9
|
+
#
|
10
|
+
# @param title [String]
|
11
|
+
# @return [String]
|
12
|
+
def self.title(title)
|
13
|
+
[
|
14
|
+
"*",
|
15
|
+
"* #{title}",
|
16
|
+
"*#{" *" * ((title.size / 2) + 2)}"
|
17
|
+
].join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
# @example for elements [Array<String>]
|
21
|
+
# *
|
22
|
+
# * Title
|
23
|
+
# * * * * *
|
24
|
+
# (attr1 | attr2 | attr3)
|
25
|
+
# (attr1 | attr2 | attr3)
|
26
|
+
# (attr1 | attr2 | attr3)
|
27
|
+
#
|
28
|
+
# @example for elements [Hash<String, Array<String>>]
|
29
|
+
# *
|
30
|
+
# * Title
|
31
|
+
# * * * * *
|
32
|
+
# - Heading 1.0
|
33
|
+
# (attr1 | attr2 | attr3)
|
34
|
+
# (attr1 | attr2 | attr3)
|
35
|
+
# - Heading 2.0
|
36
|
+
# (attr1 | attr2 | attr3)
|
37
|
+
#
|
38
|
+
# @param title [String]
|
39
|
+
# @param elements [Array<String>, Hash<String, Array<String>>]
|
40
|
+
# @return [String]
|
41
|
+
def self.brief_template(title:, elements:)
|
42
|
+
elements =
|
43
|
+
case elements
|
44
|
+
when Array
|
45
|
+
elements.sort
|
46
|
+
when Hash
|
47
|
+
elements
|
48
|
+
.sort_by(&:first)
|
49
|
+
.each_with_object([]) do |(key, values), array|
|
50
|
+
array << "- #{key}"
|
51
|
+
values.sort.each { |value| array << " #{value}" }
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise Error, "Unknown elements type: #{elements.class}"
|
55
|
+
end
|
56
|
+
|
57
|
+
[
|
58
|
+
Format.title(title),
|
59
|
+
*elements
|
60
|
+
].join("\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
# @example
|
64
|
+
# *
|
65
|
+
# * Title
|
66
|
+
# * * * * *
|
67
|
+
# (attr1 | attr2 | attr3)
|
68
|
+
# | Info One: 1
|
69
|
+
# | Info Two: 2
|
70
|
+
# | Info Three: 3
|
71
|
+
# |________________________________________
|
72
|
+
#
|
73
|
+
# @param title [String]
|
74
|
+
# @param attributes [String]
|
75
|
+
# @param info [Hash<String, String>]
|
76
|
+
# @return [String]
|
77
|
+
def self.verbose_template(title:, attributes:, info:)
|
78
|
+
info_ladder = info.map.with_index do |(name, value), index|
|
79
|
+
"#{" " * (index + 1)}| #{name}: #{value}"
|
80
|
+
end
|
81
|
+
info_ladder << "#{" " * (info_ladder.size + 1)}|#{"_" * 40}"
|
82
|
+
|
83
|
+
[
|
84
|
+
Format.title(title),
|
85
|
+
attributes,
|
86
|
+
*info_ladder
|
87
|
+
].join("\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param value
|
91
|
+
# @param search_term [String]
|
92
|
+
# @return [String]
|
93
|
+
def self.any(value, search_term)
|
94
|
+
case value
|
95
|
+
in ISO3166::Country
|
96
|
+
Format.country(value, search_term)
|
97
|
+
in Atlasq::Data::Region
|
98
|
+
Format.region(value)
|
99
|
+
in [Atlasq::Data::Currency, *]
|
100
|
+
Format.currencies(value)
|
101
|
+
else
|
102
|
+
raise Error, "Unknown format type: #{value.class}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param country [ISO3166::Country]
|
107
|
+
# @param search_term [String]
|
108
|
+
# @return [String]
|
109
|
+
def self.country(country, search_term)
|
110
|
+
Format.verbose_template(
|
111
|
+
title: "Country: #{country.iso_long_name}",
|
112
|
+
attributes: Format.one_line_country(country),
|
113
|
+
info: {
|
114
|
+
"Search Term" => search_term,
|
115
|
+
"Languages" => Format.languages(country.languages),
|
116
|
+
"Nationality" => country.nationality,
|
117
|
+
"Region" => country.subregion,
|
118
|
+
"Continent" => country.continent,
|
119
|
+
"Currency" => "#{country.currency.symbol} #{country.currency.name}"
|
120
|
+
}.reject do |_, value|
|
121
|
+
# "countries" like Antarctica can have missing language, nationality,
|
122
|
+
# and region data so we remove that missing data beforehand.
|
123
|
+
value.nil? || value.empty?
|
124
|
+
end.to_h
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
# @example "English / Shona / Ndebele, North; North Ndebele"
|
129
|
+
# @param language_codes [Array<String>] Ex. ["id"]
|
130
|
+
# @return [String]
|
131
|
+
def self.languages(language_codes)
|
132
|
+
language_codes
|
133
|
+
.take(4) # arbitrary limit to avoid long lines
|
134
|
+
.map do |lang|
|
135
|
+
ISO_639.find(lang).english_name
|
136
|
+
end
|
137
|
+
.join(" / ")
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param countries [Array<ISO3166::Country|Hash>]
|
141
|
+
# @param title [String]
|
142
|
+
# @return [String]
|
143
|
+
def self.countries(countries, title:)
|
144
|
+
Format.brief_template(
|
145
|
+
title: title,
|
146
|
+
elements: countries.map do |country|
|
147
|
+
Format.one_line_country(country)
|
148
|
+
end
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
# @param country [ISO3166::Country|Hash]
|
153
|
+
# @return [String]
|
154
|
+
def self.one_line_country(country)
|
155
|
+
case country
|
156
|
+
when ISO3166::Country
|
157
|
+
[
|
158
|
+
country.emoji_flag,
|
159
|
+
country.number,
|
160
|
+
country.alpha2,
|
161
|
+
country.alpha3,
|
162
|
+
country.iso_short_name
|
163
|
+
]
|
164
|
+
when Hash
|
165
|
+
values = country.slice(
|
166
|
+
"number",
|
167
|
+
"alpha2",
|
168
|
+
"alpha3",
|
169
|
+
"iso_short_name"
|
170
|
+
).values
|
171
|
+
|
172
|
+
[
|
173
|
+
Data.emoji_flag(country.fetch("number")),
|
174
|
+
*values
|
175
|
+
]
|
176
|
+
else
|
177
|
+
raise Error, "Unknown country type: #{country.class}"
|
178
|
+
end.then do |country_values|
|
179
|
+
"(#{country_values.compact.join(" | ")})"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# @param region [Atlasq::Data::Region]
|
184
|
+
# @return [String]
|
185
|
+
def self.region(region)
|
186
|
+
type = Util::String.titleize(region.type)
|
187
|
+
title = "#{type}: #{region.name}"
|
188
|
+
|
189
|
+
Format.countries(region.countries, title: title)
|
190
|
+
end
|
191
|
+
|
192
|
+
# @param subregions [Hash<String, Array<ISO3166::Country>>]
|
193
|
+
# @return [String]
|
194
|
+
def self.subregions(subregions)
|
195
|
+
subregions.transform_values! do |countries|
|
196
|
+
countries.map(&Format.method(:one_line_country))
|
197
|
+
end
|
198
|
+
|
199
|
+
Format.brief_template(title: "All Subregions", elements: subregions)
|
200
|
+
end
|
201
|
+
|
202
|
+
# @param currencies [Array<Atlasq::Data::Currencies]
|
203
|
+
# @return [String]
|
204
|
+
def self.currencies(currencies)
|
205
|
+
currencies = currencies.to_h do |currency_class|
|
206
|
+
currency = Money::Currency.new(currency_class.currency_code)
|
207
|
+
|
208
|
+
[
|
209
|
+
"[#{currency.iso_code}] #{currency.symbol} #{currency.name}",
|
210
|
+
currency_class.countries.map(&Format.method(:one_line_country))
|
211
|
+
]
|
212
|
+
end
|
213
|
+
|
214
|
+
if currencies.size == 1
|
215
|
+
title, elements = currencies.first
|
216
|
+
title = "Currency: #{title}"
|
217
|
+
Format.brief_template(title: title, elements: elements)
|
218
|
+
else
|
219
|
+
Format.brief_template(title: "Currencies", elements: currencies)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
data/lib/atlasq/shell.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Shell
|
5
|
+
SKIP_PAGER = %i[usage version].freeze
|
6
|
+
|
7
|
+
def self.start!(args = ARGV)
|
8
|
+
warn "DEBUG: args: #{args}" if DEBUG
|
9
|
+
options = Command.parse(args)
|
10
|
+
warn "DEBUG: options: #{options}" if DEBUG
|
11
|
+
content = options.command.run(options.args)
|
12
|
+
|
13
|
+
if content.empty?
|
14
|
+
Atlasq.failed!
|
15
|
+
elsif use_pager?(options, content)
|
16
|
+
require "tty-pager"
|
17
|
+
TTY::Pager.page(content)
|
18
|
+
else
|
19
|
+
puts content
|
20
|
+
end
|
21
|
+
|
22
|
+
exit(1) if Atlasq.failed?
|
23
|
+
end
|
24
|
+
|
25
|
+
DEFAULT_SHELL_HEIGHT = 24
|
26
|
+
|
27
|
+
def self.use_pager?(options, content)
|
28
|
+
$stdout.tty? &&
|
29
|
+
options.command.to_pager? &&
|
30
|
+
content.count("\n") >= DEFAULT_SHELL_HEIGHT
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atlasq
|
4
|
+
module Util
|
5
|
+
module String
|
6
|
+
# @param string [#to_s]
|
7
|
+
# @return [String]
|
8
|
+
def self.titleize(string)
|
9
|
+
string
|
10
|
+
.to_s
|
11
|
+
.split(/[-_ \t]+/)
|
12
|
+
.map(&:capitalize)
|
13
|
+
.join(" ")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/atlasq/util.rb
ADDED
data/lib/atlasq.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "atlasq/version"
|
4
|
+
|
5
|
+
module Atlasq
|
6
|
+
class Error < StandardError; end
|
7
|
+
DEBUG = ENV.key?("ATLASQ_DEBUG")
|
8
|
+
|
9
|
+
autoload :Command, "atlasq/command"
|
10
|
+
autoload :Data, "atlasq/data"
|
11
|
+
autoload :Format, "atlasq/format"
|
12
|
+
autoload :Shell, "atlasq/shell"
|
13
|
+
autoload :Util, "atlasq/util"
|
14
|
+
|
15
|
+
def self.failed!
|
16
|
+
@failed = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.failed?
|
20
|
+
!!@failed
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atlasq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Robell
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: countries
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: iso-639
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: money
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.9'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: money-heuristics
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.1.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tty-pager
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.14'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.14'
|
83
|
+
description: |
|
84
|
+
Country, region, and currency info at your fingertips.
|
85
|
+
Query for regional info and see which countries show up.
|
86
|
+
email:
|
87
|
+
- apainintheneck@gmail.com
|
88
|
+
executables:
|
89
|
+
- atlasq
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- exe/atlasq
|
94
|
+
- lib/atlasq.rb
|
95
|
+
- lib/atlasq/command.rb
|
96
|
+
- lib/atlasq/command/any.rb
|
97
|
+
- lib/atlasq/command/base.rb
|
98
|
+
- lib/atlasq/command/country.rb
|
99
|
+
- lib/atlasq/command/help.rb
|
100
|
+
- lib/atlasq/command/money.rb
|
101
|
+
- lib/atlasq/command/region.rb
|
102
|
+
- lib/atlasq/command/usage.rb
|
103
|
+
- lib/atlasq/command/version.rb
|
104
|
+
- lib/atlasq/data.rb
|
105
|
+
- lib/atlasq/data/currency.rb
|
106
|
+
- lib/atlasq/data/region.rb
|
107
|
+
- lib/atlasq/format.rb
|
108
|
+
- lib/atlasq/shell.rb
|
109
|
+
- lib/atlasq/util.rb
|
110
|
+
- lib/atlasq/util/string.rb
|
111
|
+
- lib/atlasq/version.rb
|
112
|
+
homepage:
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
metadata:
|
116
|
+
homepage_uri: https://github.com/apainintheneck/atlasq/
|
117
|
+
changelog_uri: https://github.com/apainintheneck/atlasq/blob/main/CHANGELOG.md
|
118
|
+
rubygems_mfa_required: 'true'
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: 2.7.0
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubygems_version: 3.4.10
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Query for countries info at the command line.
|
138
|
+
test_files: []
|