flowengine-cli 0.1.0 → 0.1.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.
data/Rakefile CHANGED
@@ -1,21 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'timeout'
6
- require 'yard'
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "timeout"
6
+ require "yard"
7
7
 
8
8
  def shell(*args)
9
- puts "running: #{args.join(' ')}"
10
- system(args.join(' '))
9
+ puts "running: #{args.join(" ")}"
10
+ system(args.join(" "))
11
11
  end
12
12
 
13
13
  task :clean do
14
- shell('rm -rf pkg/ tmp/ coverage/ doc/ ' )
14
+ shell("rm -rf pkg/ tmp/ coverage/ doc/ ")
15
15
  end
16
16
 
17
17
  task gem: [:build] do
18
- shell('gem install pkg/*')
18
+ shell("gem install pkg/*")
19
19
  end
20
20
 
21
21
  task permissions: [:clean] do
@@ -24,12 +24,11 @@ task permissions: [:clean] do
24
24
  end
25
25
 
26
26
  YARD::Rake::YardocTask.new(:doc) do |t|
27
- t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE.txt)
28
- t.options.unshift('--title', '"FlowEngine CLI is the CLI for validating FlowEngine in the Terminal"')
29
- t.after = -> { exec('open doc/index.html') } if RUBY_PLATFORM =~ /darwin/
27
+ t.files = %w[lib/**/*.rb exe/*.rb - README.md LICENSE.txt CHANGELOG.md]
28
+ t.options.unshift("--title", '"FlowEngine CLI is the CLI for validating FlowEngine in the Terminal"')
29
+ t.after = -> { exec("open doc/index.html") } if RUBY_PLATFORM =~ /darwin/
30
30
  end
31
31
 
32
-
33
32
  task build: :permissions
34
33
 
35
34
  RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 1: Hello World
4
+ #
5
+ # The simplest possible flow — three linear steps, no branching.
6
+ # Demonstrates: text input, number input, display output.
7
+ #
8
+ # Run: bundle exec exe/flowengine-cli run examples/01_hello_world.rb
9
+
10
+ FlowEngine.define do
11
+ start :name
12
+
13
+ step :name do
14
+ type :text
15
+ question "What is your name?"
16
+ transition to: :age
17
+ end
18
+
19
+ step :age do
20
+ type :number
21
+ question "How old are you?"
22
+ transition to: :farewell
23
+ end
24
+
25
+ step :farewell do
26
+ type :display
27
+ question "Thanks for stopping by! Have a great day."
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 2: Yes or No
4
+ #
5
+ # A single boolean branch. Answering "yes" takes a detour;
6
+ # answering "no" goes straight to the end.
7
+ # Demonstrates: boolean step, equals rule, simple branching.
8
+ #
9
+ # Run: bundle exec exe/flowengine-cli run examples/02_yes_or_no.rb
10
+
11
+ FlowEngine.define do
12
+ start :has_pet
13
+
14
+ step :has_pet do
15
+ type :boolean
16
+ question "Do you have a pet?"
17
+ transition to: :pet_name, if_rule: equals(:has_pet, true)
18
+ transition to: :done
19
+ end
20
+
21
+ step :pet_name do
22
+ type :text
23
+ question "What is your pet's name?"
24
+ transition to: :done
25
+ end
26
+
27
+ step :done do
28
+ type :display
29
+ question "All done! Thanks for answering."
30
+ end
31
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 3: Food Preferences
4
+ #
5
+ # Multiple independent branches from a single multi_select step.
6
+ # Each selection may activate a different follow-up question.
7
+ # Demonstrates: multi_select, contains rule, multiple transitions.
8
+ #
9
+ # Run: bundle exec exe/flowengine-cli run examples/03_food_preferences.rb
10
+
11
+ FlowEngine.define do
12
+ start :diet
13
+
14
+ step :diet do
15
+ type :multi_select
16
+ question "Which food categories do you enjoy?"
17
+ options %w[Meat Seafood Vegetarian Vegan Dessert]
18
+ transition to: :meat_preference, if_rule: contains(:diet, "Meat")
19
+ transition to: :seafood_preference, if_rule: contains(:diet, "Seafood")
20
+ transition to: :dessert_preference, if_rule: contains(:diet, "Dessert")
21
+ transition to: :summary
22
+ end
23
+
24
+ step :meat_preference do
25
+ type :single_select
26
+ question "What is your favorite type of meat?"
27
+ options %w[Beef Chicken Pork Lamb]
28
+ transition to: :seafood_preference, if_rule: contains(:diet, "Seafood")
29
+ transition to: :dessert_preference, if_rule: contains(:diet, "Dessert")
30
+ transition to: :summary
31
+ end
32
+
33
+ step :seafood_preference do
34
+ type :single_select
35
+ question "What is your favorite type of seafood?"
36
+ options %w[Salmon Tuna Shrimp Lobster Crab]
37
+ transition to: :dessert_preference, if_rule: contains(:diet, "Dessert")
38
+ transition to: :summary
39
+ end
40
+
41
+ step :dessert_preference do
42
+ type :single_select
43
+ question "What is your favorite dessert?"
44
+ options %w[Cake IceCream Pie Cookies Fruit]
45
+ transition to: :summary
46
+ end
47
+
48
+ step :summary do
49
+ type :display
50
+ question "Thanks! We've noted your food preferences."
51
+ end
52
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 4: Event Registration
4
+ #
5
+ # Two levels of conditional logic. The ticket type determines one
6
+ # branch, and within VIP there's a further branch based on
7
+ # whether the guest wants a plus-one.
8
+ # Demonstrates: single_select, boolean, equals rule, two-level branching.
9
+ #
10
+ # Run: bundle exec exe/flowengine-cli run examples/04_event_registration.rb
11
+
12
+ FlowEngine.define do
13
+ start :attendee_name
14
+
15
+ step :attendee_name do
16
+ type :text
17
+ question "What is your full name?"
18
+ transition to: :ticket_type
19
+ end
20
+
21
+ step :ticket_type do
22
+ type :single_select
23
+ question "Select your ticket type:"
24
+ options %w[General VIP Speaker]
25
+ transition to: :vip_options, if_rule: equals(:ticket_type, "VIP")
26
+ transition to: :talk_title, if_rule: equals(:ticket_type, "Speaker")
27
+ transition to: :dietary
28
+ end
29
+
30
+ # --- VIP branch (level 1) ---
31
+
32
+ step :vip_options do
33
+ type :boolean
34
+ question "Would you like to bring a plus-one?"
35
+ transition to: :plus_one_name, if_rule: equals(:vip_options, true)
36
+ transition to: :dietary
37
+ end
38
+
39
+ # VIP plus-one sub-branch (level 2)
40
+ step :plus_one_name do
41
+ type :text
42
+ question "What is your plus-one's name?"
43
+ transition to: :dietary
44
+ end
45
+
46
+ # --- Speaker branch (level 1) ---
47
+
48
+ step :talk_title do
49
+ type :text
50
+ question "What is the title of your talk?"
51
+ transition to: :av_needs
52
+ end
53
+
54
+ # Speaker AV sub-branch (level 2)
55
+ step :av_needs do
56
+ type :multi_select
57
+ question "What A/V equipment do you need?"
58
+ options %w[Projector Microphone Whiteboard ScreenShare None]
59
+ transition to: :dietary
60
+ end
61
+
62
+ # --- Common path ---
63
+
64
+ step :dietary do
65
+ type :single_select
66
+ question "Any dietary restrictions?"
67
+ options %w[None Vegetarian Vegan GlutenFree Halal Kosher]
68
+ transition to: :confirmation
69
+ end
70
+
71
+ step :confirmation do
72
+ type :display
73
+ question "You're registered! See you at the event."
74
+ end
75
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 5: Job Application Intake
4
+ #
5
+ # Two levels of branching with composed rules (all/any).
6
+ # The role determines the first branch; experience level and
7
+ # specific answers open deeper sub-branches.
8
+ # Demonstrates: all(), any(), greater_than, contains, two-level branching.
9
+ #
10
+ # Run: bundle exec exe/flowengine-cli run examples/05_job_application.rb
11
+
12
+ FlowEngine.define do
13
+ start :applicant_name
14
+
15
+ step :applicant_name do
16
+ type :text
17
+ question "What is your full name?"
18
+ transition to: :role
19
+ end
20
+
21
+ step :role do
22
+ type :single_select
23
+ question "Which role are you applying for?"
24
+ options %w[Engineering Design ProductManagement Sales]
25
+ transition to: :engineering_skills, if_rule: equals(:role, "Engineering")
26
+ transition to: :design_portfolio, if_rule: equals(:role, "Design")
27
+ transition to: :years_experience
28
+ end
29
+
30
+ # --- Engineering branch (level 1) ---
31
+
32
+ step :engineering_skills do
33
+ type :multi_select
34
+ question "Select your primary skills:"
35
+ options %w[Ruby Python JavaScript Go Rust Java]
36
+ transition to: :years_experience
37
+ end
38
+
39
+ # --- Design branch (level 1) ---
40
+
41
+ step :design_portfolio do
42
+ type :text
43
+ question "Please provide a link to your portfolio:"
44
+ transition to: :years_experience
45
+ end
46
+
47
+ # --- Common: experience (feeds level 2 branching) ---
48
+
49
+ step :years_experience do
50
+ type :number
51
+ question "How many years of professional experience do you have?"
52
+ transition to: :leadership_experience, if_rule: greater_than(:years_experience, 7)
53
+ transition to: :education
54
+ end
55
+
56
+ # Level 2 branch: senior applicants
57
+ step :leadership_experience do
58
+ type :boolean
59
+ question "Have you managed a team of 5 or more people?"
60
+ transition to: :management_style, if_rule: equals(:leadership_experience, true)
61
+ transition to: :education
62
+ end
63
+
64
+ # Level 2 sub-branch: managers
65
+ step :management_style do
66
+ type :single_select
67
+ question "How would you describe your management style?"
68
+ options %w[Collaborative Directive Coaching Delegative]
69
+ transition to: :education
70
+ end
71
+
72
+ step :education do
73
+ type :single_select
74
+ question "What is your highest level of education?"
75
+ options %w[HighSchool Bachelors Masters PhD Bootcamp SelfTaught]
76
+ transition to: :availability
77
+ end
78
+
79
+ step :availability do
80
+ type :single_select
81
+ question "When can you start?"
82
+ options %w[Immediately TwoWeeks OneMonth ThreeMonths]
83
+ transition to: :referral
84
+ end
85
+
86
+ step :referral do
87
+ type :boolean
88
+ question "Were you referred by a current employee?"
89
+ transition to: :referral_name, if_rule: equals(:referral, true)
90
+ transition to: :thanks
91
+ end
92
+
93
+ step :referral_name do
94
+ type :text
95
+ question "Who referred you?"
96
+ transition to: :thanks
97
+ end
98
+
99
+ step :thanks do
100
+ type :display
101
+ question "Application submitted! We'll be in touch within 5 business days."
102
+ end
103
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 6: Health Risk Assessment
4
+ #
5
+ # Three levels of conditional branching with composed rules.
6
+ #
7
+ # Level 1: Lifestyle choices branch into exercise, smoking, or diet paths.
8
+ # Level 2: Within exercise, intensity level opens a sub-branch.
9
+ # Within smoking, pack count opens a sub-branch.
10
+ # Level 3: Heavy smokers with additional risk factors get a deeper follow-up.
11
+ #
12
+ # Demonstrates: all(), any(), greater_than, less_than, contains, equals,
13
+ # three-level deep conditional logic.
14
+ #
15
+ # Run: bundle exec exe/flowengine-cli run examples/06_health_assessment.rb
16
+
17
+ FlowEngine.define do
18
+ start :patient_info
19
+
20
+ step :patient_info do
21
+ type :text
22
+ question "Patient name and date of birth (e.g., Jane Doe, 1985-03-15):"
23
+ transition to: :lifestyle
24
+ end
25
+
26
+ step :lifestyle do
27
+ type :multi_select
28
+ question "Select all that apply to your lifestyle:"
29
+ options %w[Exercise Smoking Alcohol HighStress PoorDiet]
30
+ transition to: :exercise_frequency, if_rule: contains(:lifestyle, "Exercise")
31
+ transition to: :smoking_details, if_rule: contains(:lifestyle, "Smoking")
32
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
33
+ transition to: :sleep_quality
34
+ end
35
+
36
+ # ============================================================
37
+ # LEVEL 1 — Exercise branch
38
+ # ============================================================
39
+
40
+ step :exercise_frequency do
41
+ type :number
42
+ question "How many days per week do you exercise?"
43
+ transition to: :exercise_intensity, if_rule: greater_than(:exercise_frequency, 3)
44
+ transition to: :smoking_details, if_rule: contains(:lifestyle, "Smoking")
45
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
46
+ transition to: :sleep_quality
47
+ end
48
+
49
+ # LEVEL 2 — Intense exerciser sub-branch
50
+ step :exercise_intensity do
51
+ type :single_select
52
+ question "What best describes your typical workout intensity?"
53
+ options %w[Moderate Vigorous Extreme]
54
+ transition to: :injury_history, if_rule: equals(:exercise_intensity, "Extreme")
55
+ transition to: :smoking_details, if_rule: contains(:lifestyle, "Smoking")
56
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
57
+ transition to: :sleep_quality
58
+ end
59
+
60
+ # LEVEL 3 — Extreme exerciser injury check
61
+ step :injury_history do
62
+ type :boolean
63
+ question "Have you had any exercise-related injuries in the past year?"
64
+ transition to: :smoking_details, if_rule: contains(:lifestyle, "Smoking")
65
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
66
+ transition to: :sleep_quality
67
+ end
68
+
69
+ # ============================================================
70
+ # LEVEL 1 — Smoking branch
71
+ # ============================================================
72
+
73
+ step :smoking_details do
74
+ type :number
75
+ question "How many packs per day do you smoke?"
76
+ transition to: :smoking_duration, if_rule: greater_than(:smoking_details, 1)
77
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
78
+ transition to: :sleep_quality
79
+ end
80
+
81
+ # LEVEL 2 — Heavy smoker sub-branch
82
+ step :smoking_duration do
83
+ type :number
84
+ question "How many years have you been smoking?"
85
+ transition to: :smoking_cessation, if_rule: all(
86
+ greater_than(:smoking_duration, 10),
87
+ greater_than(:smoking_details, 1)
88
+ )
89
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
90
+ transition to: :sleep_quality
91
+ end
92
+
93
+ # LEVEL 3 — Long-term heavy smoker: cessation counseling
94
+ step :smoking_cessation do
95
+ type :boolean
96
+ question "Have you tried a cessation program before?"
97
+ transition to: :cessation_details, if_rule: equals(:smoking_cessation, true)
98
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
99
+ transition to: :sleep_quality
100
+ end
101
+
102
+ step :cessation_details do
103
+ type :text
104
+ question "Please describe what programs you tried and when:"
105
+ transition to: :diet_details, if_rule: contains(:lifestyle, "PoorDiet")
106
+ transition to: :sleep_quality
107
+ end
108
+
109
+ # ============================================================
110
+ # LEVEL 1 — Diet branch
111
+ # ============================================================
112
+
113
+ step :diet_details do
114
+ type :multi_select
115
+ question "Which of these describe your typical diet?"
116
+ options %w[HighSugar HighSodium LowFiber SkipsMeals FastFood ProcessedFoods]
117
+ transition to: :sleep_quality
118
+ end
119
+
120
+ # ============================================================
121
+ # Common tail
122
+ # ============================================================
123
+
124
+ step :sleep_quality do
125
+ type :single_select
126
+ question "How would you rate your sleep quality?"
127
+ options %w[Excellent Good Fair Poor]
128
+ transition to: :mental_health, if_rule: any(
129
+ equals(:sleep_quality, "Fair"),
130
+ equals(:sleep_quality, "Poor")
131
+ )
132
+ transition to: :family_history
133
+ end
134
+
135
+ step :mental_health do
136
+ type :multi_select
137
+ question "Do any of these apply to you?"
138
+ options %w[Anxiety Depression Insomnia ChronicFatigue None]
139
+ transition to: :family_history
140
+ end
141
+
142
+ step :family_history do
143
+ type :multi_select
144
+ question "Select any conditions that run in your family:"
145
+ options %w[HeartDisease Diabetes Cancer Hypertension None]
146
+ transition to: :risk_summary
147
+ end
148
+
149
+ step :risk_summary do
150
+ type :display
151
+ question "Assessment complete. Your responses have been recorded for review by your provider."
152
+ end
153
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Example 7: Loan Application
4
+ #
5
+ # Three levels of conditional branching with composed rules (all, any).
6
+ #
7
+ # Level 1: Loan type (Personal / Mortgage / Business) splits into different paths.
8
+ # Level 2: Within Mortgage, property type triggers sub-branches.
9
+ # Within Business, revenue level triggers sub-branches.
10
+ # Level 3: High-value mortgage applicants with specific conditions get
11
+ # additional scrutiny. Low-revenue startups get a different path
12
+ # than established businesses.
13
+ #
14
+ # Demonstrates: all(), any(), greater_than, less_than, equals, contains,
15
+ # three-level deep conditional logic, number_matrix.
16
+ #
17
+ # Run: bundle exec exe/flowengine-cli run examples/07_loan_application.rb
18
+
19
+ FlowEngine.define do
20
+ start :applicant_info
21
+
22
+ step :applicant_info do
23
+ type :text
24
+ question "Full legal name:"
25
+ transition to: :loan_type
26
+ end
27
+
28
+ step :loan_type do
29
+ type :single_select
30
+ question "What type of loan are you applying for?"
31
+ options %w[Personal Mortgage Business]
32
+ transition to: :personal_amount, if_rule: equals(:loan_type, "Personal")
33
+ transition to: :mortgage_property, if_rule: equals(:loan_type, "Mortgage")
34
+ transition to: :business_info, if_rule: equals(:loan_type, "Business")
35
+ end
36
+
37
+ # ============================================================
38
+ # LEVEL 1 — Personal loan (simple path)
39
+ # ============================================================
40
+
41
+ step :personal_amount do
42
+ type :number
43
+ question "How much would you like to borrow (in dollars)?"
44
+ transition to: :personal_purpose
45
+ end
46
+
47
+ step :personal_purpose do
48
+ type :single_select
49
+ question "What is the primary purpose of this loan?"
50
+ options %w[DebtConsolidation HomeImprovement Medical Travel Education Other]
51
+ transition to: :credit_check
52
+ end
53
+
54
+ # ============================================================
55
+ # LEVEL 1 — Mortgage branch
56
+ # ============================================================
57
+
58
+ step :mortgage_property do
59
+ type :single_select
60
+ question "What type of property is this for?"
61
+ options %w[SingleFamily Condo Townhouse MultiFamily Commercial]
62
+ transition to: :mortgage_amount
63
+ end
64
+
65
+ step :mortgage_amount do
66
+ type :number
67
+ question "What is the estimated property value (in dollars)?"
68
+ transition to: :mortgage_high_value, if_rule: greater_than(:mortgage_amount, 750_000)
69
+ transition to: :down_payment
70
+ end
71
+
72
+ # LEVEL 2 — High-value mortgage
73
+ step :mortgage_high_value do
74
+ type :boolean
75
+ question "Will this be your primary residence?"
76
+ transition to: :jumbo_review, if_rule: all(
77
+ equals(:mortgage_high_value, false),
78
+ greater_than(:mortgage_amount, 750_000)
79
+ )
80
+ transition to: :down_payment
81
+ end
82
+
83
+ # LEVEL 3 — Investment property jumbo loan
84
+ step :jumbo_review do
85
+ type :number_matrix
86
+ question "Provide details about your existing properties:"
87
+ fields %w[OwnedProperties RentalProperties MortgagesOwed]
88
+ transition to: :down_payment
89
+ end
90
+
91
+ step :down_payment do
92
+ type :number
93
+ question "How much is your down payment (in dollars)?"
94
+ transition to: :credit_check
95
+ end
96
+
97
+ # ============================================================
98
+ # LEVEL 1 — Business loan branch
99
+ # ============================================================
100
+
101
+ step :business_info do
102
+ type :text
103
+ question "Business name and EIN:"
104
+ transition to: :business_type
105
+ end
106
+
107
+ step :business_type do
108
+ type :single_select
109
+ question "Business structure:"
110
+ options %w[SoleProprietor LLC SCorp CCorp Partnership]
111
+ transition to: :annual_revenue
112
+ end
113
+
114
+ step :annual_revenue do
115
+ type :number
116
+ question "What is your annual revenue (in dollars)?"
117
+ transition to: :startup_details, if_rule: less_than(:annual_revenue, 100_000)
118
+ transition to: :established_details, if_rule: greater_than(:annual_revenue, 500_000)
119
+ transition to: :business_loan_amount
120
+ end
121
+
122
+ # LEVEL 2 — Startup path
123
+ step :startup_details do
124
+ type :number
125
+ question "How many months has the business been operating?"
126
+ transition to: :startup_funding, if_rule: less_than(:startup_details, 12)
127
+ transition to: :business_loan_amount
128
+ end
129
+
130
+ # LEVEL 3 — Very new startup
131
+ step :startup_funding do
132
+ type :multi_select
133
+ question "What funding sources have you used so far?"
134
+ options %w[PersonalSavings FriendsFamily AngelInvestor VentureCapital Grant CreditCards None]
135
+ transition to: :business_loan_amount
136
+ end
137
+
138
+ # LEVEL 2 — Established business path
139
+ step :established_details do
140
+ type :number_matrix
141
+ question "Provide financial details:"
142
+ fields %w[Employees AnnualExpenses OutstandingDebt]
143
+ transition to: :established_expansion, if_rule: all(
144
+ greater_than(:annual_revenue, 500_000),
145
+ any(
146
+ equals(:business_type, "CCorp"),
147
+ equals(:business_type, "SCorp")
148
+ )
149
+ )
150
+ transition to: :business_loan_amount
151
+ end
152
+
153
+ # LEVEL 3 — Corp expansion review
154
+ step :established_expansion do
155
+ type :multi_select
156
+ question "What will the loan fund?"
157
+ options %w[Hiring Equipment RealEstate Acquisition Marketing RAndD]
158
+ transition to: :business_loan_amount
159
+ end
160
+
161
+ step :business_loan_amount do
162
+ type :number
163
+ question "How much funding are you requesting (in dollars)?"
164
+ transition to: :credit_check
165
+ end
166
+
167
+ # ============================================================
168
+ # Common tail
169
+ # ============================================================
170
+
171
+ step :credit_check do
172
+ type :boolean
173
+ question "Do you authorize a credit check?"
174
+ transition to: :review, if_rule: equals(:credit_check, true)
175
+ transition to: :declined
176
+ end
177
+
178
+ step :declined do
179
+ type :display
180
+ question "A credit check is required to proceed. Your application has been saved as a draft."
181
+ end
182
+
183
+ step :review do
184
+ type :display
185
+ question "Application submitted! You will receive a decision within 3-5 business days."
186
+ end
187
+ end