dry-cli-ui 0.3.0 → 0.3.1
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 +4 -4
- data/examples/Gemfile +14 -0
- data/examples/Gemfile.lock +109 -0
- data/examples/README.md +35 -0
- data/examples/bin/mycli +206 -0
- data/lib/dry/cli/ui/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 555aba61a68d2f480ae76f61d6851786e83e46afd0855c276e5eba01fe0d8dc8
|
|
4
|
+
data.tar.gz: 584e4a3268d121ecdb3e85f3ead9afef643e5c1a086b0c4702b418f550c1b8d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86e23d86e7eca50b4a7ed51bf7dc6d4a784c4711f7ddfc5c10fbc90ebc53d44647da0eaea7ea00296e7228ba73c08920a1dd08ff6c435cbd4d10f2b3266d4c37
|
|
7
|
+
data.tar.gz: 3b73f7e064fd7dfd35540a034ef1e721e4aed3e368d4d474ffa8ccc283fd4c06d4913bba72343b3760e8ecaf9ec8a64645c4d97f6c160bfb26cf7c7cb5021f30
|
data/examples/Gemfile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
group :development, :test do
|
|
6
|
+
gem 'dry-cli'
|
|
7
|
+
gem 'dry-cli-autocomplete'
|
|
8
|
+
gem 'dry-cli-help'
|
|
9
|
+
gem 'prime'
|
|
10
|
+
# multi_spinner, multi_progress and status_bar live on the
|
|
11
|
+
# kig/add-multi-spinner-progress branch until it is merged; switch this
|
|
12
|
+
# back to path: "../" then.
|
|
13
|
+
gem 'dry-cli-ui', path: File.expand_path("~/.agents.worktrees/dry-cli-ui-add-multi-spinner-progress")
|
|
14
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: /Users/kig/.agents.worktrees/dry-cli-ui-add-multi-spinner-progress
|
|
3
|
+
specs:
|
|
4
|
+
dry-cli-ui (0.3.0)
|
|
5
|
+
concurrent-ruby (~> 1.3)
|
|
6
|
+
dry-cli (>= 1.0)
|
|
7
|
+
pastel (~> 0.8)
|
|
8
|
+
strings (~> 0.2)
|
|
9
|
+
tty-box (~> 0.7)
|
|
10
|
+
tty-cursor (~> 0.7)
|
|
11
|
+
tty-progressbar (~> 0.18)
|
|
12
|
+
tty-prompt (~> 0.23)
|
|
13
|
+
tty-screen (~> 0.8)
|
|
14
|
+
tty-spinner (~> 0.9)
|
|
15
|
+
tty-table (~> 0.12)
|
|
16
|
+
|
|
17
|
+
GEM
|
|
18
|
+
remote: https://rubygems.org/
|
|
19
|
+
specs:
|
|
20
|
+
concurrent-ruby (1.3.8)
|
|
21
|
+
dry-cli (1.4.1)
|
|
22
|
+
dry-cli-autocomplete (0.1.3)
|
|
23
|
+
dry-cli (>= 1.0)
|
|
24
|
+
dry-inflector (>= 1.0)
|
|
25
|
+
dry-cli-help (0.2.0)
|
|
26
|
+
dry-cli (>= 1.1.1, < 2)
|
|
27
|
+
pastel (~> 0.8)
|
|
28
|
+
dry-inflector (1.3.1)
|
|
29
|
+
forwardable (1.4.0)
|
|
30
|
+
pastel (0.8.0)
|
|
31
|
+
tty-color (~> 0.5)
|
|
32
|
+
prime (0.1.4)
|
|
33
|
+
forwardable
|
|
34
|
+
singleton
|
|
35
|
+
singleton (0.3.0)
|
|
36
|
+
strings (0.2.1)
|
|
37
|
+
strings-ansi (~> 0.2)
|
|
38
|
+
unicode-display_width (>= 1.5, < 3.0)
|
|
39
|
+
unicode_utils (~> 1.4)
|
|
40
|
+
strings-ansi (0.2.0)
|
|
41
|
+
tty-box (0.7.0)
|
|
42
|
+
pastel (~> 0.8)
|
|
43
|
+
strings (~> 0.2.0)
|
|
44
|
+
tty-cursor (~> 0.7)
|
|
45
|
+
tty-color (0.6.0)
|
|
46
|
+
tty-cursor (0.7.1)
|
|
47
|
+
tty-progressbar (0.18.3)
|
|
48
|
+
strings-ansi (~> 0.2)
|
|
49
|
+
tty-cursor (~> 0.7)
|
|
50
|
+
tty-screen (~> 0.8)
|
|
51
|
+
unicode-display_width (>= 1.6, < 3.0)
|
|
52
|
+
tty-prompt (0.23.1)
|
|
53
|
+
pastel (~> 0.8)
|
|
54
|
+
tty-reader (~> 0.8)
|
|
55
|
+
tty-reader (0.9.0)
|
|
56
|
+
tty-cursor (~> 0.7)
|
|
57
|
+
tty-screen (~> 0.8)
|
|
58
|
+
wisper (~> 2.0)
|
|
59
|
+
tty-screen (0.8.2)
|
|
60
|
+
tty-spinner (0.9.3)
|
|
61
|
+
tty-cursor (~> 0.7)
|
|
62
|
+
tty-table (0.12.0)
|
|
63
|
+
pastel (~> 0.8)
|
|
64
|
+
strings (~> 0.2.0)
|
|
65
|
+
tty-screen (~> 0.8)
|
|
66
|
+
unicode-display_width (2.6.0)
|
|
67
|
+
unicode_utils (1.4.0)
|
|
68
|
+
wisper (2.0.1)
|
|
69
|
+
|
|
70
|
+
PLATFORMS
|
|
71
|
+
arm64-darwin-25
|
|
72
|
+
ruby
|
|
73
|
+
|
|
74
|
+
DEPENDENCIES
|
|
75
|
+
dry-cli
|
|
76
|
+
dry-cli-autocomplete
|
|
77
|
+
dry-cli-help
|
|
78
|
+
dry-cli-ui!
|
|
79
|
+
prime
|
|
80
|
+
|
|
81
|
+
CHECKSUMS
|
|
82
|
+
bundler (4.1.0.beta1) sha256=8a2dac8ca276ff4eff5efc2c6457b0044080fc1e431534ad7c5cc6187232b800
|
|
83
|
+
concurrent-ruby (1.3.8) sha256=b2f1be836e968ccc78ccfce277ea79c72a88633f22306782c16ff23fb415d1e1
|
|
84
|
+
dry-cli (1.4.1) sha256=b8015bb76c708aa8705a36faf694973e75eeeffca39b89c8e172dc6f66a7d874
|
|
85
|
+
dry-cli-autocomplete (0.1.3) sha256=14f76447bda0000c71739b585c827dc0a0a763e30a68a8b4b2dff91f640768e4
|
|
86
|
+
dry-cli-help (0.2.0)
|
|
87
|
+
dry-cli-ui (0.3.0)
|
|
88
|
+
dry-inflector (1.3.1) sha256=7fb0c2bb04f67638f25c52e7ba39ab435d922a3a5c3cd196120f63accb682dcc
|
|
89
|
+
forwardable (1.4.0) sha256=f1cd40cc9812937980e1c76f1aa053660990a7c9b6a98fc37d945468afcce838
|
|
90
|
+
pastel (0.8.0) sha256=481da9fb7d2f6e6b1a08faf11fa10363172dc40fd47848f096ae21209f805a75
|
|
91
|
+
prime (0.1.4) sha256=4d755ebf7c2994a6f3a3fee0d072063be3fff2d4042ebff6cd5eebd4747a225e
|
|
92
|
+
singleton (0.3.0) sha256=83ea1bca5f4aa34d00305ab842a7862ea5a8a11c73d362cb52379d94e9615778
|
|
93
|
+
strings (0.2.1) sha256=933293b3c95cf85b81eb44b3cf673e3087661ba739bbadfeadf442083158d6fb
|
|
94
|
+
strings-ansi (0.2.0) sha256=90262d760ea4a94cc2ae8d58205277a343409c288cbe7c29416b1826bd511c88
|
|
95
|
+
tty-box (0.7.0) sha256=17f453a0c1df43871fdb6de461ee797b78574dacc652372fa2ae98a00785df8b
|
|
96
|
+
tty-color (0.6.0) sha256=6f9c37ca3a4e2367fb2e6d09722762647d6f455c111f05b59f35730eeb24332a
|
|
97
|
+
tty-cursor (0.7.1) sha256=79534185e6a777888d88628b14b6a1fdf5154a603f285f80b1753e1908e0bf48
|
|
98
|
+
tty-progressbar (0.18.3) sha256=6cbb4260e55e74a9180d502143eb6a467d2c8e51bf5f3c9509fb5cacc3d4a5f6
|
|
99
|
+
tty-prompt (0.23.1) sha256=fcdbce905238993f27eecfdf67597a636bc839d92192f6a0eef22b8166449ec8
|
|
100
|
+
tty-reader (0.9.0) sha256=c62972c985c0b1566f0e56743b6a7882f979d3dc32ff491ed490a076f899c2b1
|
|
101
|
+
tty-screen (0.8.2) sha256=c090652115beae764336c28802d633f204fb84da93c6a968aa5d8e319e819b50
|
|
102
|
+
tty-spinner (0.9.3) sha256=0e036f047b4ffb61f2aa45f5a770ec00b4d04130531558a94bfc5b192b570542
|
|
103
|
+
tty-table (0.12.0) sha256=fdc27a4750835c1a16efe19a0b857e3ced3652cc7aceafe6dca94908965b9939
|
|
104
|
+
unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a
|
|
105
|
+
unicode_utils (1.4.0) sha256=b922d0cf2313b6b7136ada6645ce7154ffc86418ca07d53b058efe9eb72f2a40
|
|
106
|
+
wisper (2.0.1) sha256=ce17bc5c3a166f241a2e6613848b025c8146fce2defba505920c1d1f3f88fae6
|
|
107
|
+
|
|
108
|
+
BUNDLED WITH
|
|
109
|
+
4.1.0.beta1
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
These examples offers two commands that are are indicative of the added behavior.
|
|
4
|
+
|
|
5
|
+
But first,
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bundle install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then:
|
|
12
|
+
|
|
13
|
+
## Help
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
$ bundle exec bin/mycli -h
|
|
17
|
+
USAGE
|
|
18
|
+
mycli COMMAND [OPTIONS]
|
|
19
|
+
|
|
20
|
+
COMMANDS
|
|
21
|
+
version, v Print version
|
|
22
|
+
urls_progress Fetch URLs with a progress bar each, and write them all to urls.txt
|
|
23
|
+
urls_spinner Fetch URLs with a spinner each, and write each to its own file
|
|
24
|
+
primes Compute closest prime to a given number in the array
|
|
25
|
+
|
|
26
|
+
OPTIONS
|
|
27
|
+
-h, --help Show help
|
|
28
|
+
-v, --version Print version
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Commands to Try
|
|
32
|
+
|
|
33
|
+
- primes
|
|
34
|
+
- urls_progress url1 url2 ...
|
|
35
|
+
- urls_spinner url1 url2 ...
|
data/examples/bin/mycli
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Load the gems examples/Gemfile names, even when run as bin/mycli without
|
|
5
|
+
# bundle exec; otherwise Ruby picks the newest installed dry-cli-ui instead.
|
|
6
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
7
|
+
require "bundler/setup"
|
|
8
|
+
|
|
9
|
+
require "fileutils"
|
|
10
|
+
require "dry/cli"
|
|
11
|
+
require "dry/cli/help"
|
|
12
|
+
require "dry/cli/autocomplete/command"
|
|
13
|
+
require "dry/cli/ui"
|
|
14
|
+
require "net/http"
|
|
15
|
+
require "prime"
|
|
16
|
+
|
|
17
|
+
module Foo
|
|
18
|
+
module CLI
|
|
19
|
+
module Commands
|
|
20
|
+
extend Dry::CLI::Registry
|
|
21
|
+
|
|
22
|
+
class Version < Dry::CLI::Command
|
|
23
|
+
desc "Print version"
|
|
24
|
+
|
|
25
|
+
def call(*)
|
|
26
|
+
puts "1.0.0"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Shared by the two URL commands: follows redirects, and asks for the
|
|
31
|
+
# body as it is stored, so the bytes counted match Content-Length.
|
|
32
|
+
module HTTP
|
|
33
|
+
HEADERS = { "Accept-Encoding" => "identity" }.freeze
|
|
34
|
+
REDIRECTS = 5
|
|
35
|
+
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
# @return [Array(URI, Integer, nil)] where the URL ends up, and its size when the server says
|
|
39
|
+
# @raise [RuntimeError] for a response that is neither a redirect nor a success
|
|
40
|
+
def resolve(url, hops = REDIRECTS)
|
|
41
|
+
uri = URI(url)
|
|
42
|
+
response = start(uri) { |http| http.head(uri.request_uri, HEADERS) }
|
|
43
|
+
if response.is_a?(Net::HTTPRedirection) && hops.positive?
|
|
44
|
+
return resolve(URI.join(uri, response["location"]).to_s, hops - 1)
|
|
45
|
+
end
|
|
46
|
+
raise "HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
|
47
|
+
|
|
48
|
+
[uri, response.content_length]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @yieldparam bytes [Integer] the size of each chunk as it arrives
|
|
52
|
+
# @return [String] the body
|
|
53
|
+
# @raise [RuntimeError] for a response that is not a success
|
|
54
|
+
def download(uri)
|
|
55
|
+
body = +""
|
|
56
|
+
start(uri) do |http|
|
|
57
|
+
http.request_get(uri.request_uri, HEADERS) do |response|
|
|
58
|
+
raise "HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
|
59
|
+
|
|
60
|
+
response.read_body do |chunk|
|
|
61
|
+
body << chunk
|
|
62
|
+
yield chunk.bytesize if block_given?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
body
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def start(uri, &)
|
|
70
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https", open_timeout: 5, read_timeout: 10, &)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# One progress bar per URL, filling as bytes arrive, under a headline
|
|
75
|
+
# bar that counts every byte.
|
|
76
|
+
class FetchUrlsProgress < Dry::CLI::Command
|
|
77
|
+
include Dry::CLI::UI
|
|
78
|
+
|
|
79
|
+
desc "Fetch URLs with a progress bar each, and write them all to urls.txt"
|
|
80
|
+
argument :urls, type: :array, required: true, desc: "URLs to fetch, separated by spaces"
|
|
81
|
+
|
|
82
|
+
def call(urls:, **)
|
|
83
|
+
# A bar's total is fixed when it is declared, so ask each URL for its
|
|
84
|
+
# size first, with a HEAD request. A URL that fails here is left out.
|
|
85
|
+
found = urls.filter_map do |url|
|
|
86
|
+
[url, *HTTP.resolve(url)]
|
|
87
|
+
rescue StandardError => e
|
|
88
|
+
ui.status "#{url}: #{e.message}", level: :warn
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
return ui.error("None of the #{urls.size} URLs could be fetched") if found.empty?
|
|
92
|
+
|
|
93
|
+
bodies = ui.multi_progress("Fetching #{found.size} URLs", concurrent: 8) do |m|
|
|
94
|
+
found.each do |url, uri, size|
|
|
95
|
+
m.progress(url, total: size || 1) do |bar|
|
|
96
|
+
sleep rand(1..4)
|
|
97
|
+
# Move the bar one byte at a time, as each chunk arrives.
|
|
98
|
+
body = HTTP.download(uri) { |bytes| bytes.times { bar.advance } if size }
|
|
99
|
+
bar.advance unless size # no Content-Length: done in one step
|
|
100
|
+
body
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
File.write("urls.txt", bodies.join("\n"))
|
|
106
|
+
ui.success "Wrote #{bodies.sum(&:bytesize)} bytes from #{found.size} of #{urls.size} URLs to urls.txt"
|
|
107
|
+
rescue StandardError => e
|
|
108
|
+
ui.error("Fetching failed", e.message)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# One spinner per URL, each saying what it is doing, and one file per URL.
|
|
113
|
+
class FetchUrls < Dry::CLI::Command
|
|
114
|
+
include Dry::CLI::UI
|
|
115
|
+
|
|
116
|
+
desc "Fetch URLs with a spinner each, and write each to its own file"
|
|
117
|
+
argument :urls, type: :array, required: true, desc: "URLs to fetch, separated by spaces"
|
|
118
|
+
|
|
119
|
+
def call(urls:, **)
|
|
120
|
+
bodies = ui.multi_spinner("Fetching #{urls.size} URLs", concurrent: 8) do |m|
|
|
121
|
+
urls.each do |url|
|
|
122
|
+
m.spinner(url) do |line|
|
|
123
|
+
line.detail = "resolving"
|
|
124
|
+
uri, = HTTP.resolve(url)
|
|
125
|
+
line.detail = "downloading #{uri.host}"
|
|
126
|
+
sleep rand(1..4) # slow enough to watch
|
|
127
|
+
HTTP.download(uri)
|
|
128
|
+
rescue StandardError => e
|
|
129
|
+
line.fail(e.message)
|
|
130
|
+
nil
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
files = urls.zip(bodies).filter_map do |url, body|
|
|
136
|
+
next unless body
|
|
137
|
+
|
|
138
|
+
"#{friendly_filename(url)}.txt".tap { |file| File.write(file, body) }
|
|
139
|
+
end
|
|
140
|
+
ui.success "Wrote #{files.size} of #{urls.size} URLs", files.join("\n")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def friendly_filename(url)
|
|
146
|
+
url.sub(%r{\Ahttps?://}, "").gsub(/[^\w.-]+/, "_").delete_suffix("_")
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class ComputePrimes < Dry::CLI::Command
|
|
151
|
+
include Dry::CLI::UI
|
|
152
|
+
|
|
153
|
+
def self.closest_prime(n)
|
|
154
|
+
# Primes must be greater than 1
|
|
155
|
+
return 2 if n <= 2
|
|
156
|
+
return n if ::Prime.prime?(n)
|
|
157
|
+
|
|
158
|
+
distance = 1
|
|
159
|
+
loop do
|
|
160
|
+
lower = n - distance
|
|
161
|
+
upper = n + distance
|
|
162
|
+
|
|
163
|
+
primes = []
|
|
164
|
+
primes << lower if lower > 1 && ::Prime.prime?(lower)
|
|
165
|
+
primes << upper if ::Prime.prime?(upper)
|
|
166
|
+
|
|
167
|
+
# Return the prime(s) found at the shortest distance
|
|
168
|
+
return primes.size == 1 ? primes.first : primes if primes.any?
|
|
169
|
+
|
|
170
|
+
distance += 1
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
desc 'Compute closest prime to a given number in the array'
|
|
175
|
+
option :max, default: 100_000, desc: "Maximum integer to compute closest primes for", type: :integer
|
|
176
|
+
|
|
177
|
+
def call(max:)
|
|
178
|
+
ui.info "Computing closest primes..."
|
|
179
|
+
File.open('primes.txt', 'w') do |f|
|
|
180
|
+
integers = (1..max.to_i)
|
|
181
|
+
ui.progress("Computing Primes", total: integers.size) do |bar|
|
|
182
|
+
integers.each do |i|
|
|
183
|
+
p = ComputePrimes.closest_prime(i)
|
|
184
|
+
f.puts "closest prime to #{i} is #{p}"
|
|
185
|
+
bar.advance
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
ui.success("Computed #{max} primes, they are in the 'primes.txt' files.")
|
|
190
|
+
rescue StandardError => e
|
|
191
|
+
ui.error("Import failed", e.message)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
register "version", Version, aliases: ["v", "-v", "--version"]
|
|
196
|
+
register "urls_progress", FetchUrlsProgress
|
|
197
|
+
register "urls_spinner", FetchUrls
|
|
198
|
+
register "completion", ::Dry::CLI::Autocomplete::Command[::Foo::CLI::Commands], hidden: true
|
|
199
|
+
register "primes", ComputePrimes
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
Dry::CLI.new(Foo::CLI::Commands).call
|
|
205
|
+
|
|
206
|
+
FileUtils.rm_f(Dir.glob("#{File.expand_path('../', __dir__)}/*.txt"))
|
data/lib/dry/cli/ui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dry-cli-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Gredeskoul
|
|
@@ -177,6 +177,10 @@ files:
|
|
|
177
177
|
- LICENSE.txt
|
|
178
178
|
- README.md
|
|
179
179
|
- SPECIFICATION.md
|
|
180
|
+
- examples/Gemfile
|
|
181
|
+
- examples/Gemfile.lock
|
|
182
|
+
- examples/README.md
|
|
183
|
+
- examples/bin/mycli
|
|
180
184
|
- lib/dry-cli-ui.rb
|
|
181
185
|
- lib/dry/cli/ui.rb
|
|
182
186
|
- lib/dry/cli/ui/console.rb
|