taski 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/README.md +139 -9
- data/docs/GUIDE.md +54 -0
- data/examples/README.md +3 -3
- data/examples/args_demo.rb +21 -20
- data/examples/data_pipeline_demo.rb +1 -1
- data/examples/large_tree_demo.rb +519 -0
- data/examples/simple_progress_demo.rb +80 -0
- data/lib/taski/args.rb +2 -8
- data/lib/taski/env.rb +17 -0
- data/lib/taski/execution/base_progress_display.rb +348 -0
- data/lib/taski/execution/execution_context.rb +4 -0
- data/lib/taski/execution/executor.rb +111 -131
- data/lib/taski/execution/plain_progress_display.rb +76 -0
- data/lib/taski/execution/simple_progress_display.rb +173 -0
- data/lib/taski/execution/task_output_router.rb +91 -20
- data/lib/taski/execution/task_wrapper.rb +34 -31
- data/lib/taski/execution/tree_progress_display.rb +121 -271
- data/lib/taski/static_analysis/visitor.rb +3 -0
- data/lib/taski/task.rb +42 -30
- data/lib/taski/test_helper/errors.rb +13 -0
- data/lib/taski/test_helper/minitest.rb +38 -0
- data/lib/taski/test_helper/mock_registry.rb +53 -0
- data/lib/taski/test_helper/mock_wrapper.rb +46 -0
- data/lib/taski/test_helper/rspec.rb +38 -0
- data/lib/taski/test_helper.rb +246 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +119 -8
- metadata +14 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7677c0f3995a7c61b5850fb25c82c60626287584e5c7f918939ededc045e9ea
|
|
4
|
+
data.tar.gz: d470969c88a4df51503487aacdf2c6261b65e6ed75ee3c7cc2ff744dfd750365
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f93d9e7d10f7104851266f0252ec4365d445a90d3a25b885f289df5d8caafbe9f9250ff9236e4cca0791749100c83c46735a8e98e5c1b675662199ba7a0e547
|
|
7
|
+
data.tar.gz: eb4fb9f806cdd5097e0d3321d4cda9e3df183d4850c4aa8161ba09b71666444166f05b5e795b330227076d85f7410adbe2fc4f1e2b19c66d007ff1632d354f97
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-01-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Taski::Env` class for system-managed execution environment information ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
14
|
+
- Access via `Taski.env.working_directory`, `Taski.env.started_at`, `Taski.env.root_task`
|
|
15
|
+
- `args` and `workers` parameters to `Task.new` for direct task instantiation ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
16
|
+
- `mock_env` helper in `TestHelper` for mocking environment in tests ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Separate system attributes from `Taski.args` to `Taski.env` ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
20
|
+
- `Taski.args` now holds only user-defined options passed via `run(args: {...})`
|
|
21
|
+
- `Taski.env` holds system-managed execution environment (`root_task`, `started_at`, `working_directory`)
|
|
22
|
+
|
|
23
|
+
## [0.7.1] - 2026-01-22
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- `Taski::TestHelper` module for mocking task dependencies in unit tests ([#123](https://github.com/ahogappa/taski/pull/123))
|
|
27
|
+
- `mock_task(TaskClass, key: value)` to mock exported values without running tasks
|
|
28
|
+
- `assert_task_accessed` / `refute_task_accessed` for verifying dependency access
|
|
29
|
+
- Support for both Minitest and RSpec test frameworks
|
|
30
|
+
- Simple one-line progress display mode (`Taski.progress_mode = :simple`) as an alternative to tree display ([#112](https://github.com/ahogappa/taski/pull/112))
|
|
31
|
+
- Configure via `TASKI_PROGRESS_MODE` environment variable or `Taski.progress_mode` API
|
|
32
|
+
- Display captured task output (up to 30 lines) in AggregateError messages for better debugging ([#109](https://github.com/ahogappa/taski/pull/109))
|
|
33
|
+
- Background polling thread in TaskOutputRouter to ensure pipes are drained reliably ([#122](https://github.com/ahogappa/taski/pull/122))
|
|
34
|
+
- `Taski.with_args` helper method for safe argument lifecycle management ([#110](https://github.com/ahogappa/taski/pull/110))
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- Progress display now uses alternate screen buffer and shows summary line after completion ([#107](https://github.com/ahogappa/taski/pull/107))
|
|
38
|
+
- Eliminate screen flickering in tree progress display with in-place overwrite rendering ([#121](https://github.com/ahogappa/taski/pull/121))
|
|
39
|
+
- Extract `BaseProgressDisplay` class for shared progress display functionality ([#117](https://github.com/ahogappa/taski/pull/117))
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- Wait for running dependencies in nested executor to prevent deadlock ([#106](https://github.com/ahogappa/taski/pull/106))
|
|
43
|
+
- Preserve namespace path when following method calls in static analysis ([#108](https://github.com/ahogappa/taski/pull/108))
|
|
44
|
+
- Prevent race condition in `Taski.args` lifecycle during concurrent execution ([#110](https://github.com/ahogappa/taski/pull/110))
|
|
45
|
+
- Ensure progress display cleanup on interrupt (Ctrl+C) ([#107](https://github.com/ahogappa/taski/pull/107))
|
|
46
|
+
- Always enable output in PlainProgressDisplay ([#117](https://github.com/ahogappa/taski/pull/117))
|
|
47
|
+
|
|
10
48
|
## [0.7.0] - 2025-12-23
|
|
11
49
|
|
|
12
50
|
### Added
|
data/README.md
CHANGED
|
@@ -113,6 +113,87 @@ end
|
|
|
113
113
|
|
|
114
114
|
> **Note**: Nested implementation classes automatically inherit Section's `interfaces` as `exports`.
|
|
115
115
|
|
|
116
|
+
## Best Practices
|
|
117
|
+
|
|
118
|
+
### Keep Tasks Small and Focused
|
|
119
|
+
|
|
120
|
+
Each task should do **one thing only**. While Taski allows you to write complex logic within a single task, keeping tasks small and focused provides significant benefits:
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
# ✅ Good: Small, focused tasks
|
|
124
|
+
class FetchData < Taski::Task
|
|
125
|
+
exports :data
|
|
126
|
+
def run
|
|
127
|
+
@data = API.fetch
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class TransformData < Taski::Task
|
|
132
|
+
exports :result
|
|
133
|
+
def run
|
|
134
|
+
@result = FetchData.data.transform
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class SaveData < Taski::Task
|
|
139
|
+
def run
|
|
140
|
+
Database.save(TransformData.result)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# ❌ Avoid: Monolithic task doing everything
|
|
145
|
+
class DoEverything < Taski::Task
|
|
146
|
+
def run
|
|
147
|
+
data = API.fetch
|
|
148
|
+
result = data.transform
|
|
149
|
+
Database.save(result)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Why small tasks matter:**
|
|
155
|
+
|
|
156
|
+
- **Parallel Execution**: Independent tasks run concurrently. Large monolithic tasks can't be parallelized
|
|
157
|
+
- **Easier Cleanup**: `Task.clean` works per-task. Smaller tasks mean more granular cleanup control
|
|
158
|
+
- **Better Reusability**: Small tasks can be composed into different workflows
|
|
159
|
+
- **Clearer Dependencies**: The dependency graph becomes explicit and visible with `Task.tree`
|
|
160
|
+
|
|
161
|
+
**Note:** Complex internal logic is perfectly fine. "One thing" means one responsibility, not one line of code. Other tasks only care about the exported results, not how they were computed.
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class RawData < Taski::Task
|
|
165
|
+
exports :data
|
|
166
|
+
def run
|
|
167
|
+
@data = API.fetch
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class ProcessedData < Taski::Task
|
|
172
|
+
exports :result
|
|
173
|
+
|
|
174
|
+
def run
|
|
175
|
+
# Complex internal logic is OK - this task has one responsibility:
|
|
176
|
+
# producing the processed result
|
|
177
|
+
validated = validate_and_clean(RawData.data)
|
|
178
|
+
enriched = enrich_with_metadata(validated)
|
|
179
|
+
normalized = normalize_format(enriched)
|
|
180
|
+
@result = apply_business_rules(normalized)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
def validate_and_clean(data)
|
|
186
|
+
# Complex validation logic...
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def enrich_with_metadata(data)
|
|
190
|
+
# Complex enrichment logic...
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# ... other private methods
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
116
197
|
## Advanced Usage
|
|
117
198
|
|
|
118
199
|
### Args - Runtime Information and Options
|
|
@@ -122,14 +203,14 @@ Pass custom options and access execution context from any task:
|
|
|
122
203
|
```ruby
|
|
123
204
|
class DeployTask < Taski::Task
|
|
124
205
|
def run
|
|
125
|
-
# User-defined options
|
|
206
|
+
# User-defined options (Taski.args)
|
|
126
207
|
env = Taski.args[:env]
|
|
127
208
|
debug = Taski.args.fetch(:debug, false)
|
|
128
209
|
|
|
129
|
-
# Runtime information
|
|
130
|
-
puts "Working directory: #{Taski.
|
|
131
|
-
puts "Started at: #{Taski.
|
|
132
|
-
puts "Root task: #{Taski.
|
|
210
|
+
# Runtime environment information (Taski.env)
|
|
211
|
+
puts "Working directory: #{Taski.env.working_directory}"
|
|
212
|
+
puts "Started at: #{Taski.env.started_at}"
|
|
213
|
+
puts "Root task: #{Taski.env.root_task}"
|
|
133
214
|
puts "Deploying to: #{env}"
|
|
134
215
|
end
|
|
135
216
|
end
|
|
@@ -138,13 +219,15 @@ end
|
|
|
138
219
|
DeployTask.run(args: { env: "production", debug: true })
|
|
139
220
|
```
|
|
140
221
|
|
|
141
|
-
Args API:
|
|
222
|
+
Args API (user-defined options):
|
|
142
223
|
- `Taski.args[:key]` - Get option value (nil if not set)
|
|
143
224
|
- `Taski.args.fetch(:key, default)` - Get with default value
|
|
144
225
|
- `Taski.args.key?(:key)` - Check if option exists
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
- `Taski.
|
|
226
|
+
|
|
227
|
+
Env API (execution environment):
|
|
228
|
+
- `Taski.env.working_directory` - Execution directory
|
|
229
|
+
- `Taski.env.started_at` - Execution start time
|
|
230
|
+
- `Taski.env.root_task` - First task class called
|
|
148
231
|
|
|
149
232
|
### Execution Model
|
|
150
233
|
|
|
@@ -191,6 +274,23 @@ WebServer (Task)
|
|
|
191
274
|
└── ◻ Server (Task)
|
|
192
275
|
```
|
|
193
276
|
|
|
277
|
+
**Simple mode** provides a compact single-line display:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
⠹ [3/5] DeployTask | Uploading files...
|
|
281
|
+
✓ [5/5] All tasks completed (1234ms)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Configuration:**
|
|
285
|
+
|
|
286
|
+
```ruby
|
|
287
|
+
# Via API
|
|
288
|
+
Taski.progress_mode = :simple # or :tree (default)
|
|
289
|
+
|
|
290
|
+
# Via environment variable
|
|
291
|
+
TASKI_PROGRESS_MODE=simple ruby your_script.rb
|
|
292
|
+
```
|
|
293
|
+
|
|
194
294
|
To disable: `TASKI_PROGRESS_DISABLE=1 ruby your_script.rb`
|
|
195
295
|
|
|
196
296
|
### Tree Visualization
|
|
@@ -203,6 +303,36 @@ puts WebServer.tree
|
|
|
203
303
|
# └── Cache (Task)
|
|
204
304
|
```
|
|
205
305
|
|
|
306
|
+
## Testing
|
|
307
|
+
|
|
308
|
+
### Test Helper for Mocking Dependencies
|
|
309
|
+
|
|
310
|
+
Taski provides a test helper to mock task dependencies in your unit tests:
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
require 'taski/test_helper/minitest'
|
|
314
|
+
|
|
315
|
+
class BuildReportTest < Minitest::Test
|
|
316
|
+
include Taski::TestHelper::Minitest
|
|
317
|
+
|
|
318
|
+
def test_builds_report
|
|
319
|
+
# Mock direct dependencies - their run methods won't execute
|
|
320
|
+
mock_task(FetchData, users: [1, 2, 3])
|
|
321
|
+
|
|
322
|
+
# Task under test uses mocked values
|
|
323
|
+
assert_equal 3, BuildReport.user_count
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Key features:**
|
|
329
|
+
- Mock only direct dependencies; indirect dependencies are automatically isolated
|
|
330
|
+
- Verify which dependencies were accessed with `assert_task_accessed` / `refute_task_accessed`
|
|
331
|
+
- Automatic cleanup after each test
|
|
332
|
+
- Supports both Minitest and RSpec
|
|
333
|
+
|
|
334
|
+
For RSpec, use `include Taski::TestHelper::RSpec` instead.
|
|
335
|
+
|
|
206
336
|
## Development
|
|
207
337
|
|
|
208
338
|
```bash
|
data/docs/GUIDE.md
CHANGED
|
@@ -287,6 +287,59 @@ After completion:
|
|
|
287
287
|
└── Server (Task) 70.2ms
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
+
### Display Modes
|
|
291
|
+
|
|
292
|
+
Taski supports two progress display modes:
|
|
293
|
+
|
|
294
|
+
#### Tree Mode (Default)
|
|
295
|
+
|
|
296
|
+
Full dependency tree visualization with status for each task:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
WebServer (Task)
|
|
300
|
+
├── ⠋ Config (Task) | Reading config.yml...
|
|
301
|
+
│ ├── ✅ Database (Task) 45.2ms
|
|
302
|
+
│ └── ⠙ Cache (Task) | Connecting...
|
|
303
|
+
└── ◻ Server (Task)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Simple Mode
|
|
307
|
+
|
|
308
|
+
Compact single-line display showing current progress:
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
⠹ [3/5] DeployTask | Uploading files...
|
|
312
|
+
✓ [5/5] All tasks completed (1234ms)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Format: `[spinner] [completed/total] TaskName | last output...`
|
|
316
|
+
|
|
317
|
+
When multiple tasks run in parallel:
|
|
318
|
+
```
|
|
319
|
+
⠹ [2/5] DownloadLayer1, DownloadLayer2 | Downloading...
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
On failure:
|
|
323
|
+
```
|
|
324
|
+
✗ [3/5] DeployTask failed: Connection refused
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Configuring Progress Mode
|
|
328
|
+
|
|
329
|
+
**Via API:**
|
|
330
|
+
|
|
331
|
+
```ruby
|
|
332
|
+
Taski.progress_mode = :simple # Use simple mode
|
|
333
|
+
Taski.progress_mode = :tree # Use tree mode (default)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Via environment variable:**
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
TASKI_PROGRESS_MODE=simple ruby your_script.rb
|
|
340
|
+
TASKI_PROGRESS_MODE=tree ruby your_script.rb
|
|
341
|
+
```
|
|
342
|
+
|
|
290
343
|
### Disabling Progress Display
|
|
291
344
|
|
|
292
345
|
```bash
|
|
@@ -310,6 +363,7 @@ ruby build.rb > build.log 2>&1
|
|
|
310
363
|
| Variable | Purpose |
|
|
311
364
|
|----------|---------|
|
|
312
365
|
| `TASKI_PROGRESS_DISABLE=1` | Disable progress display |
|
|
366
|
+
| `TASKI_PROGRESS_MODE=simple\|tree` | Set progress display mode (default: tree) |
|
|
313
367
|
| `TASKI_DEBUG=1` | Enable debug output |
|
|
314
368
|
|
|
315
369
|
### Dependency Tree Visualization
|
data/examples/README.md
CHANGED
|
@@ -46,9 +46,9 @@ ruby examples/args_demo.rb
|
|
|
46
46
|
- User-defined options via `run(args: {...})`
|
|
47
47
|
- `Taski.args[:key]` for option access
|
|
48
48
|
- `Taski.args.fetch(:key, default)` for defaults
|
|
49
|
-
- `Taski.
|
|
50
|
-
- `Taski.
|
|
51
|
-
- `Taski.
|
|
49
|
+
- `Taski.env.working_directory`
|
|
50
|
+
- `Taski.env.started_at`
|
|
51
|
+
- `Taski.env.root_task`
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
data/examples/args_demo.rb
CHANGED
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Taski Args API Example
|
|
4
|
+
# Taski Args & Env API Example
|
|
5
5
|
#
|
|
6
|
-
# This example demonstrates the Args
|
|
7
|
-
# -
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# This example demonstrates the Args and Env APIs:
|
|
7
|
+
# - Taski.env: Execution environment information
|
|
8
|
+
# - working_directory: Where execution started
|
|
9
|
+
# - started_at: When execution began
|
|
10
|
+
# - root_task: The first task class that was called
|
|
11
|
+
# - Taski.args: User-defined options passed via run(args: {...})
|
|
11
12
|
#
|
|
12
13
|
# Run: ruby examples/args_demo.rb
|
|
13
14
|
|
|
14
15
|
require_relative "../lib/taski"
|
|
15
16
|
|
|
16
|
-
puts "Taski Args API Example"
|
|
17
|
+
puts "Taski Args & Env API Example"
|
|
17
18
|
puts "=" * 40
|
|
18
19
|
|
|
19
|
-
# Task that uses
|
|
20
|
+
# Task that uses env information for logging
|
|
20
21
|
class SetupTask < Taski::Task
|
|
21
22
|
exports :setup_info
|
|
22
23
|
|
|
23
24
|
def run
|
|
24
25
|
puts "Setup running..."
|
|
25
|
-
puts " Working directory: #{Taski.
|
|
26
|
-
puts " Started at: #{Taski.
|
|
27
|
-
puts " Root task: #{Taski.
|
|
26
|
+
puts " Working directory: #{Taski.env.working_directory}"
|
|
27
|
+
puts " Started at: #{Taski.env.started_at}"
|
|
28
|
+
puts " Root task: #{Taski.env.root_task}"
|
|
28
29
|
puts " Environment: #{Taski.args[:env]}"
|
|
29
30
|
|
|
30
31
|
@setup_info = {
|
|
31
|
-
directory: Taski.
|
|
32
|
-
timestamp: Taski.
|
|
32
|
+
directory: Taski.env.working_directory,
|
|
33
|
+
timestamp: Taski.env.started_at,
|
|
33
34
|
env: Taski.args[:env]
|
|
34
35
|
}
|
|
35
36
|
end
|
|
@@ -40,8 +41,8 @@ class FileProcessor < Taski::Task
|
|
|
40
41
|
exports :output_path
|
|
41
42
|
|
|
42
43
|
def run
|
|
43
|
-
# Use
|
|
44
|
-
base_dir = Taski.
|
|
44
|
+
# Use env to determine output location
|
|
45
|
+
base_dir = Taski.env.working_directory
|
|
45
46
|
env = Taski.args.fetch(:env, "development")
|
|
46
47
|
@output_path = File.join(base_dir, "tmp", env, "output.txt")
|
|
47
48
|
|
|
@@ -55,7 +56,7 @@ class TimingTask < Taski::Task
|
|
|
55
56
|
exports :duration_info
|
|
56
57
|
|
|
57
58
|
def run
|
|
58
|
-
start_time = Taski.
|
|
59
|
+
start_time = Taski.env.started_at
|
|
59
60
|
current_time = Time.now
|
|
60
61
|
elapsed = current_time - start_time
|
|
61
62
|
|
|
@@ -76,7 +77,7 @@ class MainTask < Taski::Task
|
|
|
76
77
|
|
|
77
78
|
def run
|
|
78
79
|
puts "\nMainTask executing..."
|
|
79
|
-
puts " Root task is: #{Taski.
|
|
80
|
+
puts " Root task is: #{Taski.env.root_task}"
|
|
80
81
|
puts " Environment: #{Taski.args[:env]}"
|
|
81
82
|
|
|
82
83
|
# Access dependencies
|
|
@@ -88,7 +89,7 @@ class MainTask < Taski::Task
|
|
|
88
89
|
setup: setup,
|
|
89
90
|
output_path: output,
|
|
90
91
|
timing: timing,
|
|
91
|
-
root_task: Taski.
|
|
92
|
+
root_task: Taski.env.root_task.to_s
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
puts "\nExecution Summary:"
|
|
@@ -114,5 +115,5 @@ puts "-" * 40
|
|
|
114
115
|
puts MainTask.tree
|
|
115
116
|
|
|
116
117
|
puts "\n" + "=" * 40
|
|
117
|
-
puts "Args API demonstration complete!"
|
|
118
|
-
puts "Note: Args provides
|
|
118
|
+
puts "Args & Env API demonstration complete!"
|
|
119
|
+
puts "Note: Args provides user options, Env provides execution environment info."
|
|
@@ -129,7 +129,7 @@ class EnrichWithActivities < Taski::Task
|
|
|
129
129
|
|
|
130
130
|
activities_by_user = activities.group_by { |a| a[:user_id] }
|
|
131
131
|
.transform_values do |records|
|
|
132
|
-
|
|
132
|
+
records.to_h { |r| [r[:action], r[:count]] }
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
@users_with_activities = users.map do |user|
|