Skip to content

Commit 73f5fd3

Browse files
committed
docs: fix env_interpolation documentation examples with proper imports
Add missing use statements to make documentation examples compile correctly. Fixes include proper module imports for build_positional_args_context, interpolate_env_value, and related functions. Also adds assert statements to verify example behavior.
1 parent 1e634ff commit 73f5fd3

File tree

6 files changed

+80
-43
lines changed

6 files changed

+80
-43
lines changed

src/cook/execution/interpolation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ impl InterpolationEngine {
3434
// ${variable}, ${variable.path}, ${variable:-default}
3535
// $VAR (simple unbraced variable name)
3636
// $1, $2, ... (positional parameters)
37-
let variable_regex =
38-
Regex::new(r"\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*|\d+)").expect("Invalid regex pattern");
37+
let variable_regex = Regex::new(r"\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*|\d+)")
38+
.expect("Invalid regex pattern");
3939

4040
Self {
4141
strict_mode,

src/cook/execution/mapreduce/coordination/executor.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ impl MapReduceCoordinator {
242242

243243
// Execute setup phase if present
244244
if let Some(setup_phase) = setup {
245-
self.execute_setup_phase(setup_phase, env, &map_phase.workflow_env).await?;
245+
self.execute_setup_phase(setup_phase, env, &map_phase.workflow_env)
246+
.await?;
246247
}
247248

248249
// Load work items
@@ -493,7 +494,10 @@ impl MapReduceCoordinator {
493494
info!("🔍 DEBUG: Original step shell command: {:?}", step.shell);
494495
info!("🔍 DEBUG: Workflow env vars: {:?}", workflow_env);
495496
let interpolated_step = self.interpolate_step_with_env(step, workflow_env)?;
496-
info!("🔍 DEBUG: Interpolated step shell command: {:?}", interpolated_step.shell);
497+
info!(
498+
"🔍 DEBUG: Interpolated step shell command: {:?}",
499+
interpolated_step.shell
500+
);
497501

498502
// Execute the interpolated step
499503
let result = self

src/cook/execution/mapreduce/coordination/executor_tests.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,9 @@ mod execute_setup_phase_tests {
679679
capture_outputs: HashMap::new(),
680680
};
681681

682-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
682+
let result = coordinator
683+
.execute_setup_phase(setup, &env, &HashMap::new())
684+
.await;
683685
assert!(
684686
result.is_ok(),
685687
"Setup phase should succeed with all passing steps"
@@ -700,7 +702,9 @@ mod execute_setup_phase_tests {
700702
capture_outputs: HashMap::new(),
701703
};
702704

703-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
705+
let result = coordinator
706+
.execute_setup_phase(setup, &env, &HashMap::new())
707+
.await;
704708
assert!(
705709
result.is_err(),
706710
"Setup phase should fail when shell command fails"
@@ -733,7 +737,9 @@ mod execute_setup_phase_tests {
733737
capture_outputs: HashMap::new(),
734738
};
735739

736-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
740+
let result = coordinator
741+
.execute_setup_phase(setup, &env, &HashMap::new())
742+
.await;
737743
assert!(
738744
result.is_err(),
739745
"Setup phase should fail when command produces stderr"
@@ -760,7 +766,9 @@ mod execute_setup_phase_tests {
760766
capture_outputs: HashMap::new(),
761767
};
762768

763-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
769+
let result = coordinator
770+
.execute_setup_phase(setup, &env, &HashMap::new())
771+
.await;
764772
assert!(result.is_err(), "Setup phase should fail");
765773

766774
let err_msg = result.unwrap_err().to_string();
@@ -785,7 +793,9 @@ mod execute_setup_phase_tests {
785793
capture_outputs: HashMap::new(),
786794
};
787795

788-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
796+
let result = coordinator
797+
.execute_setup_phase(setup, &env, &HashMap::new())
798+
.await;
789799
assert!(
790800
result.is_err(),
791801
"Setup phase should fail when Claude command fails"
@@ -824,7 +834,9 @@ mod execute_setup_phase_tests {
824834
capture_outputs: HashMap::new(),
825835
};
826836

827-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
837+
let result = coordinator
838+
.execute_setup_phase(setup, &env, &HashMap::new())
839+
.await;
828840
assert!(
829841
result.is_err(),
830842
"Setup phase should fail on first failing step"
@@ -852,7 +864,9 @@ mod execute_setup_phase_tests {
852864
capture_outputs: HashMap::new(),
853865
};
854866

855-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
867+
let result = coordinator
868+
.execute_setup_phase(setup, &env, &HashMap::new())
869+
.await;
856870
// Should succeed - this test verifies env vars are set
857871
// (actual verification would require checking the subprocess call)
858872
assert!(result.is_ok(), "Setup phase should succeed");
@@ -874,7 +888,9 @@ mod execute_setup_phase_tests {
874888

875889
// This test verifies the function runs without panicking
876890
// Debug logs are checked via tracing (would need tracing subscriber in real test)
877-
let result = coordinator.execute_setup_phase(setup, &env, &HashMap::new()).await;
891+
let result = coordinator
892+
.execute_setup_phase(setup, &env, &HashMap::new())
893+
.await;
878894
assert!(
879895
result.is_ok(),
880896
"Setup phase should succeed and log debug context"

src/cook/execution/mapreduce/env_interpolation.rs

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::collections::HashMap;
1818
///
1919
/// # Examples
2020
/// ```
21-
/// use std::collections::HashMap;
21+
/// use prodigy::cook::execution::mapreduce::env_interpolation::build_positional_args_context;
2222
/// let args = vec!["file.txt".to_string(), "output.txt".to_string()];
2323
/// let context = build_positional_args_context(&args);
2424
///
@@ -31,16 +31,10 @@ pub fn build_positional_args_context(args: &[String]) -> InterpolationContext {
3131
let position = index + 1;
3232

3333
// Add numbered variable for $1, $2 syntax
34-
variables.insert(
35-
position.to_string(),
36-
Value::String(arg.clone()),
37-
);
34+
variables.insert(position.to_string(), Value::String(arg.clone()));
3835

3936
// Add named variable for ${ARG_1}, ${ARG_2} syntax
40-
variables.insert(
41-
format!("ARG_{}", position),
42-
Value::String(arg.clone()),
43-
);
37+
variables.insert(format!("ARG_{}", position), Value::String(arg.clone()));
4438
}
4539

4640
InterpolationContext {
@@ -53,12 +47,15 @@ pub fn build_positional_args_context(args: &[String]) -> InterpolationContext {
5347
///
5448
/// # Examples
5549
/// ```
50+
/// use prodigy::cook::execution::mapreduce::env_interpolation::{build_positional_args_context, interpolate_env_value};
51+
/// use prodigy::cook::execution::interpolation::InterpolationEngine;
52+
///
5653
/// let value = "$1";
5754
/// let args = vec!["file.txt".to_string()];
5855
/// let context = build_positional_args_context(&args);
5956
/// let mut engine = InterpolationEngine::new(false);
6057
///
61-
/// let result = interpolate_env_value(value, &context, &mut engine)?;
58+
/// let result = interpolate_env_value(value, &context, &mut engine).unwrap();
6259
/// assert_eq!(result, "file.txt");
6360
/// ```
6461
pub fn interpolate_env_value(
@@ -78,16 +75,20 @@ pub fn interpolate_env_value(
7875
///
7976
/// # Examples
8077
/// ```
78+
/// use std::collections::HashMap;
79+
/// use prodigy::cook::execution::mapreduce::env_interpolation::interpolate_workflow_env_with_positional_args;
80+
///
8181
/// let mut env = HashMap::new();
8282
/// env.insert("BLOG_POST".to_string(), "$1".to_string());
8383
/// env.insert("OUTPUT_DIR".to_string(), "out".to_string());
8484
///
8585
/// let args = vec!["content/blog/my-post.md".to_string()];
86-
/// let result = interpolate_workflow_env_with_positional_args(Some(&env), &args)?;
86+
/// let result = interpolate_workflow_env_with_positional_args(Some(&env), &args).unwrap();
8787
///
8888
/// // result contains:
8989
/// // "BLOG_POST" => "content/blog/my-post.md"
9090
/// // "OUTPUT_DIR" => "out"
91+
/// # assert_eq!(result.len(), 2);
9192
/// ```
9293
pub fn interpolate_workflow_env_with_positional_args(
9394
workflow_env: Option<&HashMap<String, String>>,
@@ -106,8 +107,8 @@ pub fn interpolate_workflow_env_with_positional_args(
106107
// Interpolate each environment variable value
107108
let mut result = HashMap::new();
108109
for (key, value) in env_map {
109-
let interpolated_value = interpolate_env_value(value, &context, &mut engine)
110-
.with_context(|| {
110+
let interpolated_value =
111+
interpolate_env_value(value, &context, &mut engine).with_context(|| {
111112
format!(
112113
"Failed to interpolate workflow env variable '{}' with value '{}'",
113114
key, value
@@ -127,12 +128,15 @@ pub fn interpolate_workflow_env_with_positional_args(
127128
///
128129
/// # Examples
129130
/// ```
131+
/// use prodigy::cook::execution::mapreduce::env_interpolation::positional_args_as_env_vars;
132+
///
130133
/// let args = vec!["file.txt".to_string(), "output.txt".to_string()];
131134
/// let result = positional_args_as_env_vars(&args);
132135
///
133136
/// // result contains:
134137
/// // "ARG_1" => EnvValue::Static("file.txt")
135138
/// // "ARG_2" => EnvValue::Static("output.txt")
139+
/// # assert_eq!(result.len(), 2);
136140
/// ```
137141
pub fn positional_args_as_env_vars(positional_args: &[String]) -> HashMap<String, EnvValue> {
138142
positional_args
@@ -149,6 +153,10 @@ pub fn positional_args_as_env_vars(positional_args: &[String]) -> HashMap<String
149153
///
150154
/// # Examples
151155
/// ```
156+
/// use std::collections::HashMap;
157+
/// use prodigy::cook::environment::EnvValue;
158+
/// use prodigy::cook::execution::mapreduce::env_interpolation::env_values_to_plain_map;
159+
///
152160
/// let mut env_values = HashMap::new();
153161
/// env_values.insert("KEY".to_string(), EnvValue::Static("value".to_string()));
154162
///
@@ -308,10 +316,7 @@ mod tests {
308316

309317
#[test]
310318
fn test_positional_args_as_env_vars() {
311-
let args = vec![
312-
"file.txt".to_string(),
313-
"output.txt".to_string(),
314-
];
319+
let args = vec!["file.txt".to_string(), "output.txt".to_string()];
315320
let result = positional_args_as_env_vars(&args);
316321

317322
assert_eq!(result.len(), 2);
@@ -344,16 +349,17 @@ mod tests {
344349
// Setup: workflow env with positional arg references
345350
let mut workflow_env = HashMap::new();
346351
workflow_env.insert("BLOG_POST".to_string(), "$1".to_string());
347-
workflow_env.insert("SITE_URL".to_string(), "https://entropicdrift.com".to_string());
352+
workflow_env.insert(
353+
"SITE_URL".to_string(),
354+
"https://entropicdrift.com".to_string(),
355+
);
348356
workflow_env.insert("OUTPUT_DIR".to_string(), "cross-posts".to_string());
349357

350358
let args = vec!["content/blog/rethinking-code-quality-analysis.md".to_string()];
351359

352360
// Step 1: Interpolate workflow env
353-
let mut interpolated_env = interpolate_workflow_env_with_positional_args(
354-
Some(&workflow_env),
355-
&args
356-
).unwrap();
361+
let mut interpolated_env =
362+
interpolate_workflow_env_with_positional_args(Some(&workflow_env), &args).unwrap();
357363

358364
// Step 2: Add positional args as env vars
359365
let positional_env = positional_args_as_env_vars(&args);

src/cook/orchestrator/execution_pipeline.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -938,8 +938,7 @@ impl ExecutionPipeline {
938938

939939
// Use pure functions for environment variable interpolation
940940
use crate::cook::execution::mapreduce::env_interpolation::{
941-
env_values_to_plain_map,
942-
interpolate_workflow_env_with_positional_args,
941+
env_values_to_plain_map, interpolate_workflow_env_with_positional_args,
943942
positional_args_as_env_vars,
944943
};
945944

@@ -1003,8 +1002,10 @@ impl ExecutionPipeline {
10031002
|| config.workflow.profiles.is_some()
10041003
{
10051004
// Interpolate standard workflow env vars too
1006-
let interpolated_standard_env =
1007-
interpolate_workflow_env_with_positional_args(config.workflow.env.as_ref(), &config.command.args)?;
1005+
let interpolated_standard_env = interpolate_workflow_env_with_positional_args(
1006+
config.workflow.env.as_ref(),
1007+
&config.command.args,
1008+
)?;
10081009

10091010
let global_env_config = crate::cook::environment::EnvironmentConfig {
10101011
global_env: interpolated_standard_env,

tests/mapreduce_env_integration_test.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,24 +319,34 @@ reduce:
319319
let env = config.get("env").unwrap().as_mapping().unwrap();
320320

321321
// Check $1 notation
322-
let input_file = env.get(&serde_yaml::Value::String("INPUT_FILE".to_string()))
322+
let input_file = env
323+
.get(&serde_yaml::Value::String("INPUT_FILE".to_string()))
323324
.and_then(|v| v.as_str());
324325
assert_eq!(input_file, Some("$1"), "INPUT_FILE should use $1 notation");
325326

326327
// Check $2 notation
327-
let output_dir = env.get(&serde_yaml::Value::String("OUTPUT_DIR".to_string()))
328+
let output_dir = env
329+
.get(&serde_yaml::Value::String("OUTPUT_DIR".to_string()))
328330
.and_then(|v| v.as_str());
329331
assert_eq!(output_dir, Some("$2"), "OUTPUT_DIR should use $2 notation");
330332

331333
// Check ${ARG_3} notation
332-
let project_name = env.get(&serde_yaml::Value::String("PROJECT_NAME".to_string()))
334+
let project_name = env
335+
.get(&serde_yaml::Value::String("PROJECT_NAME".to_string()))
333336
.and_then(|v| v.as_str());
334-
assert_eq!(project_name, Some("${ARG_3}"), "PROJECT_NAME should use ARG_3 notation");
337+
assert_eq!(
338+
project_name,
339+
Some("${ARG_3}"),
340+
"PROJECT_NAME should use ARG_3 notation"
341+
);
335342

336343
// Verify setup commands use these env vars
337344
let setup = config.get("setup").unwrap().as_sequence().unwrap();
338345
let first_cmd = setup[0].get("shell").unwrap().as_str().unwrap();
339-
assert!(first_cmd.contains("${INPUT_FILE}"), "Setup should use INPUT_FILE env var");
346+
assert!(
347+
first_cmd.contains("${INPUT_FILE}"),
348+
"Setup should use INPUT_FILE env var"
349+
);
340350

341351
Ok(())
342352
}

0 commit comments

Comments
 (0)