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.
Files changed (275) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +48 -0
  3. data/.gitattributes +19 -0
  4. data/.github/dependabot.yml +12 -0
  5. data/.github/workflows/ci.yml +90 -0
  6. data/.rubocop.yml +8 -0
  7. data/.ruby-version +1 -0
  8. data/Dockerfile +69 -0
  9. data/Gemfile +68 -0
  10. data/README.md +188 -0
  11. data/Rakefile +6 -0
  12. data/app/assets/config/manifest.js +5 -0
  13. data/app/assets/images/.keep +0 -0
  14. data/app/assets/images/2024-12-30-07:58:34-screenshot.png +0 -0
  15. data/app/assets/images/facebook/facebook-logo.svg +3 -0
  16. data/app/assets/images/google/googlelogo_color_272x92dp.png +0 -0
  17. data/app/assets/images/instagram/app-store.png +0 -0
  18. data/app/assets/images/instagram/google-play.png +0 -0
  19. data/app/assets/images/instagram/instagram-logo.png +0 -0
  20. data/app/assets/images/instagram/screenshot1.png +0 -0
  21. data/app/assets/images/instagram/screenshot2.png +0 -0
  22. data/app/assets/images/instagram/screenshot3.png +0 -0
  23. data/app/assets/images/instagram/screenshot4.png +0 -0
  24. data/app/assets/images/nauta_etecsa/CUBADEBATE.jpg +0 -0
  25. data/app/assets/images/nauta_etecsa/CUBAEDUCA.jpg +0 -0
  26. data/app/assets/images/nauta_etecsa/CUBARTE.jpg +0 -0
  27. data/app/assets/images/nauta_etecsa/CUBASI.jpg +0 -0
  28. data/app/assets/images/nauta_etecsa/ECURED.jpg +0 -0
  29. data/app/assets/images/nauta_etecsa/OFERTAS.jpg +0 -0
  30. data/app/assets/images/nauta_etecsa/PAPELETA.jpg +0 -0
  31. data/app/assets/images/nauta_etecsa/contenedor_bg.jpg +0 -0
  32. data/app/assets/images/nauta_etecsa/etecsa.jpg +0 -0
  33. data/app/assets/images/nauta_etecsa/nauta_wifi.jpg +0 -0
  34. data/app/assets/images/nauta_hogar/CUBADEBATE.jpg +0 -0
  35. data/app/assets/images/nauta_hogar/CUBAEDUCA.jpg +0 -0
  36. data/app/assets/images/nauta_hogar/CUBARTE.jpg +0 -0
  37. data/app/assets/images/nauta_hogar/CUBASI.jpg +0 -0
  38. data/app/assets/images/nauta_hogar/ECURED.jpg +0 -0
  39. data/app/assets/images/nauta_hogar/OFERTAS.jpg +0 -0
  40. data/app/assets/images/nauta_hogar/PAPELETA.jpg +0 -0
  41. data/app/assets/images/nauta_hogar/banner_hogar.png +0 -0
  42. data/app/assets/images/wibrfake/Breaker-Wallpaper1.jpg +0 -0
  43. data/app/assets/images/wibrfake/mac-list-parameter.png +0 -0
  44. data/app/assets/images/wibrfake/wibrfake-100x100.png +0 -0
  45. data/app/assets/images/wibrfake/wibrfake-32x32.png +0 -0
  46. data/app/assets/images/wibrfake/wibrfake-48x48.png +0 -0
  47. data/app/assets/images/wibrfake/wibrfake-apfake-on.png +0 -0
  48. data/app/assets/images/wibrfake/wibrfake-apfake-set-basic.png +0 -0
  49. data/app/assets/images/wibrfake/wibrfake-apfake-show.png +0 -0
  50. data/app/assets/images/wibrfake/wibrfake-help.png +0 -0
  51. data/app/assets/images/wibrfake/wibrfake-hostpot.png +0 -0
  52. data/app/assets/images/wibrfake/wibrfake-init.png +0 -0
  53. data/app/assets/images/wibrfake/wibrfake-init2.png +0 -0
  54. data/app/assets/images/wibrfake/wibrfake-login-basic.jpg +0 -0
  55. data/app/assets/images/wibrfake/wibrfake-mac-list.png +0 -0
  56. data/app/assets/images/wibrfake/wibrfake-mac-ramset-oui.png +0 -0
  57. data/app/assets/images/wibrfake/wibrfake-mac-ramset.png +0 -0
  58. data/app/assets/images/wibrfake/wibrfake-mac-set.png +0 -0
  59. data/app/assets/images/wibrfake/wibrfake-mac-show.png +0 -0
  60. data/app/assets/images/wibrfake/wibrfake-need-signin.jpg +0 -0
  61. data/app/assets/images/wibrfake/wibrfake-session-active.png +0 -0
  62. data/app/assets/images/wibrfake/wibrfake-session-init.png +0 -0
  63. data/app/assets/images/wibrfake/wibrfake-session-list.png +0 -0
  64. data/app/assets/images/wibrfake/wibrfake-session-new.png +0 -0
  65. data/app/assets/images/wibrfake/wibrfake-session-rename.png +0 -0
  66. data/app/assets/images/wibrfake/wibrfake-session-save.png +0 -0
  67. data/app/assets/images/wibrfake/wibrfake-web-server-apfake.png +0 -0
  68. data/app/assets/images/wibrfake/wibrfake-web-server-on.png +0 -0
  69. data/app/assets/images/wibrfake/wibrfake-web-server-show.png +0 -0
  70. data/app/assets/images/wibrfake/wibrfake-wkdump-loaded.png +0 -0
  71. data/app/assets/images/wibrfake/wibrfake-wkdump.png +0 -0
  72. data/app/assets/images/wibrfake/wibrfake.png +0 -0
  73. data/app/assets/stylesheets/application.css +15 -0
  74. data/app/assets/stylesheets/basic/page_basic.css +0 -0
  75. data/app/assets/stylesheets/facebook/page_facebook.css +93 -0
  76. data/app/assets/stylesheets/google/page_google.css +137 -0
  77. data/app/assets/stylesheets/instagram/page_instagram.css +94 -0
  78. data/app/assets/stylesheets/nauta_etecsa/page_nauta.css +325 -0
  79. data/app/assets/stylesheets/nauta_hogar/page_nauta.css +469 -0
  80. data/app/assets/stylesheets/wibrfake/page_wibrfake.css +1181 -0
  81. data/app/assets/stylesheets/wibrfake/page_wibrfake_about.css +486 -0
  82. data/app/channels/application_cable/channel.rb +4 -0
  83. data/app/channels/application_cable/connection.rb +4 -0
  84. data/app/controllers/application_controller.rb +15 -0
  85. data/app/controllers/concerns/.keep +0 -0
  86. data/app/controllers/sessions_controller.rb +111 -0
  87. data/app/helpers/application_helper.rb +2 -0
  88. data/app/helpers/sessions_helper.rb +2 -0
  89. data/app/javascript/application.js +3 -0
  90. data/app/javascript/bootstrap.bundle.min.js +7 -0
  91. data/app/javascript/controllers/application.js +9 -0
  92. data/app/javascript/controllers/hello_controller.js +7 -0
  93. data/app/javascript/controllers/index.js +4 -0
  94. data/app/javascript/google/page_google.js +50 -0
  95. data/app/javascript/incorrect3.js +29 -0
  96. data/app/javascript/page_wibrfake.js +50 -0
  97. data/app/javascript/page_wibrfake_about.js +147 -0
  98. data/app/jobs/application_job.rb +7 -0
  99. data/app/mailers/application_mailer.rb +4 -0
  100. data/app/models/application_record.rb +3 -0
  101. data/app/models/concerns/.keep +0 -0
  102. data/app/models/user.rb +6 -0
  103. data/app/views/layouts/application.html.erb +33 -0
  104. data/app/views/layouts/mailer.html.erb +13 -0
  105. data/app/views/layouts/mailer.text.erb +1 -0
  106. data/app/views/pwa/manifest.json.erb +22 -0
  107. data/app/views/pwa/service-worker.js +26 -0
  108. data/app/views/sessions/basic/basic.html.erb +21 -0
  109. data/app/views/sessions/facebook/facebook.html.erb +132 -0
  110. data/app/views/sessions/google/google.html.erb +72 -0
  111. data/app/views/sessions/index.html.erb +11 -0
  112. data/app/views/sessions/instagram/instagram.html.erb +69 -0
  113. data/app/views/sessions/nauta_etecsa/nauta_etecsa.html.erb +97 -0
  114. data/app/views/sessions/nauta_hogar/nauta_hogar.html.erb +135 -0
  115. data/app/views/sessions/wibrfake/about/about.html.erb +164 -0
  116. data/app/views/sessions/wibrfake/wibrfake.html.erb +417 -0
  117. data/bin/.names.rb.swp +0 -0
  118. data/bin/brakeman +7 -0
  119. data/bin/bundle +114 -0
  120. data/bin/docker-entrypoint +13 -0
  121. data/bin/google.wkdump +3 -0
  122. data/bin/importmap +4 -0
  123. data/bin/rails +4 -0
  124. data/bin/rake +4 -0
  125. data/bin/rubocop +8 -0
  126. data/bin/setup +37 -0
  127. data/bin/wibrfake +20 -0
  128. data/config/application.rb +26 -0
  129. data/config/boot.rb +4 -0
  130. data/config/cable.yml +10 -0
  131. data/config/credentials.yml.enc +1 -0
  132. data/config/database.yml +16 -0
  133. data/config/environment.rb +5 -0
  134. data/config/environments/development.rb +85 -0
  135. data/config/environments/production.rb +105 -0
  136. data/config/environments/test.rb +67 -0
  137. data/config/icons/application-x-wkdump.xml +13 -0
  138. data/config/icons/hicolor/16x16/mimetypes/application-x-wkdump.png +0 -0
  139. data/config/icons/hicolor/32x32/mimetypes/application-x-wkdump.png +0 -0
  140. data/config/icons/hicolor/48x48/mimetypes/application-x-wkdump.png +0 -0
  141. data/config/icons/hicolor/icon-theme.cache +0 -0
  142. data/config/icons/hicolor/index.theme +20 -0
  143. data/config/icons/wkdump.desktop +5 -0
  144. data/config/importmap.rb +7 -0
  145. data/config/initializers/assets.rb +12 -0
  146. data/config/initializers/content_security_policy.rb +25 -0
  147. data/config/initializers/devise.rb +313 -0
  148. data/config/initializers/filter_parameter_logging.rb +8 -0
  149. data/config/initializers/inflections.rb +16 -0
  150. data/config/initializers/permissions_policy.rb +13 -0
  151. data/config/locales/devise.en.yml +65 -0
  152. data/config/locales/en.yml +31 -0
  153. data/config/puma.rb +35 -0
  154. data/config/routes.rb +12 -0
  155. data/config/storage.yml +34 -0
  156. data/config.ru +6 -0
  157. data/db/development.sqlite3 +0 -0
  158. data/db/schema.rb +14 -0
  159. data/ext/wibrfake/extconf.rb +3 -0
  160. data/ext/wibrfake/wibrfake.h +0 -0
  161. data/images/ouilist.png +0 -0
  162. data/images/wibrfakehelp.png +0 -0
  163. data/images/wibrfakeinit.png +0 -0
  164. data/lib/assets/.keep +0 -0
  165. data/lib/tasks/.keep +0 -0
  166. data/lib/wibrfake/Config/ipaddr.rb +71 -0
  167. data/lib/wibrfake/Config/options.rb +98 -0
  168. data/lib/wibrfake/Config/security_wpa.rb +43 -0
  169. data/lib/wibrfake/DataBase/howuis.db +0 -0
  170. data/lib/wibrfake/DataBase/ouis.db +0 -0
  171. data/lib/wibrfake/DataBase/ouis.rb +24 -0
  172. data/lib/wibrfake/DataBase/rename.rb +15 -0
  173. data/lib/wibrfake/DataBase/show.rb +18 -0
  174. data/lib/wibrfake/Dnsmasq/dhcp.rb +149 -0
  175. data/lib/wibrfake/Dnsmasq/dhcp_prueba.rb +135 -0
  176. data/lib/wibrfake/Dnsmasq/dns.rb +34 -0
  177. data/lib/wibrfake/Dnsmasq/dns_prueba.rb +36 -0
  178. data/lib/wibrfake/Dnsmasq/dnsmasq.rb +33 -0
  179. data/lib/wibrfake/Listing/apfake.rb +28 -0
  180. data/lib/wibrfake/Listing/clients.rb +76 -0
  181. data/lib/wibrfake/Listing/ouis.rb +53 -0
  182. data/lib/wibrfake/Listing/process.rb +14 -0
  183. data/lib/wibrfake/Listing/sessions.rb +47 -0
  184. data/lib/wibrfake/Listing/web_server.rb +17 -0
  185. data/lib/wibrfake/Listing/wireless.rb +30 -0
  186. data/lib/wibrfake/Logs/credentials.log +59 -0
  187. data/lib/wibrfake/NetworkInterface/ip-routing.rb +99 -0
  188. data/lib/wibrfake/NetworkInterface/mac.rb +114 -0
  189. data/lib/wibrfake/NetworkInterface/monitor.rb +44 -0
  190. data/lib/wibrfake/NetworkInterface/ouis.db +0 -0
  191. data/lib/wibrfake/Process/id.rb +11 -0
  192. data/lib/wibrfake/Process/pids.log +5 -0
  193. data/lib/wibrfake/Process/pkill.rb +124 -0
  194. data/lib/wibrfake/Process/processes.rb +76 -0
  195. data/lib/wibrfake/Rails/login.rb +20 -0
  196. data/lib/wibrfake/Rails/routes.rb +76 -0
  197. data/lib/wibrfake/Rails/service.rb +58 -0
  198. data/lib/wibrfake/Rails/service_usage.rb +46 -0
  199. data/lib/wibrfake/Sessions/session.rb +188 -0
  200. data/lib/wibrfake/String/string.rb +109 -0
  201. data/lib/wibrfake/Tmp/config.yml +1 -0
  202. data/lib/wibrfake/config.rb +24 -0
  203. data/lib/wibrfake/help.rb +107 -0
  204. data/lib/wibrfake/optionpr.rb +68 -0
  205. data/lib/wibrfake/run.rb +9 -0
  206. data/lib/wibrfake/ty/apld.rb +110 -0
  207. data/lib/wibrfake/ty/prompt/answers_collector.rb +78 -0
  208. data/lib/wibrfake/ty/prompt/block_paginator.rb +59 -0
  209. data/lib/wibrfake/ty/prompt/choice.rb +147 -0
  210. data/lib/wibrfake/ty/prompt/choices.rb +129 -0
  211. data/lib/wibrfake/ty/prompt/confirm_question.rb +158 -0
  212. data/lib/wibrfake/ty/prompt/const.rb +17 -0
  213. data/lib/wibrfake/ty/prompt/converter_dsl.rb +21 -0
  214. data/lib/wibrfake/ty/prompt/converter_registry.rb +69 -0
  215. data/lib/wibrfake/ty/prompt/converters.rb +182 -0
  216. data/lib/wibrfake/ty/prompt/distance.rb +49 -0
  217. data/lib/wibrfake/ty/prompt/enum_list.rb +433 -0
  218. data/lib/wibrfake/ty/prompt/errors.rb +31 -0
  219. data/lib/wibrfake/ty/prompt/evaluator.rb +29 -0
  220. data/lib/wibrfake/ty/prompt/expander.rb +321 -0
  221. data/lib/wibrfake/ty/prompt/keypress.rb +98 -0
  222. data/lib/wibrfake/ty/prompt/list.rb +589 -0
  223. data/lib/wibrfake/ty/prompt/mask_question.rb +96 -0
  224. data/lib/wibrfake/ty/prompt/multi_list.rb +224 -0
  225. data/lib/wibrfake/ty/prompt/multiline.rb +72 -0
  226. data/lib/wibrfake/ty/prompt/paginator.rb +111 -0
  227. data/lib/wibrfake/ty/prompt/question/checks.rb +105 -0
  228. data/lib/wibrfake/ty/prompt/question/modifier.rb +96 -0
  229. data/lib/wibrfake/ty/prompt/question/validation.rb +72 -0
  230. data/lib/wibrfake/ty/prompt/question.rb +391 -0
  231. data/lib/wibrfake/ty/prompt/result.rb +42 -0
  232. data/lib/wibrfake/ty/prompt/selected_choices.rb +77 -0
  233. data/lib/wibrfake/ty/prompt/slider.rb +286 -0
  234. data/lib/wibrfake/ty/prompt/statement.rb +55 -0
  235. data/lib/wibrfake/ty/prompt/suggestion.rb +113 -0
  236. data/lib/wibrfake/ty/prompt/symbols.rb +89 -0
  237. data/lib/wibrfake/ty/prompt/test.rb +36 -0
  238. data/lib/wibrfake/ty/prompt/timer.rb +75 -0
  239. data/lib/wibrfake/ty/prompt/utils.rb +42 -0
  240. data/lib/wibrfake/ty/prompt/version.rb +7 -0
  241. data/lib/wibrfake/ty/prompt.rb +589 -0
  242. data/lib/wibrfake/version.rb +5 -0
  243. data/lib/wibrfake/wibrfake_cli.rb +683 -0
  244. data/log/.keep +0 -0
  245. data/pruebas/daemon1.pid +1 -0
  246. data/pruebas/daemon2.pid +1 -0
  247. data/pruebas/daemons.rb +44 -0
  248. data/public/404.html +67 -0
  249. data/public/406-unsupported-browser.html +66 -0
  250. data/public/422.html +67 -0
  251. data/public/500.html +66 -0
  252. data/public/icon.png +0 -0
  253. data/public/icon.svg +3 -0
  254. data/public/robots.txt +1 -0
  255. data/storage/.keep +0 -0
  256. data/test/application_system_test_case.rb +5 -0
  257. data/test/channels/application_cable/connection_test.rb +13 -0
  258. data/test/controllers/.keep +0 -0
  259. data/test/controllers/sessions_controller_test.rb +7 -0
  260. data/test/fixtures/files/.keep +0 -0
  261. data/test/fixtures/users.yml +11 -0
  262. data/test/helpers/.keep +0 -0
  263. data/test/integration/.keep +0 -0
  264. data/test/mailers/.keep +0 -0
  265. data/test/models/.keep +0 -0
  266. data/test/models/user_test.rb +7 -0
  267. data/test/system/.keep +0 -0
  268. data/test/test_helper.rb +15 -0
  269. data/tmp/.keep +0 -0
  270. data/tmp/pids/.keep +0 -0
  271. data/tmp/storage/.keep +0 -0
  272. data/vendor/.keep +0 -0
  273. data/vendor/javascript/.keep +0 -0
  274. data/wibrfake.gemspec +49 -0
  275. 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