inquirex-tty 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,604 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 8: Tax Preparer Intake (Realistic, Privacy-Safe)
4
+ #
5
+ # Real-world intake wizard used by tax preparers to estimate how long a
6
+ # return will take and how much phone time the client will consume. Every
7
+ # question is scoped so the answer changes the fee quote.
8
+ #
9
+ # Privacy rule: this form lives on an unsecured embeddable widget, so we
10
+ # collect NO PII — no names, no SSN / ITIN, no date of birth, no addresses,
11
+ # no account numbers. The only contact field is an email so we can send
12
+ # the quote back. Everything else is bucketed multiple choice.
13
+ #
14
+ # The flow branches on:
15
+ #
16
+ # * residency status (non-resident / dual-status multiplies the fee),
17
+ # * business ownership (entity mix, employee / contractor bands, and
18
+ # which books — P&L, Balance Sheet, GL, Trial Balance — are ready),
19
+ # * investment, crypto, rental, and foreign-earned income blocks,
20
+ # * the "surprise pile" (IRS letters, state notices) that blows up
21
+ # timelines if not flagged early.
22
+ #
23
+ # Bucketed `enum` and `multi_enum` options are used everywhere so a
24
+ # downstream pricing pass can `accumulate` fees per selected option.
25
+ #
26
+ # Run: bundle exec exe/inquirex run examples/08_tax_preparer.rb
27
+
28
+ US_STATES = %w[
29
+ AL AK AZ AR CA CO CT DE FL GA
30
+ HI ID IL IN IA KS KY LA ME MD
31
+ MA MI MN MS MO MT NE NV NH NJ
32
+ NM NY NC ND OH OK OR PA RI SC
33
+ SD TN TX UT VT VA WA WV WI WY
34
+ DC
35
+ ].freeze
36
+
37
+ Inquirex.define id: "tax-preparer-2025", version: "2.0.0" do
38
+ meta title: "Tax Preparation Intake",
39
+ subtitle: "Help us scope your return and quote you a fair fee"
40
+
41
+ start :intro
42
+
43
+ # -----------------------------------------------------------------------
44
+ # Opening
45
+ # -----------------------------------------------------------------------
46
+
47
+ say :intro do
48
+ text "Short multiple-choice scoping questions — 2 to 3 minutes.\n" \
49
+ "Please do NOT enter any personal information: no names,\n" \
50
+ "SSN, ITIN, addresses, or account numbers. We only need\n" \
51
+ "enough to quote a fee."
52
+ transition to: :residency_status
53
+ end
54
+
55
+ # -----------------------------------------------------------------------
56
+ # Scope-driving baseline (residency + prior return)
57
+ # -----------------------------------------------------------------------
58
+
59
+ ask :residency_status do
60
+ type :enum
61
+ question "Which best describes your US tax residency for 2025?"
62
+ options({
63
+ "us_person" => "US citizen or permanent resident",
64
+ "resident" => "Resident alien (substantial presence)",
65
+ "non_resident" => "Non-resident alien (1040-NR)",
66
+ "dual_status" => "Dual-status (arrived or departed this year)"
67
+ })
68
+ widget target: :tty, type: :select
69
+ widget target: :desktop, type: :radio_group, columns: 2
70
+ widget target: :mobile, type: :dropdown
71
+ transition to: :prior_return_available
72
+ end
73
+
74
+ ask :prior_return_available do
75
+ type :enum
76
+ question "Do you have a copy of your most recent tax return?"
77
+ options({
78
+ "yes_last_year" => "Yes, last year's return",
79
+ "yes_older" => "Yes, but older than last year",
80
+ "no" => "No",
81
+ "first_time" => "First return — never filed before"
82
+ })
83
+ widget target: :tty, type: :select
84
+ widget target: :desktop, type: :radio_group, columns: 2
85
+ transition to: :filing_status
86
+ end
87
+
88
+ ask :filing_status do
89
+ type :enum
90
+ question "What is your filing status for 2025?"
91
+ options({
92
+ "single" => "Single",
93
+ "married_filing_jointly" => "Married Filing Jointly",
94
+ "married_filing_separately" => "Married Filing Separately",
95
+ "head_of_household" => "Head of Household",
96
+ "widowed" => "Qualifying Widow(er)"
97
+ })
98
+ widget target: :tty, type: :select
99
+ widget target: :desktop, type: :radio_group, columns: 1
100
+ widget target: :mobile, type: :dropdown
101
+ transition to: :dependents_band
102
+ end
103
+
104
+ ask :dependents_band do
105
+ type :enum
106
+ question "How many dependents will you claim?"
107
+ options %w[0 1 2 3 4+]
108
+ widget target: :tty, type: :select
109
+ widget target: :desktop, type: :radio_group, columns: 5
110
+ widget target: :mobile, type: :dropdown
111
+ transition to: :income_types
112
+ end
113
+
114
+ # -----------------------------------------------------------------------
115
+ # Income sources
116
+ # -----------------------------------------------------------------------
117
+
118
+ ask :income_types do
119
+ type :multi_enum
120
+ question "Select every type of income you had in 2025."
121
+ options({
122
+ "W2" => "W-2 wages",
123
+ "1099_nec" => "1099-NEC (contractor)",
124
+ "1099_k" => "1099-K (payment apps, marketplaces)",
125
+ "business" => "Business income (self-employed or entity)",
126
+ "investment" => "Investment income (brokerage, dividends)",
127
+ "crypto" => "Cryptocurrency",
128
+ "rental" => "Rental property",
129
+ "retirement" => "Retirement distributions (1099-R)",
130
+ "social_sec" => "Social Security",
131
+ "gambling" => "Gambling / lottery winnings",
132
+ "foreign" => "Foreign earned income",
133
+ "home_sale" => "Sold a home or primary residence",
134
+ "inheritance" => "Inheritance or large gift received",
135
+ "none" => "None of the above"
136
+ })
137
+ widget target: :tty, type: :multi_select
138
+ widget target: :desktop, type: :checkbox_group, columns: 2
139
+ transition to: :w2_count, if_rule: contains(:income_types, "W2")
140
+ transition to: :business_entities, if_rule: contains(:income_types, "business")
141
+ transition to: :investment_details, if_rule: contains(:income_types, "investment")
142
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
143
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
144
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
145
+ transition to: :state_filing
146
+ end
147
+
148
+ ask :w2_count do
149
+ type :enum
150
+ question "How many W-2s will you report?"
151
+ options %w[1 2 3 4 5+]
152
+ widget target: :tty, type: :select
153
+ widget target: :desktop, type: :radio_group, columns: 5
154
+ transition to: :business_entities, if_rule: contains(:income_types, "business")
155
+ transition to: :investment_details, if_rule: contains(:income_types, "investment")
156
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
157
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
158
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
159
+ transition to: :state_filing
160
+ end
161
+
162
+ # -----------------------------------------------------------------------
163
+ # Business block
164
+ # -----------------------------------------------------------------------
165
+
166
+ ask :business_entities do
167
+ type :multi_enum
168
+ question "Which business entity types do you own or partner in?"
169
+ options({
170
+ "sole_prop" => "Sole Proprietor / Schedule C",
171
+ "single_llc" => "Single-member LLC",
172
+ "multi_llc" => "Multi-member LLC / Partnership",
173
+ "s_corp" => "S-Corporation",
174
+ "c_corp" => "C-Corporation",
175
+ "partnership" => "Partnership (non-LLC)",
176
+ "trust" => "Trust / Estate",
177
+ "nonprofit" => "Nonprofit / 501(c)"
178
+ })
179
+ widget target: :tty, type: :multi_select
180
+ widget target: :desktop, type: :checkbox_group, columns: 2
181
+ transition to: :business_count_band
182
+ end
183
+
184
+ ask :business_count_band do
185
+ type :enum
186
+ question "Across all entities, how many separate business returns?"
187
+ options %w[1 2-3 4-5 6+]
188
+ widget target: :tty, type: :select
189
+ widget target: :desktop, type: :radio_group, columns: 4
190
+ transition to: :books_ready
191
+ end
192
+
193
+ ask :books_ready do
194
+ type :multi_enum
195
+ question "Which of these are already prepared for the full year?"
196
+ options({
197
+ "pnl" => "Profit & Loss (Income Statement)",
198
+ "balance" => "Balance Sheet (beginning and end of year)",
199
+ "gl" => "General Ledger",
200
+ "trial" => "Trial Balance",
201
+ "bank_recs" => "Bank reconciliations",
202
+ "none" => "None / unsure"
203
+ })
204
+ widget target: :tty, type: :multi_select
205
+ widget target: :desktop, type: :checkbox_group, columns: 2
206
+ transition to: :employee_band
207
+ end
208
+
209
+ ask :employee_band do
210
+ type :enum
211
+ question "How many W-2 employees across all businesses?"
212
+ options({
213
+ "0" => "None",
214
+ "1-10" => "1-10",
215
+ "10-50" => "10-50",
216
+ "50-500" => "50-500",
217
+ "500-1000" => "500-1,000",
218
+ "1000+" => "1,000 or more"
219
+ })
220
+ widget target: :tty, type: :select
221
+ widget target: :desktop, type: :radio_group, columns: 3
222
+ widget target: :mobile, type: :dropdown
223
+ transition to: :contractor_band
224
+ end
225
+
226
+ ask :contractor_band do
227
+ type :enum
228
+ question "How many 1099 contractors paid over $600 in 2025?"
229
+ options %w[0 1-5 6-20 21-50 50+]
230
+ widget target: :tty, type: :select
231
+ widget target: :desktop, type: :radio_group, columns: 5
232
+ transition to: :ppp_eidl
233
+ end
234
+
235
+ ask :ppp_eidl do
236
+ type :multi_enum
237
+ question "Any pandemic-era loans or credits still open?"
238
+ options({
239
+ "ppp_forgiven" => "PPP (forgiven)",
240
+ "ppp_pending" => "PPP (forgiveness pending)",
241
+ "eidl" => "EIDL loan still outstanding",
242
+ "erc" => "Employee Retention Credit claimed",
243
+ "none" => "None"
244
+ })
245
+ widget target: :tty, type: :multi_select
246
+ widget target: :desktop, type: :checkbox_group, columns: 2
247
+ transition to: :fringe_benefits
248
+ end
249
+
250
+ ask :fringe_benefits do
251
+ type :multi_enum
252
+ question "Fringe benefits or business deductions to account for?"
253
+ options({
254
+ "company_car" => "Company vehicle / personal use",
255
+ "reimburse" => "Accountable-plan reimbursements",
256
+ "home_office" => "Home office",
257
+ "meals" => "Business meals / travel",
258
+ "education" => "Education / tuition assistance",
259
+ "none" => "None"
260
+ })
261
+ widget target: :tty, type: :multi_select
262
+ widget target: :desktop, type: :checkbox_group, columns: 2
263
+ transition to: :business_retirement
264
+ end
265
+
266
+ ask :business_retirement do
267
+ type :multi_enum
268
+ question "Business-side retirement plans in 2025?"
269
+ options({
270
+ "solo_401k" => "Solo 401(k)",
271
+ "sep_ira" => "SEP-IRA",
272
+ "simple_ira" => "SIMPLE IRA",
273
+ "401k" => "Traditional 401(k) plan",
274
+ "defined" => "Defined benefit / cash balance plan",
275
+ "none" => "None"
276
+ })
277
+ widget target: :tty, type: :multi_select
278
+ widget target: :desktop, type: :checkbox_group, columns: 2
279
+ transition to: :investment_details, if_rule: contains(:income_types, "investment")
280
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
281
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
282
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
283
+ transition to: :state_filing
284
+ end
285
+
286
+ # -----------------------------------------------------------------------
287
+ # Investment block
288
+ # -----------------------------------------------------------------------
289
+
290
+ ask :investment_details do
291
+ type :multi_enum
292
+ question "What types of investments did you hold?"
293
+ options({
294
+ "brokerage" => "Taxable brokerage (stocks, ETFs)",
295
+ "options" => "Options / derivatives",
296
+ "private" => "Private equity / angel / K-1s",
297
+ "real_estate" => "REITs",
298
+ "hsa" => "HSA",
299
+ "529" => "529 plan"
300
+ })
301
+ widget target: :tty, type: :multi_select
302
+ widget target: :desktop, type: :checkbox_group, columns: 2
303
+ transition to: :brokerage_count, if_rule: contains(:investment_details, "brokerage")
304
+ transition to: :k1_count, if_rule: contains(:investment_details, "private")
305
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
306
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
307
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
308
+ transition to: :state_filing
309
+ end
310
+
311
+ ask :brokerage_count do
312
+ type :enum
313
+ question "How many brokerage 1099-B statements will you receive?"
314
+ options %w[1 2 3 4-5 6+]
315
+ widget target: :tty, type: :select
316
+ widget target: :desktop, type: :radio_group, columns: 5
317
+ transition to: :k1_count, if_rule: contains(:investment_details, "private")
318
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
319
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
320
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
321
+ transition to: :state_filing
322
+ end
323
+
324
+ ask :k1_count do
325
+ type :enum
326
+ question "How many K-1s will you receive?"
327
+ options %w[1 2-3 4-6 7-10 10+]
328
+ widget target: :tty, type: :select
329
+ widget target: :desktop, type: :radio_group, columns: 5
330
+ transition to: :crypto_volume, if_rule: contains(:income_types, "crypto")
331
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
332
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
333
+ transition to: :state_filing
334
+ end
335
+
336
+ # -----------------------------------------------------------------------
337
+ # Crypto block
338
+ # -----------------------------------------------------------------------
339
+
340
+ ask :crypto_volume do
341
+ type :enum
342
+ question "Roughly how many crypto transactions in 2025?"
343
+ options({
344
+ "0-10" => "Fewer than 10",
345
+ "10-100" => "10-100",
346
+ "100-1000" => "100-1,000",
347
+ "1000-10000" => "1,000-10,000",
348
+ "10000+" => "More than 10,000"
349
+ })
350
+ widget target: :tty, type: :select
351
+ widget target: :desktop, type: :radio_group, columns: 5
352
+ transition to: :crypto_activity
353
+ end
354
+
355
+ ask :crypto_activity do
356
+ type :multi_enum
357
+ question "Which crypto activities apply?"
358
+ options({
359
+ "trading" => "Buying / selling",
360
+ "staking" => "Staking rewards",
361
+ "mining" => "Mining",
362
+ "nfts" => "NFTs",
363
+ "defi" => "DeFi (lending, LP, yield)",
364
+ "airdrops" => "Airdrops / forks",
365
+ "payments" => "Received crypto as payment"
366
+ })
367
+ widget target: :tty, type: :multi_select
368
+ widget target: :desktop, type: :checkbox_group, columns: 2
369
+ transition to: :crypto_report_ready
370
+ end
371
+
372
+ ask :crypto_report_ready do
373
+ type :boolean
374
+ question "Do you already have a CoinTracker / Koinly / TokenTax " \
375
+ "tax report covering 2025?"
376
+ widget target: :tty, type: :yes_no
377
+ widget target: :desktop, type: :yes_no_buttons
378
+ transition to: :rental_count, if_rule: contains(:income_types, "rental")
379
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
380
+ transition to: :state_filing
381
+ end
382
+
383
+ # -----------------------------------------------------------------------
384
+ # Rental block
385
+ # -----------------------------------------------------------------------
386
+
387
+ ask :rental_count do
388
+ type :enum
389
+ question "How many rental properties do you own?"
390
+ options %w[1 2-3 4-6 7-10 10+]
391
+ widget target: :tty, type: :select
392
+ widget target: :desktop, type: :radio_group, columns: 5
393
+ transition to: :rental_types
394
+ end
395
+
396
+ ask :rental_types do
397
+ type :multi_enum
398
+ question "What types of rental properties?"
399
+ options({
400
+ "residential_long" => "Residential long-term",
401
+ "short_term" => "Short-term (Airbnb / VRBO)",
402
+ "commercial" => "Commercial",
403
+ "vacation" => "Vacation / mixed personal use",
404
+ "foreign_rental" => "Foreign rental"
405
+ })
406
+ widget target: :tty, type: :multi_select
407
+ widget target: :desktop, type: :checkbox_group, columns: 2
408
+ transition to: :foreign_earned, if_rule: contains(:income_types, "foreign")
409
+ transition to: :state_filing
410
+ end
411
+
412
+ # -----------------------------------------------------------------------
413
+ # Foreign earned income block
414
+ # -----------------------------------------------------------------------
415
+
416
+ ask :foreign_earned do
417
+ type :multi_enum
418
+ question "What foreign income situation applies?"
419
+ options({
420
+ "worked_abroad" => "Worked abroad during 2025",
421
+ "foreign_employer" => "Paid by a foreign employer",
422
+ "foreign_self" => "Self-employed abroad",
423
+ "us_expat" => "US citizen living abroad",
424
+ "treaty" => "Tax treaty benefits expected"
425
+ })
426
+ widget target: :tty, type: :multi_select
427
+ widget target: :desktop, type: :checkbox_group, columns: 2
428
+ transition to: :state_filing
429
+ end
430
+
431
+ # -----------------------------------------------------------------------
432
+ # State filing (all 50 + DC, rendered as a grid)
433
+ # -----------------------------------------------------------------------
434
+
435
+ ask :state_filing do
436
+ type :multi_enum
437
+ question "Select every state (and DC) you need to file a return in."
438
+ options US_STATES
439
+ widget target: :tty, type: :multi_select
440
+ widget target: :desktop, type: :checkbox_group, columns: 10, layout: :grid
441
+ widget target: :mobile, type: :multi_select_dropdown
442
+ transition to: :state_residency
443
+ end
444
+
445
+ ask :state_residency do
446
+ type :enum
447
+ question "Were you a resident of more than one state during 2025?"
448
+ options({
449
+ "no" => "No, one state all year",
450
+ "part_year" => "Yes, part-year resident",
451
+ "multi" => "Yes, multiple states",
452
+ "non_resident" => "No, but earned income in another state"
453
+ })
454
+ widget target: :tty, type: :select
455
+ widget target: :desktop, type: :radio_group, columns: 2
456
+ transition to: :foreign_accounts
457
+ end
458
+
459
+ # -----------------------------------------------------------------------
460
+ # Foreign accounts (FBAR / Form 8938 scope trigger)
461
+ # -----------------------------------------------------------------------
462
+
463
+ ask :foreign_accounts do
464
+ type :enum
465
+ question "Did you hold foreign financial accounts in 2025?"
466
+ options({
467
+ "no" => "No",
468
+ "under10k" => "Yes, aggregate always under $10,000",
469
+ "over10k" => "Yes, aggregate exceeded $10,000",
470
+ "unsure" => "Not sure"
471
+ })
472
+ widget target: :tty, type: :select
473
+ widget target: :desktop, type: :radio_group, columns: 2
474
+ transition to: :foreign_account_count, if_rule: equals(:foreign_accounts, "over10k")
475
+ transition to: :foreign_account_count, if_rule: equals(:foreign_accounts, "unsure")
476
+ transition to: :surprise_heads_up
477
+ end
478
+
479
+ ask :foreign_account_count do
480
+ type :enum
481
+ question "How many foreign accounts?"
482
+ options %w[1 2-3 4-10 10+]
483
+ widget target: :tty, type: :select
484
+ widget target: :desktop, type: :radio_group, columns: 4
485
+ transition to: :surprise_heads_up
486
+ end
487
+
488
+ # -----------------------------------------------------------------------
489
+ # "Surprise pile" — late-arriving items that blow up timelines
490
+ # -----------------------------------------------------------------------
491
+
492
+ warning :surprise_heads_up do
493
+ text "Last stretch: items that commonly arrive late and add billable\n" \
494
+ "hours. Flagging them now keeps our quote accurate."
495
+ transition to: :tax_notices
496
+ end
497
+
498
+ ask :tax_notices do
499
+ type :multi_enum
500
+ question "Any outstanding tax notices we should know about?"
501
+ options({
502
+ "irs_cp2000" => "IRS CP2000 (underreported income)",
503
+ "irs_balance" => "IRS balance-due notice",
504
+ "irs_audit" => "IRS audit or examination",
505
+ "irs_identity" => "IRS identity verification",
506
+ "irs_lien_levy" => "IRS lien or levy",
507
+ "state_notice" => "State or local tax notice",
508
+ "none" => "None"
509
+ })
510
+ widget target: :tty, type: :multi_select
511
+ widget target: :desktop, type: :checkbox_group, columns: 2
512
+ transition to: :estimated_payments
513
+ end
514
+
515
+ ask :estimated_payments do
516
+ type :enum
517
+ question "Did you make 2025 federal estimated tax payments?"
518
+ options({
519
+ "all_four" => "Yes, all four quarters",
520
+ "some" => "Yes, some quarters",
521
+ "none" => "No",
522
+ "refund" => "No — applied prior-year refund instead",
523
+ "unsure" => "Not sure"
524
+ })
525
+ widget target: :tty, type: :select
526
+ widget target: :desktop, type: :radio_group, columns: 2
527
+ transition to: :deduction_types
528
+ end
529
+
530
+ # -----------------------------------------------------------------------
531
+ # Deductions & credits
532
+ # -----------------------------------------------------------------------
533
+
534
+ ask :deduction_types do
535
+ type :multi_enum
536
+ question "Which deductions or credits apply?"
537
+ options({
538
+ "mortgage" => "Mortgage interest",
539
+ "salt" => "State & local taxes (SALT)",
540
+ "medical" => "Major medical expenses",
541
+ "charitable" => "Charitable contributions",
542
+ "education" => "Education credits / student loan interest",
543
+ "energy" => "Energy / EV credits",
544
+ "childcare" => "Childcare expenses",
545
+ "hsa_fsa" => "HSA / FSA contributions",
546
+ "none" => "None / standard deduction"
547
+ })
548
+ widget target: :tty, type: :multi_select
549
+ widget target: :desktop, type: :checkbox_group, columns: 2
550
+ transition to: :charitable_band, if_rule: contains(:deduction_types, "charitable")
551
+ transition to: :timeline
552
+ end
553
+
554
+ ask :charitable_band do
555
+ type :enum
556
+ question "Roughly how much in charitable contributions?"
557
+ options({
558
+ "under1k" => "Under $1,000",
559
+ "1k-5k" => "$1,000 - $5,000",
560
+ "5k-25k" => "$5,000 - $25,000",
561
+ "25k-100k" => "$25,000 - $100,000",
562
+ "over100k" => "Over $100,000",
563
+ "non_cash" => "Includes non-cash donations"
564
+ })
565
+ widget target: :tty, type: :select
566
+ widget target: :desktop, type: :radio_group, columns: 3
567
+ transition to: :timeline
568
+ end
569
+
570
+ # -----------------------------------------------------------------------
571
+ # Timing (affects rush pricing)
572
+ # -----------------------------------------------------------------------
573
+
574
+ ask :timeline do
575
+ type :enum
576
+ question "How soon do you need this return filed?"
577
+ options({
578
+ "asap" => "As soon as possible",
579
+ "by_april" => "By the April deadline",
580
+ "extension" => "Happy to file an extension",
581
+ "already_ext" => "Already on extension"
582
+ })
583
+ widget target: :tty, type: :select
584
+ widget target: :desktop, type: :radio_group, columns: 2
585
+ transition to: :client_email
586
+ end
587
+
588
+ # -----------------------------------------------------------------------
589
+ # Single contact field — email only, so we can send the quote back.
590
+ # No names, no phone numbers, no addresses.
591
+ # -----------------------------------------------------------------------
592
+
593
+ ask :client_email do
594
+ type :email
595
+ question "Email address to send your fee quote to:"
596
+ widget target: :tty, type: :text_input
597
+ transition to: :thanks
598
+ end
599
+
600
+ say :thanks do
601
+ text "Thanks! We'll email your fee quote and a document checklist\n" \
602
+ "within one business day. No personal information was stored."
603
+ end
604
+ end
@@ -0,0 +1,50 @@
1
+ # Examples
2
+
3
+ This folder contains examples of the Ruby DSL that is converted in the question/answer
4
+ dialog with the end-user and results in the single JSON file containing all the answers.
5
+
6
+ The binary that comes with this gem supports multiple sub-commands:
7
+
8
+ ```text
9
+ ❯ inquirex
10
+ Commands:
11
+ inquirex export FLOW_FILE # Export a flow definition as JSON or YAML .
12
+ inquirex graph FLOW_FILE # Export a flow definition as a Mermaid diagram source, an image, or both.
13
+ inquirex run FLOW_FILE # Run a flow definition interactively
14
+ inquirex validate FLOW_FILE # Validate a flow definition file
15
+ inquirex version # Print version information
16
+ ```
17
+
18
+ Each command supports `--help` of its own.
19
+
20
+ ## Flow File
21
+
22
+ The argument `FLOW_FILE` in the above help definition is a ruby file, just like the ones
23
+ contained in this folder. If you modify it, or write your own, the first you should likely take
24
+ is to run `validate` subcommand on this file.
25
+
26
+ For instance, let's validate the simple questionare about your food preferences:
27
+
28
+ ### Validation
29
+
30
+ ```bash
31
+ ❯ inquirex validate 03_food_preferences.rb
32
+ Flow definition is valid!
33
+ ID: food-preferences
34
+ Version: 1.0.0
35
+ Start step: diet
36
+ Total steps: 5
37
+ Steps: diet, meat_preference, seafood_preference, dessert_preference, summary
38
+ Title: Food Preferences
39
+ Subtitle: Tell us what you enjoy
40
+ ```
41
+
42
+ If the file is valid, most likely all the other commands will work as well.
43
+
44
+ You may want to start with `graph` to visualize the flow of the questions on the aptly named "flow chart":
45
+
46
+ ![flow-chart](03_food_preferences.png)
47
+
48
+ We deliberately used a very simple DSL file, because for a more complex (and likely more realistic) scenario
49
+ the flow chart could be enormous and difficult to follow. Sometimes it's easier to follow the DSL than it is
50
+ to understand the graph.
data/exe/inquirex ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # When this file lives inside a checkout (inquirex-tty/exe/inquirex) we want to
5
+ # use the gems pinned in the repo's Gemfile — NOT whatever rubygems has
6
+ # installed globally. Bundler's `with_unbundled_env`-style bootstrapping:
7
+ # point BUNDLE_GEMFILE at our Gemfile (if present), then require bundler/setup.
8
+ gemfile = File.expand_path("../Gemfile", __dir__)
9
+ if File.file?(gemfile)
10
+ ENV["BUNDLE_GEMFILE"] = gemfile
11
+ begin
12
+ require "bundler/setup"
13
+ rescue LoadError
14
+ # Bundler isn't available — fall through to plain $LOAD_PATH priming below.
15
+ end
16
+ end
17
+
18
+ if File.directory?("#{__dir__}/../lib")
19
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
20
+ end
21
+
22
+ require "inquirex/tty"
23
+
24
+ Dry::CLI.new(Inquirex::TTY::Commands).call