wibrfake-brk 0.0.2
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/.dockerignore +48 -0
- data/.gitattributes +19 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/ci.yml +90 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/Dockerfile +69 -0
- data/Gemfile +68 -0
- data/README.md +188 -0
- data/Rakefile +6 -0
- data/app/assets/config/manifest.js +5 -0
- data/app/assets/images/.keep +0 -0
- data/app/assets/images/2024-12-30-07:58:34-screenshot.png +0 -0
- data/app/assets/images/facebook/facebook-logo.svg +3 -0
- data/app/assets/images/google/googlelogo_color_272x92dp.png +0 -0
- data/app/assets/images/instagram/app-store.png +0 -0
- data/app/assets/images/instagram/google-play.png +0 -0
- data/app/assets/images/instagram/instagram-logo.png +0 -0
- data/app/assets/images/instagram/screenshot1.png +0 -0
- data/app/assets/images/instagram/screenshot2.png +0 -0
- data/app/assets/images/instagram/screenshot3.png +0 -0
- data/app/assets/images/instagram/screenshot4.png +0 -0
- data/app/assets/images/nauta_etecsa/CUBADEBATE.jpg +0 -0
- data/app/assets/images/nauta_etecsa/CUBAEDUCA.jpg +0 -0
- data/app/assets/images/nauta_etecsa/CUBARTE.jpg +0 -0
- data/app/assets/images/nauta_etecsa/CUBASI.jpg +0 -0
- data/app/assets/images/nauta_etecsa/ECURED.jpg +0 -0
- data/app/assets/images/nauta_etecsa/OFERTAS.jpg +0 -0
- data/app/assets/images/nauta_etecsa/PAPELETA.jpg +0 -0
- data/app/assets/images/nauta_etecsa/contenedor_bg.jpg +0 -0
- data/app/assets/images/nauta_etecsa/etecsa.jpg +0 -0
- data/app/assets/images/nauta_etecsa/nauta_wifi.jpg +0 -0
- data/app/assets/images/nauta_hogar/CUBADEBATE.jpg +0 -0
- data/app/assets/images/nauta_hogar/CUBAEDUCA.jpg +0 -0
- data/app/assets/images/nauta_hogar/CUBARTE.jpg +0 -0
- data/app/assets/images/nauta_hogar/CUBASI.jpg +0 -0
- data/app/assets/images/nauta_hogar/ECURED.jpg +0 -0
- data/app/assets/images/nauta_hogar/OFERTAS.jpg +0 -0
- data/app/assets/images/nauta_hogar/PAPELETA.jpg +0 -0
- data/app/assets/images/nauta_hogar/banner_hogar.png +0 -0
- data/app/assets/images/wibrfake/Breaker-Wallpaper1.jpg +0 -0
- data/app/assets/images/wibrfake/mac-list-parameter.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-100x100.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-32x32.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-48x48.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-apfake-on.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-apfake-set-basic.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-apfake-show.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-help.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-hostpot.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-init.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-init2.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-login-basic.jpg +0 -0
- data/app/assets/images/wibrfake/wibrfake-mac-list.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-mac-ramset-oui.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-mac-ramset.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-mac-set.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-mac-show.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-need-signin.jpg +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-active.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-init.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-list.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-new.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-rename.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-session-save.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-web-server-apfake.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-web-server-on.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-web-server-show.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-wkdump-loaded.png +0 -0
- data/app/assets/images/wibrfake/wibrfake-wkdump.png +0 -0
- data/app/assets/images/wibrfake/wibrfake.png +0 -0
- data/app/assets/stylesheets/application.css +15 -0
- data/app/assets/stylesheets/basic/page_basic.css +0 -0
- data/app/assets/stylesheets/facebook/page_facebook.css +93 -0
- data/app/assets/stylesheets/google/page_google.css +137 -0
- data/app/assets/stylesheets/instagram/page_instagram.css +94 -0
- data/app/assets/stylesheets/nauta_etecsa/page_nauta.css +325 -0
- data/app/assets/stylesheets/nauta_hogar/page_nauta.css +469 -0
- data/app/assets/stylesheets/wibrfake/page_wibrfake.css +1181 -0
- data/app/assets/stylesheets/wibrfake/page_wibrfake_about.css +486 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +4 -0
- data/app/controllers/application_controller.rb +15 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/sessions_controller.rb +111 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/sessions_helper.rb +2 -0
- data/app/javascript/application.js +3 -0
- data/app/javascript/bootstrap.bundle.min.js +7 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/hello_controller.js +7 -0
- data/app/javascript/controllers/index.js +4 -0
- data/app/javascript/google/page_google.js +50 -0
- data/app/javascript/incorrect3.js +29 -0
- data/app/javascript/page_wibrfake.js +50 -0
- data/app/javascript/page_wibrfake_about.js +147 -0
- data/app/jobs/application_job.rb +7 -0
- data/app/mailers/application_mailer.rb +4 -0
- data/app/models/application_record.rb +3 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/user.rb +6 -0
- data/app/views/layouts/application.html.erb +33 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/pwa/manifest.json.erb +22 -0
- data/app/views/pwa/service-worker.js +26 -0
- data/app/views/sessions/basic/basic.html.erb +21 -0
- data/app/views/sessions/facebook/facebook.html.erb +132 -0
- data/app/views/sessions/google/google.html.erb +72 -0
- data/app/views/sessions/index.html.erb +11 -0
- data/app/views/sessions/instagram/instagram.html.erb +69 -0
- data/app/views/sessions/nauta_etecsa/nauta_etecsa.html.erb +97 -0
- data/app/views/sessions/nauta_hogar/nauta_hogar.html.erb +135 -0
- data/app/views/sessions/wibrfake/about/about.html.erb +164 -0
- data/app/views/sessions/wibrfake/wibrfake.html.erb +417 -0
- data/bin/.names.rb.swp +0 -0
- data/bin/brakeman +7 -0
- data/bin/bundle +114 -0
- data/bin/docker-entrypoint +13 -0
- data/bin/google.wkdump +3 -0
- data/bin/importmap +4 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/bin/rubocop +8 -0
- data/bin/setup +37 -0
- data/bin/wibrfake +20 -0
- data/config/application.rb +26 -0
- data/config/boot.rb +4 -0
- data/config/cable.yml +10 -0
- data/config/credentials.yml.enc +1 -0
- data/config/database.yml +16 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +85 -0
- data/config/environments/production.rb +105 -0
- data/config/environments/test.rb +67 -0
- data/config/icons/application-x-wkdump.xml +13 -0
- data/config/icons/hicolor/16x16/mimetypes/application-x-wkdump.png +0 -0
- data/config/icons/hicolor/32x32/mimetypes/application-x-wkdump.png +0 -0
- data/config/icons/hicolor/48x48/mimetypes/application-x-wkdump.png +0 -0
- data/config/icons/hicolor/icon-theme.cache +0 -0
- data/config/icons/hicolor/index.theme +20 -0
- data/config/icons/wkdump.desktop +5 -0
- data/config/importmap.rb +7 -0
- data/config/initializers/assets.rb +12 -0
- data/config/initializers/content_security_policy.rb +25 -0
- data/config/initializers/devise.rb +313 -0
- data/config/initializers/filter_parameter_logging.rb +8 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/permissions_policy.rb +13 -0
- data/config/locales/devise.en.yml +65 -0
- data/config/locales/en.yml +31 -0
- data/config/puma.rb +35 -0
- data/config/routes.rb +12 -0
- data/config/storage.yml +34 -0
- data/config.ru +6 -0
- data/db/development.sqlite3 +0 -0
- data/db/schema.rb +14 -0
- data/ext/wibrfake/extconf.rb +3 -0
- data/ext/wibrfake/wibrfake.h +0 -0
- data/images/ouilist.png +0 -0
- data/images/wibrfakehelp.png +0 -0
- data/images/wibrfakeinit.png +0 -0
- data/lib/assets/.keep +0 -0
- data/lib/tasks/.keep +0 -0
- data/lib/wibrfake/Config/ipaddr.rb +71 -0
- data/lib/wibrfake/Config/options.rb +98 -0
- data/lib/wibrfake/Config/security_wpa.rb +43 -0
- data/lib/wibrfake/DataBase/howuis.db +0 -0
- data/lib/wibrfake/DataBase/ouis.db +0 -0
- data/lib/wibrfake/DataBase/ouis.rb +24 -0
- data/lib/wibrfake/DataBase/rename.rb +15 -0
- data/lib/wibrfake/DataBase/show.rb +18 -0
- data/lib/wibrfake/Dnsmasq/dhcp.rb +149 -0
- data/lib/wibrfake/Dnsmasq/dhcp_prueba.rb +135 -0
- data/lib/wibrfake/Dnsmasq/dns.rb +34 -0
- data/lib/wibrfake/Dnsmasq/dns_prueba.rb +36 -0
- data/lib/wibrfake/Dnsmasq/dnsmasq.rb +33 -0
- data/lib/wibrfake/Listing/apfake.rb +28 -0
- data/lib/wibrfake/Listing/clients.rb +76 -0
- data/lib/wibrfake/Listing/ouis.rb +53 -0
- data/lib/wibrfake/Listing/process.rb +14 -0
- data/lib/wibrfake/Listing/sessions.rb +47 -0
- data/lib/wibrfake/Listing/web_server.rb +17 -0
- data/lib/wibrfake/Listing/wireless.rb +30 -0
- data/lib/wibrfake/Logs/credentials.log +59 -0
- data/lib/wibrfake/NetworkInterface/ip-routing.rb +99 -0
- data/lib/wibrfake/NetworkInterface/mac.rb +114 -0
- data/lib/wibrfake/NetworkInterface/monitor.rb +44 -0
- data/lib/wibrfake/NetworkInterface/ouis.db +0 -0
- data/lib/wibrfake/Process/id.rb +11 -0
- data/lib/wibrfake/Process/pids.log +5 -0
- data/lib/wibrfake/Process/pkill.rb +124 -0
- data/lib/wibrfake/Process/processes.rb +76 -0
- data/lib/wibrfake/Rails/login.rb +20 -0
- data/lib/wibrfake/Rails/routes.rb +76 -0
- data/lib/wibrfake/Rails/service.rb +58 -0
- data/lib/wibrfake/Rails/service_usage.rb +46 -0
- data/lib/wibrfake/Sessions/session.rb +188 -0
- data/lib/wibrfake/String/string.rb +109 -0
- data/lib/wibrfake/Tmp/config.yml +1 -0
- data/lib/wibrfake/config.rb +24 -0
- data/lib/wibrfake/help.rb +107 -0
- data/lib/wibrfake/optionpr.rb +68 -0
- data/lib/wibrfake/run.rb +9 -0
- data/lib/wibrfake/ty/apld.rb +110 -0
- data/lib/wibrfake/ty/prompt/answers_collector.rb +78 -0
- data/lib/wibrfake/ty/prompt/block_paginator.rb +59 -0
- data/lib/wibrfake/ty/prompt/choice.rb +147 -0
- data/lib/wibrfake/ty/prompt/choices.rb +129 -0
- data/lib/wibrfake/ty/prompt/confirm_question.rb +158 -0
- data/lib/wibrfake/ty/prompt/const.rb +17 -0
- data/lib/wibrfake/ty/prompt/converter_dsl.rb +21 -0
- data/lib/wibrfake/ty/prompt/converter_registry.rb +69 -0
- data/lib/wibrfake/ty/prompt/converters.rb +182 -0
- data/lib/wibrfake/ty/prompt/distance.rb +49 -0
- data/lib/wibrfake/ty/prompt/enum_list.rb +433 -0
- data/lib/wibrfake/ty/prompt/errors.rb +31 -0
- data/lib/wibrfake/ty/prompt/evaluator.rb +29 -0
- data/lib/wibrfake/ty/prompt/expander.rb +321 -0
- data/lib/wibrfake/ty/prompt/keypress.rb +98 -0
- data/lib/wibrfake/ty/prompt/list.rb +589 -0
- data/lib/wibrfake/ty/prompt/mask_question.rb +96 -0
- data/lib/wibrfake/ty/prompt/multi_list.rb +224 -0
- data/lib/wibrfake/ty/prompt/multiline.rb +72 -0
- data/lib/wibrfake/ty/prompt/paginator.rb +111 -0
- data/lib/wibrfake/ty/prompt/question/checks.rb +105 -0
- data/lib/wibrfake/ty/prompt/question/modifier.rb +96 -0
- data/lib/wibrfake/ty/prompt/question/validation.rb +72 -0
- data/lib/wibrfake/ty/prompt/question.rb +391 -0
- data/lib/wibrfake/ty/prompt/result.rb +42 -0
- data/lib/wibrfake/ty/prompt/selected_choices.rb +77 -0
- data/lib/wibrfake/ty/prompt/slider.rb +286 -0
- data/lib/wibrfake/ty/prompt/statement.rb +55 -0
- data/lib/wibrfake/ty/prompt/suggestion.rb +113 -0
- data/lib/wibrfake/ty/prompt/symbols.rb +89 -0
- data/lib/wibrfake/ty/prompt/test.rb +36 -0
- data/lib/wibrfake/ty/prompt/timer.rb +75 -0
- data/lib/wibrfake/ty/prompt/utils.rb +42 -0
- data/lib/wibrfake/ty/prompt/version.rb +7 -0
- data/lib/wibrfake/ty/prompt.rb +589 -0
- data/lib/wibrfake/version.rb +5 -0
- data/lib/wibrfake/wibrfake_cli.rb +683 -0
- data/log/.keep +0 -0
- data/pruebas/daemon1.pid +1 -0
- data/pruebas/daemon2.pid +1 -0
- data/pruebas/daemons.rb +44 -0
- data/public/404.html +67 -0
- data/public/406-unsupported-browser.html +66 -0
- data/public/422.html +67 -0
- data/public/500.html +66 -0
- data/public/icon.png +0 -0
- data/public/icon.svg +3 -0
- data/public/robots.txt +1 -0
- data/storage/.keep +0 -0
- data/test/application_system_test_case.rb +5 -0
- data/test/channels/application_cable/connection_test.rb +13 -0
- data/test/controllers/.keep +0 -0
- data/test/controllers/sessions_controller_test.rb +7 -0
- data/test/fixtures/files/.keep +0 -0
- data/test/fixtures/users.yml +11 -0
- data/test/helpers/.keep +0 -0
- data/test/integration/.keep +0 -0
- data/test/mailers/.keep +0 -0
- data/test/models/.keep +0 -0
- data/test/models/user_test.rb +7 -0
- data/test/system/.keep +0 -0
- data/test/test_helper.rb +15 -0
- data/tmp/.keep +0 -0
- data/tmp/pids/.keep +0 -0
- data/tmp/storage/.keep +0 -0
- data/vendor/.keep +0 -0
- data/vendor/javascript/.keep +0 -0
- data/wibrfake.gemspec +49 -0
- metadata +743 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Prompt
|
5
|
+
# An immutable representation of a single choice option from select menu
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
class Choice
|
9
|
+
# Create choice from value
|
10
|
+
#
|
11
|
+
# @examples
|
12
|
+
# Choice.from(:foo)
|
13
|
+
# # => <TTY::Prompt::Choice @key=nil @name="foo" @value="foo" @disabled=false>
|
14
|
+
#
|
15
|
+
# Choice.from([:foo, 1])
|
16
|
+
# # => <TTY::Prompt::Choice @key=nil @name="foo" @value=1 @disabled=false>
|
17
|
+
#
|
18
|
+
# Choice.from({name: :foo, value: 1, key: "f"}
|
19
|
+
# # => <TTY::Prompt::Choice @key="f" @name="foo" @value=1 @disabled=false>
|
20
|
+
#
|
21
|
+
# @param [Object] val
|
22
|
+
# the value to be converted
|
23
|
+
#
|
24
|
+
# @raise [ArgumentError]
|
25
|
+
#
|
26
|
+
# @return [Choice]
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def self.from(val)
|
30
|
+
case val
|
31
|
+
when Choice
|
32
|
+
val
|
33
|
+
when Array
|
34
|
+
convert_array(val)
|
35
|
+
when Hash
|
36
|
+
convert_hash(val)
|
37
|
+
else
|
38
|
+
new(val, val)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Convert an array into choice
|
43
|
+
#
|
44
|
+
# @param [Array<Object>]
|
45
|
+
#
|
46
|
+
# @return [Choice]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def self.convert_array(val)
|
50
|
+
name, value, options = *val
|
51
|
+
if name.is_a?(Hash)
|
52
|
+
convert_hash(name)
|
53
|
+
elsif val.size == 1
|
54
|
+
new(name.to_s, name.to_s)
|
55
|
+
else
|
56
|
+
new(name.to_s, value, **(options || {}))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Convert a hash into choice
|
61
|
+
#
|
62
|
+
# @param [Hash<Symbol,Object>]
|
63
|
+
#
|
64
|
+
# @return [Choice]
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def self.convert_hash(val)
|
68
|
+
if val.key?(:name) && val.key?(:value)
|
69
|
+
new(val[:name].to_s, val[:value], **val)
|
70
|
+
elsif val.key?(:name)
|
71
|
+
new(val[:name].to_s, val[:name].to_s, **val)
|
72
|
+
else
|
73
|
+
new(val.keys.first.to_s, val.values.first)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# The label name
|
78
|
+
#
|
79
|
+
# @api public
|
80
|
+
attr_reader :name
|
81
|
+
|
82
|
+
# The keyboard key to activate this choice
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
attr_reader :key
|
86
|
+
|
87
|
+
# The text to display for disabled choice
|
88
|
+
#
|
89
|
+
# @api public
|
90
|
+
attr_reader :disabled
|
91
|
+
|
92
|
+
# Create a Choice instance
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
def initialize(name, value, **options)
|
96
|
+
@name = name
|
97
|
+
@value = value
|
98
|
+
@key = options[:key]
|
99
|
+
@disabled = options[:disabled].nil? ? false : options[:disabled]
|
100
|
+
freeze
|
101
|
+
end
|
102
|
+
|
103
|
+
# Check if this choice is disabled
|
104
|
+
#
|
105
|
+
# @return [Boolean]
|
106
|
+
#
|
107
|
+
# @api public
|
108
|
+
def disabled?
|
109
|
+
!!@disabled
|
110
|
+
end
|
111
|
+
|
112
|
+
# Read value and evaluate
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
def value
|
116
|
+
case @value
|
117
|
+
when Proc
|
118
|
+
@value.call
|
119
|
+
else
|
120
|
+
@value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Object equality comparison
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
127
|
+
#
|
128
|
+
# @api public
|
129
|
+
def ==(other)
|
130
|
+
return false unless other.is_a?(self.class)
|
131
|
+
|
132
|
+
name == other.name &&
|
133
|
+
value == other.value &&
|
134
|
+
key == other.key
|
135
|
+
end
|
136
|
+
|
137
|
+
# Object string representation
|
138
|
+
#
|
139
|
+
# @return [String]
|
140
|
+
#
|
141
|
+
# @api public
|
142
|
+
def to_s
|
143
|
+
name.to_s
|
144
|
+
end
|
145
|
+
end # Choice
|
146
|
+
end # Prompt
|
147
|
+
end # TTY
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
require_relative "choice"
|
6
|
+
|
7
|
+
module TTY
|
8
|
+
class Prompt
|
9
|
+
# A class responsible for storing a collection of choices
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class Choices
|
13
|
+
include Enumerable
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
def_delegators :choices, :length, :size, :to_ary, :empty?,
|
17
|
+
:values_at, :index, :==
|
18
|
+
|
19
|
+
# Convenience for creating choices
|
20
|
+
#
|
21
|
+
# @param [Array[Object]] choices
|
22
|
+
# the choice objects
|
23
|
+
#
|
24
|
+
# @return [Choices]
|
25
|
+
# the choices collection
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def self.[](*choices)
|
29
|
+
new(choices)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create Choices collection
|
33
|
+
#
|
34
|
+
# @param [Array[Choice]] choices
|
35
|
+
# the choices to add to collection
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def initialize(choices = [])
|
39
|
+
@choices = choices.map do |choice|
|
40
|
+
Choice.from(choice)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Scope of choices which are not disabled
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def enabled
|
48
|
+
reject(&:disabled?)
|
49
|
+
end
|
50
|
+
|
51
|
+
def enabled_indexes
|
52
|
+
each_with_index.reduce([]) do |acc, (choice, idx)|
|
53
|
+
acc << idx unless choice.disabled?
|
54
|
+
acc
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Iterate over all choices in the collection
|
59
|
+
#
|
60
|
+
# @yield [Choice]
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def each(&block)
|
64
|
+
return to_enum unless block_given?
|
65
|
+
|
66
|
+
choices.each(&block)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Add choice to collection
|
70
|
+
#
|
71
|
+
# @param [Object] choice
|
72
|
+
# the choice to add
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
def <<(choice)
|
76
|
+
choices << Choice.from(choice)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Access choice by index
|
80
|
+
#
|
81
|
+
# @param [Integer] index
|
82
|
+
#
|
83
|
+
# @return [Choice]
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
def [](index)
|
87
|
+
@choices[index]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Pluck a choice by its name from collection
|
91
|
+
#
|
92
|
+
# @param [String] name
|
93
|
+
# the label name for the choice
|
94
|
+
#
|
95
|
+
# @return [Choice]
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def pluck(name)
|
99
|
+
map { |choice| choice.public_send(name) }
|
100
|
+
end
|
101
|
+
|
102
|
+
# Find a matching choice
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# choices.find_by(:name, "small")
|
106
|
+
#
|
107
|
+
# @param [Symbol] attr
|
108
|
+
# the attribute name
|
109
|
+
# @param [Object] value
|
110
|
+
#
|
111
|
+
# @return [Choice]
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
def find_by(attr, value)
|
115
|
+
find { |choice| choice.public_send(attr) == value }
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
# The actual collection choices
|
121
|
+
#
|
122
|
+
# @return [Array[Choice]]
|
123
|
+
#
|
124
|
+
# @api private
|
125
|
+
|
126
|
+
attr_reader :choices
|
127
|
+
end # Choices
|
128
|
+
end # Prompt
|
129
|
+
end # TTY
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "question"
|
4
|
+
require_relative "utils"
|
5
|
+
|
6
|
+
module TTY
|
7
|
+
class Prompt
|
8
|
+
class ConfirmQuestion < Question
|
9
|
+
# Create confirmation question
|
10
|
+
#
|
11
|
+
# @param [Hash] options
|
12
|
+
# @option options [String] :suffix
|
13
|
+
# @option options [String] :positive
|
14
|
+
# @option options [String] :negative
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def initialize(prompt, **options)
|
18
|
+
super
|
19
|
+
@suffix = options.fetch(:suffix) { UndefinedSetting }
|
20
|
+
@positive = options.fetch(:positive) { UndefinedSetting }
|
21
|
+
@negative = options.fetch(:negative) { UndefinedSetting }
|
22
|
+
end
|
23
|
+
|
24
|
+
def positive?
|
25
|
+
@positive != UndefinedSetting
|
26
|
+
end
|
27
|
+
|
28
|
+
def negative?
|
29
|
+
@negative != UndefinedSetting
|
30
|
+
end
|
31
|
+
|
32
|
+
def suffix?
|
33
|
+
@suffix != UndefinedSetting
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set question suffix
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def suffix(value = (not_set = true))
|
40
|
+
return @negative if not_set
|
41
|
+
|
42
|
+
@suffix = value
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set value for matching positive choice
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def positive(value = (not_set = true))
|
49
|
+
return @positive if not_set
|
50
|
+
|
51
|
+
@positive = value
|
52
|
+
end
|
53
|
+
|
54
|
+
# Set value for matching negative choice
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def negative(value = (not_set = true))
|
58
|
+
return @negative if not_set
|
59
|
+
|
60
|
+
@negative = value
|
61
|
+
end
|
62
|
+
|
63
|
+
def call(message, &block)
|
64
|
+
return if Utils.blank?(message)
|
65
|
+
|
66
|
+
@message = message
|
67
|
+
block.call(self) if block
|
68
|
+
setup_defaults
|
69
|
+
render
|
70
|
+
end
|
71
|
+
|
72
|
+
# Render confirmation question
|
73
|
+
#
|
74
|
+
# @return [String]
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
def render_question
|
78
|
+
header = "#{@prefix}#{message} "
|
79
|
+
if !@done
|
80
|
+
header += @prompt.decorate("(#{@suffix})", @help_color) + " "
|
81
|
+
else
|
82
|
+
answer = conversion.call(@input)
|
83
|
+
label = answer ? @positive : @negative
|
84
|
+
header += @prompt.decorate(label, @active_color)
|
85
|
+
end
|
86
|
+
header << "\n" if @done
|
87
|
+
header
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
# Decide how to handle input from user
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
def process_input(question)
|
96
|
+
@input = read_input(question)
|
97
|
+
if Utils.blank?(@input)
|
98
|
+
@input = default ? positive : negative
|
99
|
+
end
|
100
|
+
@evaluator.call(@input)
|
101
|
+
end
|
102
|
+
|
103
|
+
# @api private
|
104
|
+
def setup_defaults
|
105
|
+
infer_default
|
106
|
+
@convert = conversion
|
107
|
+
return if suffix? && positive?
|
108
|
+
|
109
|
+
if suffix? && (!positive? || !negative?)
|
110
|
+
parts = @suffix.split("/")
|
111
|
+
@positive = parts[0]
|
112
|
+
@negative = parts[1]
|
113
|
+
elsif !suffix? && positive?
|
114
|
+
@suffix = create_suffix
|
115
|
+
else
|
116
|
+
create_default_labels
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# @api private
|
121
|
+
def infer_default
|
122
|
+
converted = Converters.convert(:bool, default.to_s)
|
123
|
+
if converted == Const::Undefined
|
124
|
+
raise InvalidArgument, "default needs to be `true` or `false`"
|
125
|
+
else
|
126
|
+
default(converted)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @api private
|
131
|
+
def create_default_labels
|
132
|
+
@suffix = default ? "Y/n" : "y/N"
|
133
|
+
@positive = default ? "Yes" : "yes"
|
134
|
+
@negative = default ? "no" : "No"
|
135
|
+
@validation = /^(y(es)?|no?)$/i
|
136
|
+
@messages[:valid?] = "Invalid input."
|
137
|
+
end
|
138
|
+
|
139
|
+
# @api private
|
140
|
+
def create_suffix
|
141
|
+
(default ? positive.capitalize : positive.downcase) + "/" +
|
142
|
+
(default ? negative.downcase : negative.capitalize)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Create custom conversion
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
def conversion
|
149
|
+
->(input) do
|
150
|
+
positive_word = Regexp.escape(positive)
|
151
|
+
positive_letter = Regexp.escape(positive[0])
|
152
|
+
pattern = Regexp.new("^(#{positive_word}|#{positive_letter})$", true)
|
153
|
+
!input.match(pattern).nil?
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end # ConfirmQuestion
|
157
|
+
end # Prompt
|
158
|
+
end # TTY
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Prompt
|
5
|
+
module Const
|
6
|
+
Undefined = Object.new.tap do |obj|
|
7
|
+
def obj.to_s
|
8
|
+
"undefined"
|
9
|
+
end
|
10
|
+
|
11
|
+
def obj.inspect
|
12
|
+
"undefined".inspect
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end # Const
|
16
|
+
end # Prompt
|
17
|
+
end # TTY
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "converter_registry"
|
4
|
+
|
5
|
+
module TTY
|
6
|
+
class Prompt
|
7
|
+
module ConverterDSL
|
8
|
+
def converter_registry
|
9
|
+
@__converter_registry ||= ConverterRegistry.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def converter(*names, &block)
|
13
|
+
converter_registry.register(*names, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert(name, input)
|
17
|
+
converter_registry[name].call(input)
|
18
|
+
end
|
19
|
+
end # ConverterDSL
|
20
|
+
end # Prompt
|
21
|
+
end # TTY
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module TTY
|
6
|
+
class Prompt
|
7
|
+
# Immutable collection of converters for type transformation
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class ConverterRegistry
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def_delegators "@__registry", :keys
|
14
|
+
|
15
|
+
# Create a registry of conversions
|
16
|
+
#
|
17
|
+
# @param [Hash] registry
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
def initialize(registry = {})
|
21
|
+
@__registry = registry.dup
|
22
|
+
end
|
23
|
+
|
24
|
+
# Check if conversion is available
|
25
|
+
#
|
26
|
+
# @param [String] name
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def contain?(name)
|
32
|
+
conv_name = name.to_s.downcase.to_sym
|
33
|
+
@__registry.key?(conv_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Register a conversion
|
37
|
+
#
|
38
|
+
# @param [Symbol] name
|
39
|
+
# the converter name
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def register(*names, &block)
|
43
|
+
names.each do |name|
|
44
|
+
if contain?(name)
|
45
|
+
raise ConversionAlreadyDefined,
|
46
|
+
"converter for #{name.inspect} is already registered"
|
47
|
+
end
|
48
|
+
@__registry[name] = block
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Execute converter
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def [](name)
|
56
|
+
conv_name = name.to_s.downcase.to_sym
|
57
|
+
@__registry.fetch(conv_name) do
|
58
|
+
raise UnsupportedConversion,
|
59
|
+
"converter #{conv_name.inspect} is not registered"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
alias fetch []
|
63
|
+
|
64
|
+
def inspect
|
65
|
+
@_registry.inspect
|
66
|
+
end
|
67
|
+
end # ConverterRegistry
|
68
|
+
end # Prompt
|
69
|
+
end # TTY
|