clack 0.1.4 → 0.4.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/CHANGELOG.md +76 -1
- data/README.md +184 -10
- data/examples/advanced_prompts.rb +63 -0
- data/examples/basic.rb +15 -0
- data/examples/create_app.rb +86 -0
- data/examples/date_demo.rb +40 -0
- data/examples/demo.rb +179 -0
- data/examples/full_demo.rb +84 -0
- data/examples/group_demo.rb +79 -0
- data/examples/images/confirm_example.rb +12 -0
- data/examples/images/multiselect_example.rb +15 -0
- data/examples/images/password_example.rb +10 -0
- data/examples/images/select_example.rb +15 -0
- data/examples/images/spinner_example.rb +11 -0
- data/examples/images/text_example.rb +11 -0
- data/examples/spinner_demo.rb +38 -0
- data/examples/tasks_demo.rb +59 -0
- data/examples/validation.rb +73 -0
- data/lib/clack/colors.rb +97 -3
- data/lib/clack/core/ci_mode.rb +35 -0
- data/lib/clack/core/cursor.rb +1 -0
- data/lib/clack/core/fuzzy_matcher.rb +121 -0
- data/lib/clack/core/key_reader.rb +5 -0
- data/lib/clack/core/prompt.rb +98 -20
- data/lib/clack/core/scroll_helper.rb +54 -0
- data/lib/clack/core/settings.rb +11 -3
- data/lib/clack/core/text_input_helper.rb +28 -8
- data/lib/clack/environment.rb +1 -1
- data/lib/clack/log.rb +51 -0
- data/lib/clack/note.rb +7 -0
- data/lib/clack/prompts/autocomplete.rb +27 -34
- data/lib/clack/prompts/autocomplete_multiselect.rb +23 -66
- data/lib/clack/prompts/date.rb +280 -0
- data/lib/clack/prompts/group_multiselect.rb +46 -18
- data/lib/clack/prompts/multiline_text.rb +8 -9
- data/lib/clack/prompts/multiselect.rb +3 -5
- data/lib/clack/prompts/password.rb +5 -10
- data/lib/clack/prompts/path.rb +24 -27
- data/lib/clack/prompts/progress.rb +2 -6
- data/lib/clack/prompts/range.rb +112 -0
- data/lib/clack/prompts/select.rb +2 -6
- data/lib/clack/prompts/select_key.rb +5 -8
- data/lib/clack/prompts/spinner.rb +12 -10
- data/lib/clack/prompts/tasks.rb +47 -62
- data/lib/clack/prompts/text.rb +61 -5
- data/lib/clack/stream.rb +32 -3
- data/lib/clack/symbols.rb +25 -0
- data/lib/clack/task_log.rb +3 -5
- data/lib/clack/testing.rb +171 -0
- data/lib/clack/transformers.rb +8 -7
- data/lib/clack/validators.rb +33 -2
- data/lib/clack/version.rb +2 -1
- data/lib/clack.rb +123 -215
- metadata +23 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c0622f234b9f83906c6440e54c29a12715ecfc7a2b3777ec68efaf3882defcb7
|
|
4
|
+
data.tar.gz: 450c6376c40ad88a27683294e97292f227e2081ccc90a0c076949bba3e5afd1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08a7d471122e503168817430b65ad3618488eef6a2c79229a50e20a0a3ff3f2df741faef330a81b57875ddca3a37a68d0aebd19e770b7bbe73addd9a737bc9ec'
|
|
7
|
+
data.tar.gz: 76e01f5eef142fd64069e1d9ba705edebc5694834ab68d5f7a8370eb345f1bf1473f2f1771d0178ed80e0b6c977c05d032d0059112bf36e72dd2fbe18f3850a3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.4.1] - 2026-02-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- `AutocompleteMultiselect` now renders warning validation messages (was error-only)
|
|
7
|
+
- CI mode no longer writes ANSI escape codes to non-TTY output
|
|
8
|
+
- CI mode prints a warning when validation fails instead of silently returning
|
|
9
|
+
- Spinner animation restarts from frame 0 when reused
|
|
10
|
+
- `Environment.raw_mode_supported?` catches specific exceptions instead of bare rescue
|
|
11
|
+
- `FuzzyMatcher.filter` pre-computes downcased query (performance optimization for large lists)
|
|
12
|
+
- Removed dead instance variables in Path, Testing, and Spinner
|
|
13
|
+
- Simplified `Range#clamp` by removing unreachable branch
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Updated gem dependencies (rubocop 1.84, standard 1.54, prism 1.9, bigdecimal 4.0)
|
|
17
|
+
- Autocomplete YARD docs corrected: default filter is fuzzy matching, not substring
|
|
18
|
+
- Expanded YARD `@option` documentation for spinner, multiselect, group_multiselect, path, tasks
|
|
19
|
+
- README and ARCHITECTURE.md updated to cover all v0.3.0-v0.4.0 features
|
|
20
|
+
|
|
21
|
+
## [0.4.0] - 2026-02-19
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- `range` slider prompt for numeric selection (`Clack.range(message:, min:, max:, step:, default:)`)
|
|
25
|
+
- Tab completion on `text` prompt via `completions:` parameter (array or proc)
|
|
26
|
+
- Minimum terminal width warning (non-blocking, 40 columns)
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- Path prompt caches directory listings to avoid repeated filesystem scans on every keystroke
|
|
30
|
+
|
|
31
|
+
## [0.3.0] - 2026-02-19
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `Clack::Testing` module with first-class test helpers (`simulate`, `simulate_with_output`, `PromptDriver`)
|
|
35
|
+
- `Clack::Core::FuzzyMatcher` with scored fuzzy matching (consecutive/boundary/start bonuses)
|
|
36
|
+
- CI / non-interactive mode: `Clack.update_settings(ci_mode: true)` or `:auto` to auto-detect
|
|
37
|
+
- `autocomplete_multiselect` now accepts `filter:` proc for custom matching logic
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
- Autocomplete prompts default to fuzzy matching instead of substring matching
|
|
41
|
+
- Spinner is now thread-safe: guards against double-finish, protects `@cancelled` reads with mutex
|
|
42
|
+
|
|
43
|
+
## [0.2.1] - 2026-02-19
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
- `Core::ScrollHelper` mixin extracted from scroll/filter logic across 3 prompts
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
- `TextInputHelper` parameterized via `text_value`/`text_value=` for custom backing stores
|
|
50
|
+
- Tasks prompt now reuses `Core::Spinner` instead of inline spinner implementation
|
|
51
|
+
- Removed redundant `@value = nil` from SelectKey
|
|
52
|
+
|
|
53
|
+
## [0.2.0] - 2026-02-19
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
- `date` prompt for inline segmented date selection with Tab/arrow navigation and digit typing
|
|
57
|
+
- Date min/max enforcement: clamps values to bounds during navigation
|
|
58
|
+
- Date-specific validators: `Validators.future_date`, `Validators.past_date`, `Validators.date_range`
|
|
59
|
+
- `autocomplete` now accepts `filter:` proc for custom matching logic
|
|
60
|
+
- `tasks` now passes a message-update proc to task callbacks for mid-task status updates
|
|
61
|
+
- `tasks` now supports `enabled:` flag to conditionally skip tasks
|
|
62
|
+
- 100% YARD documentation coverage (was 79%)
|
|
63
|
+
- 30 new edge-case tests covering warning validation, transforms, date boundaries, and more
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
- `Transformers.resolve` now accepts any object responding to `#call` (not just Proc)
|
|
67
|
+
- Standardized required-validation error messages across multiselect variants
|
|
68
|
+
- Extracted `dispatch_key` from `handle_key` in base `Prompt` so warning/error state transitions are handled centrally for all prompts
|
|
69
|
+
- Ruby idiom improvements: pattern matching, endless methods, guard clauses, `find_index`
|
|
70
|
+
- Gemspec now excludes dev-only files (cast, exp, gif, svg) from the gem package
|
|
71
|
+
- Examples include `require "clack"` alternative comment for gem users
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
- `Password#handle_input` now correctly handles backspace (was unreachable due to guard order)
|
|
75
|
+
- `Validators.as_warning` no longer double-wraps values that are already `Warning` instances
|
|
76
|
+
- `AutocompleteMultiselect` backspace was dead code (printable guard blocked it)
|
|
77
|
+
- `MultilineText` and `Autocomplete` now render warning validation messages (was error-only)
|
|
78
|
+
- Removed dead `@buffer` and `@name` instance variables from `TaskLogGroup`
|
|
4
79
|
|
|
5
80
|
## [0.1.4] - 2026-01-23
|
|
6
81
|
|
data/README.md
CHANGED
|
@@ -95,9 +95,16 @@ agg examples/demo.cast examples/demo.gif --font-size 18 --cols 80 --rows 28 --sp
|
|
|
95
95
|
All prompts return the user's input, or `Clack::CANCEL` if they pressed Escape/Ctrl+C.
|
|
96
96
|
|
|
97
97
|
```ruby
|
|
98
|
-
#
|
|
98
|
+
# Check for cancellation
|
|
99
99
|
result = Clack.text(message: "Name?")
|
|
100
100
|
exit 1 if Clack.cancel?(result)
|
|
101
|
+
|
|
102
|
+
# Or use handle_cancel for a one-liner that prints "Cancelled" and returns true
|
|
103
|
+
result = Clack.text(message: "Name?")
|
|
104
|
+
exit 1 if Clack.handle_cancel(result)
|
|
105
|
+
|
|
106
|
+
# With a custom message
|
|
107
|
+
exit 1 if Clack.handle_cancel(result, "Aborted by user")
|
|
101
108
|
```
|
|
102
109
|
|
|
103
110
|
### Validation & Transforms
|
|
@@ -144,15 +151,25 @@ Built-in validators and transformers:
|
|
|
144
151
|
|
|
145
152
|
```ruby
|
|
146
153
|
# Validators - return error message, Warning, or nil
|
|
147
|
-
Clack::Validators.required
|
|
148
|
-
Clack::Validators.min_length(
|
|
154
|
+
Clack::Validators.required # Non-empty input
|
|
155
|
+
Clack::Validators.min_length(3) # Minimum character count
|
|
156
|
+
Clack::Validators.max_length(100) # Maximum character count
|
|
149
157
|
Clack::Validators.format(/\A[a-z]+\z/, "Only lowercase")
|
|
150
|
-
Clack::Validators.email
|
|
151
|
-
Clack::Validators.
|
|
158
|
+
Clack::Validators.email # Email format (user@host.tld)
|
|
159
|
+
Clack::Validators.url # URL format (http/https)
|
|
160
|
+
Clack::Validators.integer # Integer string ("-5", "42")
|
|
161
|
+
Clack::Validators.in_range(1..100) # Numeric range (parses as int)
|
|
162
|
+
Clack::Validators.one_of(%w[a b c]) # Allowlist check
|
|
163
|
+
Clack::Validators.path_exists # File/dir exists on disk
|
|
164
|
+
Clack::Validators.directory_exists # Directory exists on disk
|
|
165
|
+
Clack::Validators.future_date # Date strictly after today
|
|
166
|
+
Clack::Validators.past_date # Date strictly before today
|
|
167
|
+
Clack::Validators.date_range(min: d1, max: d2) # Date within range
|
|
168
|
+
Clack::Validators.combine(v1, v2) # First error/warning wins
|
|
152
169
|
|
|
153
170
|
# Warning validators - allow user to confirm or edit
|
|
154
|
-
Clack::Validators.file_exists_warning
|
|
155
|
-
Clack::Validators.as_warning(validator)
|
|
171
|
+
Clack::Validators.file_exists_warning # For file overwrite confirmations
|
|
172
|
+
Clack::Validators.as_warning(validator) # Convert any validator to warning
|
|
156
173
|
|
|
157
174
|
# Transformers - normalize the value (use :symbol or Clack::Transformers.name)
|
|
158
175
|
:strip / :trim # Remove leading/trailing whitespace
|
|
@@ -176,7 +193,24 @@ name = Clack.text(
|
|
|
176
193
|
placeholder: "my-project", # Shown when empty (dim)
|
|
177
194
|
default_value: "untitled", # Used if submitted empty
|
|
178
195
|
initial_value: "hello-world", # Pre-filled, editable
|
|
179
|
-
validate: ->(v) { "Required!" if v.empty? }
|
|
196
|
+
validate: ->(v) { "Required!" if v.empty? },
|
|
197
|
+
help: "Letters, numbers, and dashes only" # Contextual help text
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Tab completion** - press `Tab` to cycle through matching candidates:
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
# Tab completion from a static list
|
|
205
|
+
cmd = Clack.text(
|
|
206
|
+
message: "Command?",
|
|
207
|
+
completions: %w[build test deploy lint format]
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Dynamic tab completion
|
|
211
|
+
file = Clack.text(
|
|
212
|
+
message: "File?",
|
|
213
|
+
completions: ->(input) { Dir.glob("#{input}*") }
|
|
180
214
|
)
|
|
181
215
|
```
|
|
182
216
|
|
|
@@ -191,6 +225,18 @@ secret = Clack.password(
|
|
|
191
225
|
)
|
|
192
226
|
```
|
|
193
227
|
|
|
228
|
+
### Multiline Text
|
|
229
|
+
|
|
230
|
+
Multi-line text input. Enter inserts a newline, Ctrl+D submits.
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
bio = Clack.multiline_text(
|
|
234
|
+
message: "Tell us about yourself",
|
|
235
|
+
initial_value: "Hello!\n",
|
|
236
|
+
validate: ->(v) { "Too short" if v.strip.length < 10 }
|
|
237
|
+
)
|
|
238
|
+
```
|
|
239
|
+
|
|
194
240
|
### Confirm
|
|
195
241
|
|
|
196
242
|
<img src="examples/images/confirm.svg" alt="Confirm prompt">
|
|
@@ -247,7 +293,7 @@ features = Clack.multiselect(
|
|
|
247
293
|
|
|
248
294
|
### Autocomplete
|
|
249
295
|
|
|
250
|
-
Type to filter from a list of options.
|
|
296
|
+
Type to filter from a list of options. Filtering uses **fuzzy matching** by default -- characters must appear in order but don't need to be consecutive (e.g. "fb" matches "foobar"). Pass `filter:` to override with custom logic.
|
|
251
297
|
|
|
252
298
|
```ruby
|
|
253
299
|
color = Clack.autocomplete(
|
|
@@ -255,6 +301,13 @@ color = Clack.autocomplete(
|
|
|
255
301
|
options: %w[red orange yellow green blue indigo violet],
|
|
256
302
|
placeholder: "Type to search..."
|
|
257
303
|
)
|
|
304
|
+
|
|
305
|
+
# Custom filter logic (receives option hash and query string)
|
|
306
|
+
cmd = Clack.autocomplete(
|
|
307
|
+
message: "Select command",
|
|
308
|
+
options: commands,
|
|
309
|
+
filter: ->(opt, query) { opt[:label].start_with?(query) }
|
|
310
|
+
)
|
|
258
311
|
```
|
|
259
312
|
|
|
260
313
|
### Autocomplete Multiselect
|
|
@@ -287,6 +340,37 @@ project_dir = Clack.path(
|
|
|
287
340
|
|
|
288
341
|
**Navigation:** Type to filter | `Tab` to autocomplete | `↑↓` to select
|
|
289
342
|
|
|
343
|
+
### Date
|
|
344
|
+
|
|
345
|
+
Segmented date picker with three format modes.
|
|
346
|
+
|
|
347
|
+
```ruby
|
|
348
|
+
date = Clack.date(
|
|
349
|
+
message: "Release date?",
|
|
350
|
+
format: :us, # :iso (YYYY-MM-DD), :us (MM/DD/YYYY), :eu (DD/MM/YYYY)
|
|
351
|
+
initial_value: Date.today + 7,
|
|
352
|
+
min: Date.today,
|
|
353
|
+
max: Date.today + 365,
|
|
354
|
+
validate: ->(d) { "Not a Friday" unless d.friday? }
|
|
355
|
+
)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Navigation:** `Tab`/`←→` between segments | `↑↓` adjust value | type digits directly
|
|
359
|
+
|
|
360
|
+
### Range
|
|
361
|
+
|
|
362
|
+
Numeric selection with a visual slider track. Navigate with `←→` or `↑↓` arrow keys (or `hjkl`).
|
|
363
|
+
|
|
364
|
+
```ruby
|
|
365
|
+
volume = Clack.range(
|
|
366
|
+
message: "Set volume",
|
|
367
|
+
min: 0,
|
|
368
|
+
max: 100,
|
|
369
|
+
step: 5,
|
|
370
|
+
default: 50
|
|
371
|
+
)
|
|
372
|
+
```
|
|
373
|
+
|
|
290
374
|
### Select Key
|
|
291
375
|
|
|
292
376
|
Quick selection using keyboard shortcuts.
|
|
@@ -320,6 +404,23 @@ spinner.stop("Dependencies installed!")
|
|
|
320
404
|
# Or: spinner.cancel("Cancelled")
|
|
321
405
|
```
|
|
322
406
|
|
|
407
|
+
**Block form** - wraps a block with automatic success/error handling:
|
|
408
|
+
|
|
409
|
+
```ruby
|
|
410
|
+
result = Clack.spin("Installing dependencies...") { system("npm install") }
|
|
411
|
+
|
|
412
|
+
# With custom messages
|
|
413
|
+
Clack.spin("Compiling...", success: "Build complete!") { build_project }
|
|
414
|
+
|
|
415
|
+
# Access the spinner inside the block
|
|
416
|
+
Clack.spin("Working...") do |s|
|
|
417
|
+
s.message "Step 1..."
|
|
418
|
+
do_step_1
|
|
419
|
+
s.message "Step 2..."
|
|
420
|
+
do_step_2
|
|
421
|
+
end
|
|
422
|
+
```
|
|
423
|
+
|
|
323
424
|
### Progress
|
|
324
425
|
|
|
325
426
|
Visual progress bar for measurable operations.
|
|
@@ -346,6 +447,22 @@ results = Clack.tasks(tasks: [
|
|
|
346
447
|
{ title: "Building project", task: -> { build } },
|
|
347
448
|
{ title: "Running tests", task: -> { run_tests } }
|
|
348
449
|
])
|
|
450
|
+
|
|
451
|
+
# Update the spinner message mid-task
|
|
452
|
+
Clack.tasks(tasks: [
|
|
453
|
+
{ title: "Installing", task: ->(message) {
|
|
454
|
+
message.call("Fetching packages...")
|
|
455
|
+
fetch_packages
|
|
456
|
+
message.call("Compiling...")
|
|
457
|
+
compile
|
|
458
|
+
}}
|
|
459
|
+
])
|
|
460
|
+
|
|
461
|
+
# Conditionally skip tasks with enabled:
|
|
462
|
+
Clack.tasks(tasks: [
|
|
463
|
+
{ title: "Lint", task: -> { lint } },
|
|
464
|
+
{ title: "Deploy", task: -> { deploy }, enabled: ENV["DEPLOY"] == "true" }
|
|
465
|
+
])
|
|
349
466
|
```
|
|
350
467
|
|
|
351
468
|
### Group Multiselect
|
|
@@ -370,7 +487,9 @@ features = Clack.group_multiselect(
|
|
|
370
487
|
{ value: "solid_queue", label: "Solid Queue" }
|
|
371
488
|
]
|
|
372
489
|
}
|
|
373
|
-
]
|
|
490
|
+
],
|
|
491
|
+
selectable_groups: true, # Toggle all options in a group at once
|
|
492
|
+
group_spacing: 1 # Blank lines between groups
|
|
374
493
|
)
|
|
375
494
|
```
|
|
376
495
|
|
|
@@ -485,6 +604,61 @@ Clack.outro("Done!") # └ Done!
|
|
|
485
604
|
Clack.cancel("Aborted") # └ Aborted (red)
|
|
486
605
|
```
|
|
487
606
|
|
|
607
|
+
## Configuration
|
|
608
|
+
|
|
609
|
+
Customize key bindings and display options globally:
|
|
610
|
+
|
|
611
|
+
```ruby
|
|
612
|
+
# Add custom key bindings (merged with defaults)
|
|
613
|
+
Clack.update_settings(aliases: { "y" => :enter, "n" => :cancel })
|
|
614
|
+
|
|
615
|
+
# Disable guide bars
|
|
616
|
+
Clack.update_settings(with_guide: false)
|
|
617
|
+
|
|
618
|
+
# CI / non-interactive mode (prompts auto-submit with defaults)
|
|
619
|
+
Clack.update_settings(ci_mode: true) # Always on
|
|
620
|
+
Clack.update_settings(ci_mode: :auto) # Auto-detect (non-TTY or CI env vars)
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
When CI mode is active, prompts immediately submit with their default values instead of waiting for input. Useful for CI pipelines and scripted environments where stdin is not a TTY.
|
|
624
|
+
|
|
625
|
+
Clack also warns when terminal width is below 40 columns, since prompts may not render cleanly in very narrow terminals.
|
|
626
|
+
|
|
627
|
+
## Testing
|
|
628
|
+
|
|
629
|
+
Clack ships with first-class test helpers. Require `clack/testing` explicitly (it is not auto-loaded):
|
|
630
|
+
|
|
631
|
+
```ruby
|
|
632
|
+
require "clack/testing"
|
|
633
|
+
|
|
634
|
+
# Simulate a text prompt
|
|
635
|
+
result = Clack::Testing.simulate(Clack.method(:text), message: "Name?") do |prompt|
|
|
636
|
+
prompt.type("Alice")
|
|
637
|
+
prompt.submit
|
|
638
|
+
end
|
|
639
|
+
# => "Alice"
|
|
640
|
+
|
|
641
|
+
# Capture rendered output alongside the result
|
|
642
|
+
result, output = Clack::Testing.simulate_with_output(Clack.method(:confirm), message: "Sure?") do |prompt|
|
|
643
|
+
prompt.left # switch to "No"
|
|
644
|
+
prompt.submit
|
|
645
|
+
end
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
The `PromptDriver` yielded to the block provides these methods:
|
|
649
|
+
|
|
650
|
+
| Method | Description |
|
|
651
|
+
|---|---|
|
|
652
|
+
| `type(text)` | Type a string character by character |
|
|
653
|
+
| `submit` | Press Enter |
|
|
654
|
+
| `cancel` | Press Escape |
|
|
655
|
+
| `up` / `down` / `left` / `right` | Arrow keys |
|
|
656
|
+
| `toggle` | Press Space (for multiselect) |
|
|
657
|
+
| `tab` | Press Tab |
|
|
658
|
+
| `backspace` | Press Backspace |
|
|
659
|
+
| `ctrl_d` | Press Ctrl+D (submit multiline text) |
|
|
660
|
+
| `key(sym_or_char)` | Press an arbitrary key by symbol (e.g. `:escape`) or raw character |
|
|
661
|
+
|
|
488
662
|
## Requirements
|
|
489
663
|
|
|
490
664
|
- Ruby 3.2+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Demonstrates advanced prompt types: multiline_text, path, select_key, autocomplete
|
|
5
|
+
# Run with: ruby examples/advanced_prompts.rb
|
|
6
|
+
|
|
7
|
+
require_relative "../lib/clack" # Or: require "clack" if installed as a gem
|
|
8
|
+
|
|
9
|
+
Clack.intro "advanced-prompts"
|
|
10
|
+
|
|
11
|
+
# Multi-line text with initial value (Ctrl+D to submit)
|
|
12
|
+
description = Clack.multiline_text(
|
|
13
|
+
message: "Project description:",
|
|
14
|
+
initial_value: "A Ruby CLI tool that "
|
|
15
|
+
)
|
|
16
|
+
exit 0 if Clack.cancel?(description)
|
|
17
|
+
|
|
18
|
+
Clack.log.info "Description:\n#{description}"
|
|
19
|
+
|
|
20
|
+
# Path selector (directories only, rooted at home)
|
|
21
|
+
project_dir = Clack.path(
|
|
22
|
+
message: "Choose project directory:",
|
|
23
|
+
root: Dir.home,
|
|
24
|
+
only_directories: true
|
|
25
|
+
)
|
|
26
|
+
exit 0 if Clack.cancel?(project_dir)
|
|
27
|
+
|
|
28
|
+
Clack.log.info "Directory: #{project_dir}"
|
|
29
|
+
|
|
30
|
+
# Select by key press (instant selection)
|
|
31
|
+
action = Clack.select_key(
|
|
32
|
+
message: "What next?",
|
|
33
|
+
options: [
|
|
34
|
+
{value: "init", label: "Initialize repo", key: "i", hint: "git init"},
|
|
35
|
+
{value: "clone", label: "Clone existing", key: "c", hint: "git clone"},
|
|
36
|
+
{value: "open", label: "Open in editor", key: "o"},
|
|
37
|
+
{value: "skip", label: "Skip", key: "s"}
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
exit 0 if Clack.cancel?(action)
|
|
41
|
+
|
|
42
|
+
Clack.log.step "Action: #{action}"
|
|
43
|
+
|
|
44
|
+
# Autocomplete with placeholder
|
|
45
|
+
license = Clack.autocomplete(
|
|
46
|
+
message: "Pick a license:",
|
|
47
|
+
placeholder: "Type to search...",
|
|
48
|
+
options: [
|
|
49
|
+
{value: "mit", label: "MIT", hint: "permissive"},
|
|
50
|
+
{value: "apache2", label: "Apache 2.0", hint: "permissive"},
|
|
51
|
+
{value: "gpl3", label: "GPL 3.0", hint: "copyleft"},
|
|
52
|
+
{value: "agpl3", label: "AGPL 3.0", hint: "copyleft"},
|
|
53
|
+
{value: "bsd2", label: "BSD 2-Clause", hint: "permissive"},
|
|
54
|
+
{value: "bsd3", label: "BSD 3-Clause", hint: "permissive"},
|
|
55
|
+
{value: "mpl2", label: "MPL 2.0", hint: "weak copyleft"},
|
|
56
|
+
{value: "unlicense", label: "Unlicense", hint: "public domain"}
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
exit 0 if Clack.cancel?(license)
|
|
60
|
+
|
|
61
|
+
Clack.log.success "License: #{license}"
|
|
62
|
+
|
|
63
|
+
Clack.outro "Done!"
|
data/examples/basic.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Run with: ruby examples/basic.rb
|
|
5
|
+
|
|
6
|
+
require_relative "../lib/clack" # Or: require "clack" if installed as a gem
|
|
7
|
+
|
|
8
|
+
Clack.intro "basic-example"
|
|
9
|
+
|
|
10
|
+
name = Clack.text(message: "What is your name?", placeholder: "Anonymous")
|
|
11
|
+
exit 0 if Clack.cancel?(name)
|
|
12
|
+
|
|
13
|
+
Clack.log.success "Hello, #{name}!"
|
|
14
|
+
|
|
15
|
+
Clack.outro "Goodbye!"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Run with: ruby examples/create_app.rb
|
|
5
|
+
|
|
6
|
+
require_relative "../lib/clack" # Or: require "clack" if installed as a gem
|
|
7
|
+
|
|
8
|
+
Clack.intro "create-my-app"
|
|
9
|
+
|
|
10
|
+
# Project name
|
|
11
|
+
name = Clack.text(
|
|
12
|
+
message: "Project name?",
|
|
13
|
+
placeholder: "my-app",
|
|
14
|
+
validate: ->(v) { "Project name is required" if v.to_s.strip.empty? }
|
|
15
|
+
)
|
|
16
|
+
exit 0 if Clack.cancel?(name)
|
|
17
|
+
|
|
18
|
+
# Framework selection
|
|
19
|
+
framework = Clack.select(
|
|
20
|
+
message: "Pick a framework",
|
|
21
|
+
options: [
|
|
22
|
+
{value: "rails", label: "Ruby on Rails", hint: "full-stack"},
|
|
23
|
+
{value: "sinatra", label: "Sinatra", hint: "micro"},
|
|
24
|
+
{value: "hanami", label: "Hanami"},
|
|
25
|
+
{value: "roda", label: "Roda"}
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
exit 0 if Clack.cancel?(framework)
|
|
29
|
+
|
|
30
|
+
# Feature selection
|
|
31
|
+
features = Clack.multiselect(
|
|
32
|
+
message: "Select features",
|
|
33
|
+
options: [
|
|
34
|
+
{value: "api", label: "API Mode"},
|
|
35
|
+
{value: "auth", label: "Authentication"},
|
|
36
|
+
{value: "admin", label: "Admin Panel"},
|
|
37
|
+
{value: "docker", label: "Docker Setup"},
|
|
38
|
+
{value: "ci", label: "GitHub Actions CI"}
|
|
39
|
+
],
|
|
40
|
+
required: false
|
|
41
|
+
)
|
|
42
|
+
exit 0 if Clack.cancel?(features)
|
|
43
|
+
|
|
44
|
+
# Database
|
|
45
|
+
database = Clack.select(
|
|
46
|
+
message: "Select database",
|
|
47
|
+
options: [
|
|
48
|
+
{value: "postgresql", label: "PostgreSQL", hint: "recommended"},
|
|
49
|
+
{value: "mysql", label: "MySQL"},
|
|
50
|
+
{value: "sqlite", label: "SQLite"}
|
|
51
|
+
]
|
|
52
|
+
)
|
|
53
|
+
exit 0 if Clack.cancel?(database)
|
|
54
|
+
|
|
55
|
+
# Confirm
|
|
56
|
+
proceed = Clack.confirm(message: "Create project?")
|
|
57
|
+
exit 0 if Clack.cancel?(proceed)
|
|
58
|
+
|
|
59
|
+
unless proceed
|
|
60
|
+
Clack.outro "Project creation cancelled."
|
|
61
|
+
exit 0
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Simulate installation
|
|
65
|
+
s = Clack.spinner
|
|
66
|
+
s.start "Creating project..."
|
|
67
|
+
sleep 1
|
|
68
|
+
s.message "Installing dependencies..."
|
|
69
|
+
sleep 1
|
|
70
|
+
s.message "Configuring #{framework}..."
|
|
71
|
+
sleep 0.5
|
|
72
|
+
s.stop "Project created!"
|
|
73
|
+
|
|
74
|
+
# Summary
|
|
75
|
+
Clack.log.info "Project: #{name}"
|
|
76
|
+
Clack.log.success "Framework: #{framework}"
|
|
77
|
+
Clack.log.step "Database: #{database}"
|
|
78
|
+
Clack.log.step "Features: #{features.join(", ")}" unless features.empty?
|
|
79
|
+
|
|
80
|
+
Clack.note <<~NOTE, title: "Next Steps"
|
|
81
|
+
cd #{name}
|
|
82
|
+
bundle install
|
|
83
|
+
bin/rails server
|
|
84
|
+
NOTE
|
|
85
|
+
|
|
86
|
+
Clack.outro "Happy coding!"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Run with: ruby examples/date_demo.rb
|
|
5
|
+
|
|
6
|
+
require_relative "../lib/clack" # Or: require "clack" if installed as a gem
|
|
7
|
+
|
|
8
|
+
Clack.intro "date-picker-demo"
|
|
9
|
+
|
|
10
|
+
# Basic date selection
|
|
11
|
+
date = Clack.date(
|
|
12
|
+
message: "When should this deploy?",
|
|
13
|
+
help: "Use Tab/arrows to navigate, Up/Down to adjust, or type digits"
|
|
14
|
+
)
|
|
15
|
+
exit 0 if Clack.cancel?(date)
|
|
16
|
+
|
|
17
|
+
Clack.log.info "Selected: #{date}"
|
|
18
|
+
|
|
19
|
+
# Date with bounds
|
|
20
|
+
bounded_date = Clack.date(
|
|
21
|
+
message: "Pick a date this year",
|
|
22
|
+
format: :us,
|
|
23
|
+
initial_value: Date.today,
|
|
24
|
+
min: Date.new(Date.today.year, 1, 1),
|
|
25
|
+
max: Date.new(Date.today.year, 12, 31)
|
|
26
|
+
)
|
|
27
|
+
exit 0 if Clack.cancel?(bounded_date)
|
|
28
|
+
|
|
29
|
+
Clack.log.info "Bounded date: #{bounded_date}"
|
|
30
|
+
|
|
31
|
+
# Date with custom validation
|
|
32
|
+
future_date = Clack.date(
|
|
33
|
+
message: "Schedule for future date",
|
|
34
|
+
validate: Clack::Validators.future_date
|
|
35
|
+
)
|
|
36
|
+
exit 0 if Clack.cancel?(future_date)
|
|
37
|
+
|
|
38
|
+
Clack.log.success "Scheduled for #{future_date}"
|
|
39
|
+
|
|
40
|
+
Clack.outro "Done!"
|