simple_flow 0.1.0 → 0.3.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/README.md +33 -0
  4. data/lib/simple_flow/pipeline.rb +104 -21
  5. data/lib/simple_flow/result.rb +20 -5
  6. data/lib/simple_flow/version.rb +1 -1
  7. data/lib/simple_flow.rb +0 -17
  8. metadata +2 -68
  9. data/.envrc +0 -1
  10. data/.github/workflows/deploy-github-pages.yml +0 -52
  11. data/.rubocop.yml +0 -57
  12. data/COMMITS.md +0 -196
  13. data/Rakefile +0 -15
  14. data/benchmarks/parallel_vs_sequential.rb +0 -98
  15. data/benchmarks/pipeline_overhead.rb +0 -130
  16. data/docs/api/middleware.md +0 -468
  17. data/docs/api/parallel-step.md +0 -363
  18. data/docs/api/pipeline.md +0 -382
  19. data/docs/api/result.md +0 -375
  20. data/docs/concurrent/best-practices.md +0 -687
  21. data/docs/concurrent/introduction.md +0 -246
  22. data/docs/concurrent/parallel-steps.md +0 -418
  23. data/docs/concurrent/performance.md +0 -481
  24. data/docs/core-concepts/flow-control.md +0 -452
  25. data/docs/core-concepts/middleware.md +0 -389
  26. data/docs/core-concepts/overview.md +0 -219
  27. data/docs/core-concepts/pipeline.md +0 -315
  28. data/docs/core-concepts/result.md +0 -168
  29. data/docs/core-concepts/steps.md +0 -391
  30. data/docs/development/benchmarking.md +0 -443
  31. data/docs/development/contributing.md +0 -380
  32. data/docs/development/dagwood-concepts.md +0 -435
  33. data/docs/development/testing.md +0 -514
  34. data/docs/getting-started/examples.md +0 -197
  35. data/docs/getting-started/installation.md +0 -62
  36. data/docs/getting-started/quick-start.md +0 -218
  37. data/docs/guides/choosing-concurrency-model.md +0 -441
  38. data/docs/guides/complex-workflows.md +0 -440
  39. data/docs/guides/data-fetching.md +0 -478
  40. data/docs/guides/error-handling.md +0 -635
  41. data/docs/guides/file-processing.md +0 -505
  42. data/docs/guides/validation-patterns.md +0 -496
  43. data/docs/index.md +0 -169
  44. data/examples/.gitignore +0 -3
  45. data/examples/01_basic_pipeline.rb +0 -112
  46. data/examples/02_error_handling.rb +0 -178
  47. data/examples/03_middleware.rb +0 -186
  48. data/examples/04_parallel_automatic.rb +0 -221
  49. data/examples/05_parallel_explicit.rb +0 -279
  50. data/examples/06_real_world_ecommerce.rb +0 -288
  51. data/examples/07_real_world_etl.rb +0 -277
  52. data/examples/08_graph_visualization.rb +0 -246
  53. data/examples/09_pipeline_visualization.rb +0 -266
  54. data/examples/10_concurrency_control.rb +0 -235
  55. data/examples/11_sequential_dependencies.rb +0 -243
  56. data/examples/12_none_constant.rb +0 -161
  57. data/examples/README.md +0 -374
  58. data/examples/regression_test/01_basic_pipeline.txt +0 -38
  59. data/examples/regression_test/02_error_handling.txt +0 -92
  60. data/examples/regression_test/03_middleware.txt +0 -61
  61. data/examples/regression_test/04_parallel_automatic.txt +0 -86
  62. data/examples/regression_test/05_parallel_explicit.txt +0 -80
  63. data/examples/regression_test/06_real_world_ecommerce.txt +0 -53
  64. data/examples/regression_test/07_real_world_etl.txt +0 -58
  65. data/examples/regression_test/08_graph_visualization.txt +0 -429
  66. data/examples/regression_test/09_pipeline_visualization.txt +0 -305
  67. data/examples/regression_test/10_concurrency_control.txt +0 -96
  68. data/examples/regression_test/11_sequential_dependencies.txt +0 -86
  69. data/examples/regression_test/12_none_constant.txt +0 -64
  70. data/examples/regression_test.rb +0 -105
  71. data/mkdocs.yml +0 -146
  72. data/pipeline_graph.dot +0 -51
  73. data/pipeline_graph.html +0 -60
  74. data/pipeline_graph.mmd +0 -19
data/docs/api/result.md DELETED
@@ -1,375 +0,0 @@
1
- # Result API Reference
2
-
3
- The `Result` class is an immutable value object that represents the outcome of a step in a SimpleFlow pipeline. It encapsulates the operation's value, contextual data, and any errors that occurred.
4
-
5
- ## Class: `SimpleFlow::Result`
6
-
7
- **Location**: `/Users/dewayne/sandbox/git_repos/madbomber/simple_flow/lib/simple_flow/result.rb`
8
-
9
- ### Constructor
10
-
11
- #### `new(value, context: {}, errors: {})`
12
-
13
- Creates a new Result instance.
14
-
15
- **Parameters:**
16
- - `value` (Object) - The outcome of the operation
17
- - `context` (Hash, optional) - Contextual data related to the operation (default: `{}`)
18
- - `errors` (Hash, optional) - Errors organized by category (default: `{}`)
19
-
20
- **Returns:** Result instance
21
-
22
- **Example:**
23
- ```ruby
24
- # Basic result
25
- result = SimpleFlow::Result.new(42)
26
-
27
- # Result with context
28
- result = SimpleFlow::Result.new(
29
- { user_id: 123 },
30
- context: { timestamp: Time.now }
31
- )
32
-
33
- # Result with errors
34
- result = SimpleFlow::Result.new(
35
- nil,
36
- errors: { validation: ["Email is required"] }
37
- )
38
- ```
39
-
40
- ### Instance Attributes
41
-
42
- #### `value`
43
-
44
- The outcome of the operation.
45
-
46
- **Type:** Object (read-only)
47
-
48
- **Example:**
49
- ```ruby
50
- result = SimpleFlow::Result.new(42)
51
- result.value # => 42
52
- ```
53
-
54
- #### `context`
55
-
56
- Contextual data related to the operation.
57
-
58
- **Type:** Hash (read-only)
59
-
60
- **Example:**
61
- ```ruby
62
- result = SimpleFlow::Result.new(42, context: { user: "John" })
63
- result.context # => { user: "John" }
64
- ```
65
-
66
- #### `errors`
67
-
68
- Errors that occurred during the operation, organized by category.
69
-
70
- **Type:** Hash (read-only)
71
-
72
- **Example:**
73
- ```ruby
74
- result = SimpleFlow::Result.new(nil, errors: {
75
- validation: ["Email required", "Password too short"],
76
- auth: ["Invalid credentials"]
77
- })
78
-
79
- result.errors[:validation] # => ["Email required", "Password too short"]
80
- result.errors[:auth] # => ["Invalid credentials"]
81
- ```
82
-
83
- ### Instance Methods
84
-
85
- #### `with_context(key, value)`
86
-
87
- Adds or updates context to the result. Returns a new Result instance with updated context.
88
-
89
- **Parameters:**
90
- - `key` (Symbol) - The key to store the context under
91
- - `value` (Object) - The value to store
92
-
93
- **Returns:** New Result instance
94
-
95
- **Immutability:** This method creates a new Result object; the original is unchanged.
96
-
97
- **Example:**
98
- ```ruby
99
- result = SimpleFlow::Result.new(42)
100
- .with_context(:user_id, 123)
101
- .with_context(:timestamp, Time.now)
102
-
103
- result.context # => { user_id: 123, timestamp: 2025-11-15 12:00:00 }
104
- ```
105
-
106
- **Chaining:**
107
- ```ruby
108
- result = SimpleFlow::Result.new(data)
109
- .with_context(:step_name, "process_data")
110
- .with_context(:duration, 0.5)
111
- .with_context(:source, :api)
112
- ```
113
-
114
- #### `with_error(key, message)`
115
-
116
- Adds an error message under a specific key. If the key already exists, the message is appended to existing errors. Returns a new Result instance with updated errors.
117
-
118
- **Parameters:**
119
- - `key` (Symbol) - The category under which to store the error
120
- - `message` (String) - The error message
121
-
122
- **Returns:** New Result instance
123
-
124
- **Immutability:** Creates a new Result object.
125
-
126
- **Example:**
127
- ```ruby
128
- result = SimpleFlow::Result.new(nil)
129
- .with_error(:validation, "Email is required")
130
- .with_error(:validation, "Password too short")
131
- .with_error(:auth, "Invalid credentials")
132
-
133
- result.errors
134
- # => {
135
- # validation: ["Email is required", "Password too short"],
136
- # auth: ["Invalid credentials"]
137
- # }
138
- ```
139
-
140
- **Error Accumulation:**
141
- ```ruby
142
- result = SimpleFlow::Result.new(data)
143
-
144
- # Add first validation error
145
- result = result.with_error(:validation, "Name is required")
146
-
147
- # Add second validation error (accumulates)
148
- result = result.with_error(:validation, "Email is required")
149
-
150
- result.errors[:validation]
151
- # => ["Name is required", "Email is required"]
152
- ```
153
-
154
- #### `halt(new_value = nil)`
155
-
156
- Halts the pipeline flow. Optionally updates the result's value. Returns a new Result instance with `continue` set to false.
157
-
158
- **Parameters:**
159
- - `new_value` (Object, optional) - New value to set (default: keep current value)
160
-
161
- **Returns:** New Result instance with `@continue = false`
162
-
163
- **Example:**
164
- ```ruby
165
- # Halt without changing value
166
- result = SimpleFlow::Result.new(42).halt
167
- result.continue? # => false
168
- result.value # => 42
169
-
170
- # Halt with new value
171
- result = SimpleFlow::Result.new(42).halt(100)
172
- result.continue? # => false
173
- result.value # => 100
174
-
175
- # Halt with error
176
- result = SimpleFlow::Result.new(data)
177
- .halt
178
- .with_error(:validation, "Invalid input")
179
-
180
- result.continue? # => false
181
- result.errors # => { validation: ["Invalid input"] }
182
- ```
183
-
184
- **Usage in Steps:**
185
- ```ruby
186
- step ->(result) {
187
- if invalid?(result.value)
188
- result.halt.with_error(:validation, "Invalid data")
189
- else
190
- result.continue(process(result.value))
191
- end
192
- }
193
- ```
194
-
195
- #### `continue(new_value)`
196
-
197
- Continues the pipeline flow with an updated value. Returns a new Result instance with the new value.
198
-
199
- **Parameters:**
200
- - `new_value` (Object) - The new value to set
201
-
202
- **Returns:** New Result instance with updated value
203
-
204
- **Example:**
205
- ```ruby
206
- result = SimpleFlow::Result.new(5)
207
- .continue(10)
208
-
209
- result.continue? # => true
210
- result.value # => 10
211
- ```
212
-
213
- **Usage in Steps:**
214
- ```ruby
215
- step ->(result) {
216
- transformed = transform(result.value)
217
- result.continue(transformed)
218
- }
219
- ```
220
-
221
- #### `continue?`
222
-
223
- Checks if the pipeline should continue executing.
224
-
225
- **Returns:** Boolean
226
- - `true` if the pipeline should continue
227
- - `false` if the pipeline has been halted
228
-
229
- **Example:**
230
- ```ruby
231
- result = SimpleFlow::Result.new(42)
232
- result.continue? # => true
233
-
234
- result = result.halt
235
- result.continue? # => false
236
- ```
237
-
238
- **Usage:**
239
- ```ruby
240
- result = pipeline.call(initial_data)
241
-
242
- if result.continue?
243
- puts "Success: #{result.value}"
244
- process_result(result)
245
- else
246
- puts "Failed: #{result.errors}"
247
- handle_errors(result)
248
- end
249
- ```
250
-
251
- ## Usage Patterns
252
-
253
- ### Basic Flow Control
254
-
255
- ```ruby
256
- step ->(result) {
257
- if valid?(result.value)
258
- result.continue(result.value)
259
- else
260
- result.halt.with_error(:validation, "Invalid")
261
- end
262
- }
263
- ```
264
-
265
- ### Error Accumulation
266
-
267
- ```ruby
268
- step ->(result) {
269
- result_obj = result
270
-
271
- if invalid_email?(result.value[:email])
272
- result_obj = result_obj.with_error(:email, "Invalid format")
273
- end
274
-
275
- if invalid_phone?(result.value[:phone])
276
- result_obj = result_obj.with_error(:phone, "Invalid format")
277
- end
278
-
279
- # Continue even with errors (check later)
280
- result_obj.continue(result.value)
281
- }
282
-
283
- step ->(result) {
284
- if result.errors.any?
285
- result.halt(result.value)
286
- else
287
- result.continue(result.value)
288
- end
289
- }
290
- ```
291
-
292
- ### Context Propagation
293
-
294
- ```ruby
295
- pipeline = SimpleFlow::Pipeline.new do
296
- step ->(result) {
297
- result
298
- .with_context(:started_at, Time.now)
299
- .with_context(:user_id, 123)
300
- .continue(result.value)
301
- }
302
-
303
- step ->(result) {
304
- # Access context from previous step
305
- user_id = result.context[:user_id]
306
- data = fetch_user_data(user_id)
307
-
308
- result
309
- .with_context(:user_data, data)
310
- .continue(result.value)
311
- }
312
-
313
- step ->(result) {
314
- # All context available
315
- duration = Time.now - result.context[:started_at]
316
-
317
- result
318
- .with_context(:duration, duration)
319
- .continue(process(result.value))
320
- }
321
- end
322
- ```
323
-
324
- ### Combining Operations
325
-
326
- ```ruby
327
- step ->(result) {
328
- result
329
- .with_context(:timestamp, Time.now)
330
- .with_context(:source, :api)
331
- .with_error(:warning, "Deprecated API version")
332
- .continue(transformed_data)
333
- }
334
- ```
335
-
336
- ## Implementation Details
337
-
338
- ### Immutability
339
-
340
- All Result methods return new instances:
341
-
342
- ```ruby
343
- original = SimpleFlow::Result.new(42)
344
- modified = original.with_context(:key, "value")
345
-
346
- original.context # => {}
347
- modified.context # => { key: "value" }
348
-
349
- # original and modified are different objects
350
- original.object_id != modified.object_id # => true
351
- ```
352
-
353
- ### Internal State
354
-
355
- The Result class maintains internal state that is preserved across method calls:
356
-
357
- ```ruby
358
- result = SimpleFlow::Result.new(42)
359
- .halt
360
- .with_context(:key, "value")
361
-
362
- # @continue flag is preserved
363
- result.continue? # => false
364
- result.context # => { key: "value" }
365
- ```
366
-
367
- ### Thread Safety
368
-
369
- Result objects are immutable and thread-safe. Multiple threads can safely read from the same Result instance.
370
-
371
- ## Related Documentation
372
-
373
- - [Pipeline API](pipeline.md) - How pipelines use Result objects
374
- - [Error Handling Guide](../guides/error-handling.md) - Error handling patterns
375
- - [Validation Patterns](../guides/validation-patterns.md) - Validation strategies