### Quick Start Example Source: https://docs.rs/clapfig/0.9.2/clapfig A simple example demonstrating how to initialize and load configuration using Clapfig. ```APIDOC ## Quick start ⓘ``` let config: AppConfig = Clapfig::builder() .app_name("myapp") .load()?; ``` ``` -------------------------------- ### Test CLI Parsing Source: https://docs.rs/clapfig/0.9.2/src/clapfig/cli.rs.html Example unit tests demonstrating how to parse configuration subcommands using the clap parser. ```rust #[test] fn parse_gen_no_output() { let args = parse(&["test", "gen"]); let action = args.into_action(); assert_eq!(action, ConfigAction::Gen { output: None }); } ``` ```rust #[test] fn parse_gen_with_output() { let args = parse(&["test", "gen", "-o", "out.toml"]); let action = args.into_action(); assert_eq!( action, ConfigAction::Gen { output: Some(PathBuf::from("out.toml")) } ); } ``` ```rust #[test] fn parse_gen_with_long_output() { let args = parse(&["test", "gen", "--output", "/etc/myapp.toml"]); let action = args.into_action(); assert_eq!( ``` -------------------------------- ### Basic Clapfig Configuration Loading Source: https://docs.rs/clapfig/0.9.2/clapfig/index.html This snippet demonstrates the minimal setup required to load application configuration using Clapfig. It initializes the builder with an application name and loads the configuration, returning a Result. ```rust let config: AppConfig = Clapfig::builder() .app_name("myapp") .load()?; ``` -------------------------------- ### List Configuration Entries Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Handles the `List` action to retrieve all configuration entries, including defaults and file-based values. The example shows how to extract and assert specific configuration keys. ```rust let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .no_env() .handle(&ConfigAction::List { scope: None }) .unwrap(); match result { ConfigResult::Listing { entries } => { let port = entries.iter().find(|(k, _)| k == "port").unwrap(); assert_eq!(port.1, "3000"); let host = entries.iter().find(|(k, _)| k == "host").unwrap(); assert_eq!(host.1, "localhost"); // default } other => panic!("Expected Listing, got {other:?}"), } ``` -------------------------------- ### Embed ConfigArgs in Clap Derive Source: https://docs.rs/clapfig/0.9.2/clapfig/struct.ConfigArgs.html Example of integrating ConfigArgs into an application's clap derive structure. ```rust #[derive(Parser)] struct Cli { #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { Config(ConfigArgs), } ``` -------------------------------- ### Initialize Clapfig Builder Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Use this to start building a clapfig configuration. It requires a generic type `C` that implements the `Config` trait. ```rust use confique::Config; // Assuming Clapfig and ClapfigBuilder are defined elsewhere pub struct Clapfig; impl Clapfig { pub fn builder() -> ClapfigBuilder { ClapfigBuilder::new() } } ``` -------------------------------- ### Set Application Name Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Sets the application name, which influences default file names, search paths, and environment variable prefixes. This is a common starting point for configuration setup. ```rust pub fn app_name(mut self, name: &str) -> Self { self.app_name = Some(name.to_string()); self } ``` -------------------------------- ### Multiple Scopes Separate Files Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates setting configuration values in multiple distinct scopes, each associated with a separate file path. This setup allows for isolated configuration management. ```rust fn multiple_scopes_separate_files() { let local_dir = TempDir::new().unwrap(); let global_dir = TempDir::new().unwrap(); let make_builder = || { Clapfig::builder::() .app_name("test") .file_name("test.toml") .persist_scope("local", SearchPath::Path(local_dir.path().to_path_buf())) .persist_scope("global", SearchPath::Path(global_dir.path().to_path_buf())) .no_env() }; // Set in local make_builder() .handle(&ConfigAction::Set { key: "port".into(), value: "3000".into(), scope: None, // defaults to "local" }) .unwrap(); // Set in global ``` -------------------------------- ### Parse CLI Subcommands Source: https://docs.rs/clapfig/0.9.2/src/clapfig/cli.rs.html Tests for standard configuration subcommands including get, set, unset, and list operations. ```rust #[test] fn parse_get() { let args = parse(&["test", "get", "database.url"]); let action = args.into_action(); assert_eq!( action, ConfigAction::Get { key: "database.url".into(), scope: None, } ); } ``` ```rust #[test] fn parse_set() { let args = parse(&["test", "set", "port", "3000"]); let action = args.into_action(); assert_eq!( action, ConfigAction::Set { key: "port".into(), value: "3000".into(), scope: None, } ); } ``` ```rust #[test] fn parse_set_string_value() { let args = parse(&["test", "set", "host", "0.0.0.0"]); let action = args.into_action(); assert_eq!( action, ConfigAction::Set { key: "host".into(), value: "0.0.0.0".into(), scope: None, } ); } ``` ```rust #[test] fn parse_unset() { let args = parse(&["test", "unset", "database.url"]); let action = args.into_action(); assert_eq!( action, ConfigAction::Unset { key: "database.url".into(), scope: None, } ); } ``` ```rust #[test] fn parse_bare_config_is_list() { let args = parse(&["test"]); let action = args.into_action(); assert_eq!(action, ConfigAction::List { scope: None }); } ``` ```rust #[test] fn parse_explicit_list() { let args = parse(&["test", "list"]); let action = args.into_action(); assert_eq!(action, ConfigAction::List { scope: None }); } ``` -------------------------------- ### End-to-End Configuration Overrides Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates overriding configuration values from a struct, merging them with values from a TOML file. The example shows how CLI arguments take precedence over file settings. ```rust let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); #[derive(Serialize)] struct Args { host: Option, port: Option, verbose: bool, } let args = Args { host: Some("1.2.3.4".into()), port: None, verbose: true, }; let config: TestConfig = Clapfig::builder() .app_name("test") .file_name("test.toml") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .no_env() .cli_overrides_from(&args) .load() .unwrap(); assert_eq!(config.host, "1.2.3.4"); // from cli assert_eq!(config.port, 3000); // from file (cli was None) assert!(!config.debug); // default (verbose not in config) ``` -------------------------------- ### Handle Get with Scope Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Shows how to retrieve a specific configuration value from a designated scope. It asserts that the correct value associated with the key in that scope is returned. ```rust fn handle_get_with_scope() { let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .persist_scope("local", SearchPath::Path(dir.path().to_path_buf())) .no_env() .handle(&ConfigAction::Get { key: "port".into(), scope: Some("local".into()), }) .unwrap(); match result { ConfigResult::KeyValue { value, .. } => assert_eq!(value, "3000"), other => panic!("Expected KeyValue, got {other:?}"), } } ``` -------------------------------- ### List Defaults Only Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Configures Clapfig to search for configuration files in a specified directory and disables environment variable loading. This setup is typically used before performing actions like listing configuration entries. ```rust let dir = TempDir::new().unwrap(); let result = Clapfig::builder::() .app_name("test") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .no_env() ``` -------------------------------- ### ConfigAction Handling API Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Handles various configuration actions such as listing, generating, getting, setting, and unsetting configuration values. ```APIDOC ## POST /config/handle ### Description Handles a `ConfigAction` which can be one of `List`, `Gen`, `Get`, `Set`, or `Unset`. ### Method POST ### Endpoint /config/handle ### Parameters #### Request Body - **action** (ConfigAction) - Required - The configuration action to perform. - **List**: Lists configuration values. Can optionally specify a `scope`. - **Gen**: Generates a configuration template. Optionally specify an `output` path. - **Get**: Retrieves a configuration value for a given `key`. Can optionally specify a `scope`. - **Set**: Sets a configuration value for a given `key` and `value`. Requires a `scope`. - **Unset**: Unsets a configuration value for a given `key`. Requires a `scope`. ### Request Example ```json { "action": { "type": "Get", "key": "database.port", "scope": "production" } } ``` ### Response #### Success Response (200) - **ConfigResult** (ConfigResult) - The result of the configuration action. - **List**: Returns a list of configuration values or scope file content. - **Gen**: Returns the generated template string or a confirmation of writing to a file. - **Get**: Returns the requested configuration value. - **Set**: Returns a success confirmation. - **Unset**: Returns a success confirmation. #### Response Example ```json { "type": "ConfigResultValue", "value": "5432" } ``` ``` -------------------------------- ### Get Config Value with Documentation Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Retrieves a specific configuration value by its dotted key and includes its associated documentation comment. Requires the config struct to implement `Config` and `Serialize`. Errors are wrapped in `ClapfigError`. ```rust pub fn get_value( config: &C, key: &str, ) -> Result { let toml_value = toml::Value::try_from(config).map_err(|e| ClapfigError::InvalidValue { key: key.into(), reason: e.to_string(), })?; let table = toml_value .as_table() .ok_or_else(|| ClapfigError::InvalidValue { key: key.into(), reason: "config did not serialize to a table".into(), })?; let value = table_get(table, key).ok_or_else(|| ClapfigError::KeyNotFound(key.into()))?; let value_str = format_value(value); let doc = lookup_doc(&C::META, key); Ok(ConfigResult::KeyValue { key: key.into(), value: value_str, doc, }) } ``` -------------------------------- ### expand_search_paths_from Source: https://docs.rs/clapfig/0.9.2/src/clapfig/file.rs.html Expands search paths, similar to `expand_search_paths`, but allows specifying an explicit start directory for `Ancestors` expansion. This is primarily used in testing scenarios. ```APIDOC ## expand_search_paths_from ### Description Expands search paths with an optional explicit start directory for `Ancestors` expansion. ### Method Rust Function ### Endpoint N/A (Rust function) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example N/A ### Response #### Success Response - `Vec`: A vector of expanded directory paths. #### Response Example N/A ``` -------------------------------- ### Handle Config Actions Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Processes various configuration actions including listing values, generating templates, getting values, setting values, and unsetting values. Requires `Serialize` and `Deserialize` traits for the configuration type. ```rust pub fn handle(self, action: &ConfigAction) -> Result where C: Serialize, C::Layer: for<'de> Deserialize<'de>, { match action { ConfigAction::List { scope } => match scope { None => { let config = self.load()?; ops::list_values(&config) } Some(name) => { let path = self.resolve_scope_persist_path(Some(name))?; ops::list_scope_file(&path) } }, ConfigAction::Gen { output } => { let template = ops::generate_template::(); match output { Some(path) => { if let Some(parent) = path.parent() { std::fs::create_dir_all(parent).map_err(|e| ClapfigError::IoError { path: parent.to_path_buf(), source: e, })?; } std::fs::write(path, &template).map_err(|e| ClapfigError::IoError { path: path.clone(), source: e, })?; Ok(ConfigResult::TemplateWritten { path: path.clone() }) } None => Ok(ConfigResult::Template(template)), } } ConfigAction::Get { key, scope } => match scope { None => { let config = self.load()?; ops::get_value(&config, key) } Some(name) => { let path = self.resolve_scope_persist_path(Some(name))?; ops::get_scope_value::(&path, key) } }, ConfigAction::Set { key, value, scope } => { let path = self.resolve_scope_persist_path(scope.as_deref())?; persist::persist_value::(&path, key, value) } ConfigAction::Unset { key, scope } => { let path = self.resolve_scope_persist_path(scope.as_deref())?; persist::unset_value(&path, key) } } } ``` -------------------------------- ### Handle Configuration Actions Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates setting configuration values with specific scopes and listing entries with or without scoping. ```rust make_builder() .handle(&ConfigAction::Set { key: "host".into(), value: "0.0.0.0".into(), scope: Some("global".into()), }) .unwrap(); // Verify separate files let local_content = fs::read_to_string(local_dir.path().join("test.toml")).unwrap(); assert!(local_content.contains("port = 3000")); // host should NOT be set (template may have commented-out host) assert!(!local_content.contains("host = \"0.0.0.0\"")); let global_content = fs::read_to_string(global_dir.path().join("test.toml")).unwrap(); assert!(global_content.contains("host = \"0.0.0.0\"")); // port should NOT be set in global assert!(!global_content.contains("port = 3000")); // List scoped: only that file's entries let local_list = make_builder() .handle(&ConfigAction::List { scope: Some("local".into()), }) .unwrap(); match local_list { ConfigResult::Listing { entries } => { assert_eq!(entries.len(), 1); assert_eq!(entries[0].0, "port"); } other => panic!("Expected Listing, got {other:?}"), } // List merged (no scope): sees both files merged + defaults let merged_list = make_builder() .handle(&ConfigAction::List { scope: None }) .unwrap(); match merged_list { ConfigResult::Listing { entries } => { let keys: Vec<&str> = entries.iter().map(|(k, _)| k.as_str()).collect(); assert!(keys.contains(&"port")); assert!(keys.contains(&"host")); } other => panic!("Expected Listing, got {other:?}"), } ``` -------------------------------- ### Type ID Function Source: https://docs.rs/clapfig/0.9.2/clapfig/struct.Clapfig.html Gets the TypeId of the current instance. This is a standard Rust trait method. ```rust fn type_id(&self) -> TypeId ``` -------------------------------- ### ClapfigBuilder Loading and Handling Methods Source: https://docs.rs/clapfig/0.9.2/clapfig/struct.ClapfigBuilder.html Methods for loading configuration and handling configuration actions using the configured ClapfigBuilder. ```APIDOC ## ClapfigBuilder Loading and Handling ### Description Methods to load the configuration based on the builder's settings and to handle specific configuration actions. ### Methods - `load(self) -> Result` Loads and resolves the configuration through all configured layers. Requires `C::Layer` to implement `Deserialize`. - `handle_and_print(self, action: &ConfigAction) -> Result<(), ClapfigError>` Handles a `ConfigAction` (e.g., get, set, list) and prints the result to standard output. Requires `C` to implement `Serialize` and `C::Layer` to implement `Deserialize`. - `handle(self, action: &ConfigAction) -> Result` Handles a `ConfigAction` and returns the result. Requires `C` to implement `Serialize` and `C::Layer` to implement `Deserialize`. ``` -------------------------------- ### Table Get Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Navigates a TOML table using a dotted key path to retrieve a specific value. ```APIDOC ## GET /api/config/table/get ### Description Retrieves a value from a TOML table using a dotted key path (e.g., "database.url"). This is a utility function for accessing nested values within a parsed TOML structure. ### Method GET ### Endpoint `/api/config/table/get` ### Parameters #### Query Parameters - **table** (object) - Required - The TOML table to search within. - **dotted_key** (string) - Required - The dotted key path to the desired value (e.g., "database.url"). ### Response #### Success Response (200) - **toml::Value** (any) - The TOML value found at the specified dotted key. This can be a string, number, boolean, array, or another table. #### Response Example ```json { "value": "postgres://user:pass@host:port/db" } ``` #### Error Response (404) - Returns `None` if the key is not found in the table. ``` -------------------------------- ### ClapfigBuilder Configuration Source: https://docs.rs/clapfig/0.9.2/clapfig/index.html Initializes the configuration builder to load application settings. ```APIDOC ## Rust: ClapfigBuilder ### Description Initializes the configuration loading process using the builder pattern. ### Method Builder Pattern ### Request Example let config: AppConfig = Clapfig::builder() .app_name("myapp") .load()?; ``` -------------------------------- ### Get Configuration Value Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Retrieves a specific configuration value by its dotted key, including associated documentation comments. ```APIDOC ## get_value ### Description Get a config value by dotted key, including its doc comment. ### Parameters - **config** (C) - Required - The configuration instance. - **key** (str) - Required - The dotted key path to retrieve. ### Response - **ConfigResult::KeyValue** - Returns the key, value, and associated documentation. ``` -------------------------------- ### Handle and Print Action Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Executes a configuration action and prints the result to standard output. ```rust pub fn handle_and_print(self, action: &ConfigAction) -> Result<(), ClapfigError> where C: Serialize, C::Layer: for<'de> Deserialize<'de>, { let result = self.handle(action)?; print!("{result}"); Ok(()) } ``` -------------------------------- ### Handle and Verify Configuration Listing Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Use this pattern to execute a configuration list action and assert the expected structure and values of the returned entries. ```rust .handle(&ConfigAction::List { scope: None }) .unwrap(); match result { ConfigResult::Listing { entries } => { assert_eq!(entries.len(), 5); let db_url = entries.iter().find(|(k, _)| k == "database.url").unwrap(); assert_eq!(db_url.1, ""); } other => panic!("Expected Listing, got {other:?}"), } } } ``` -------------------------------- ### Clapfig Struct Definition Source: https://docs.rs/clapfig/0.9.2/clapfig/struct.Clapfig.html The entry point for building a clapfig configuration. No specific setup is required to use this struct. ```rust pub struct Clapfig; ``` -------------------------------- ### Generate Configuration Template Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates generating a configuration template with and without an output file path. ```rust .app_name("test") .no_env() .handle(&ConfigAction::Gen { output: None }) .unwrap(); match result { ConfigResult::Template(t) => { assert!(t.contains("host")); assert!(t.contains("port")); } other => panic!("Expected Template, got {other:?}"), } } ``` ```rust #[test] fn handle_gen_with_output() { let dir = TempDir::new().unwrap(); let out_path = dir.path().join("generated.toml"); let result: ConfigResult = Clapfig::builder::() .app_name("test") .no_env() .handle(&ConfigAction::Gen { output: Some(out_path.clone()), }) .unwrap(); assert!(matches!(result, ConfigResult::TemplateWritten { .. })); let content = fs::read_to_string(&out_path).unwrap(); assert!(content.contains("host")); assert!(content.contains("port")); } ``` -------------------------------- ### Manage Search Paths Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates replacing, appending, and deduplicating search paths in the configuration builder. ```rust let builder = Clapfig::builder::() .app_name("myapp") .search_paths(vec![SearchPath::Cwd]); assert_eq!(builder.effective_search_paths(), vec![SearchPath::Cwd]); ``` ```rust let builder = Clapfig::builder::() .app_name("myapp") .add_search_path(SearchPath::Cwd); assert_eq!( builder.effective_search_paths(), vec![SearchPath::Platform, SearchPath::Cwd] ); ``` ```rust let builder = Clapfig::builder::() .app_name("myapp") .search_paths(vec![SearchPath::Cwd]) .add_search_path(SearchPath::Platform); assert_eq!( builder.effective_search_paths(), vec![SearchPath::Cwd, SearchPath::Platform] ); ``` -------------------------------- ### Core Library Usage Source: https://docs.rs/clapfig/0.9.2/index.html Demonstrates the basic usage of the clapfig core library without any CLI framework dependencies. Configuration is loaded using ClapfigBuilder. ```APIDOC ## Core library — no CLI framework required The core of clapfig is a **pure Rust API** with no dependency on any CLI framework. Config discovery, multi-file merging, environment variable mapping, key lookup, persistence, and template generation all work through `ClapfigBuilder` and `ConfigAction` without importing clap or any other parser. You can use clapfig in GUI apps, servers, or with any CLI parser of your choice. ### Request Example ```rust let config: AppConfig = Clapfig::builder() .app_name("myapp") .load()?; ``` ``` -------------------------------- ### Get Scope Value Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Tests for retrieving specific values from configuration files, including nested keys, missing keys, and documentation extraction. ```rust #[test] fn get_scope_value_found() { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("config.toml"); std::fs::write(&path, "port = 3000\n").unwrap(); let result = get_scope_value::(&path, "port").unwrap(); match result { ConfigResult::KeyValue { value, .. } => assert_eq!(value, "3000"), other => panic!("Expected KeyValue, got {other:?}"), } } ``` ```rust #[test] fn get_scope_value_nested() { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("config.toml"); std::fs::write(&path, "[database]\npool_size = 20\n").unwrap(); let result = get_scope_value::(&path, "database.pool_size").unwrap(); match result { ConfigResult::KeyValue { value, .. } => assert_eq!(value, "20"), other => panic!("Expected KeyValue, got {other:?}"), } } ``` ```rust #[test] fn get_scope_value_not_found() { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("config.toml"); std::fs::write(&path, "port = 3000\n").unwrap(); let result = get_scope_value::(&path, "missing"); assert!(matches!(result, Err(ClapfigError::KeyNotFound(_)))); } ``` ```rust #[test] fn get_scope_value_missing_file() { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("nonexistent.toml"); let result = get_scope_value::(&path, "port"); assert!(matches!(result, Err(ClapfigError::KeyNotFound(_)))); } ``` ```rust #[test] fn get_scope_value_includes_doc() { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("config.toml"); std::fs::write(&path, "host = \"myhost\"\n").unwrap(); let result = get_scope_value::(&path, "host").unwrap(); match result { ConfigResult::KeyValue { doc, .. } => { let doc_text = doc.join(" "); assert!( doc_text.contains("host"), "doc should mention host: {doc_text}" ); } other => panic!("Expected KeyValue, got {other:?}"), } } ``` -------------------------------- ### Get Scope Value Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Retrieves a specific configuration value from a TOML file within a given scope, along with its associated documentation comments. ```APIDOC ## GET /api/config/scope/value ### Description Retrieves a raw value from a single scope's configuration file based on a dotted key. It also returns documentation comments associated with the configuration struct's metadata. Returns `KeyNotFound` if the key is not present in the file. ### Method GET ### Endpoint `/api/config/scope/value` ### Parameters #### Query Parameters - **file_path** (string) - Required - The path to the TOML configuration file. - **key** (string) - Required - The dotted key to the desired configuration value (e.g., "database.host"). ### Response #### Success Response (200) - **ConfigResult** (object) - The result of the configuration lookup. Can be `Listing` or `KeyValue`. - **entries** (array) - If `ConfigResult::Listing` is returned, this contains a list of key-value pairs. - **key** (string) - If `ConfigResult::KeyValue` is returned, this is the requested key. - **value** (string) - If `ConfigResult::KeyValue` is returned, this is the formatted value of the key. - **doc** (array of strings) - If `ConfigResult::KeyValue` is returned, this contains the documentation comments for the key. #### Response Example ```json { "key": "database.port", "value": "5432", "doc": ["The port number for the database connection."] } ``` #### Error Response (404) - **ClapfigError::KeyNotFound** - Returned if the specified key does not exist in the configuration file. - **ClapfigError::IoError** - Returned if there is an issue reading the file. - **ClapfigError::ParseError** - Returned if the TOML file content is invalid. ``` -------------------------------- ### Load Configuration from File Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Loads configuration from a TOML file and applies CLI overrides. ```rust let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); let config: TestConfig = Clapfig::builder() .app_name("test") .file_name("test.toml") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .no_env() .load() .unwrap(); assert_eq!(config.port, 3000); assert_eq!(config.host, "localhost"); ``` ```rust let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); let config: TestConfig = Clapfig::builder() .app_name("test") ``` -------------------------------- ### FirstMatch Mode: No Files Found Source: https://docs.rs/clapfig/0.9.2/src/clapfig/file.rs.html Demonstrates the FirstMatch search mode when no configuration files are found in any of the specified paths. Asserts that the returned list is empty. ```rust let dir = TempDir::new().unwrap(); let paths = vec![SearchPath::Path(dir.path().to_path_buf())]; let files = load_config_files(&paths, "nonexistent.toml", "test", SearchMode::FirstMatch).unwrap(); assert!(files.is_empty()); ``` -------------------------------- ### Apply CLI Overrides from HashMap Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates applying configuration overrides using a HashMap. ```rust #[test] fn overrides_from_hashmap() { use std::collections::HashMap; let mut map = HashMap::new(); map.insert("port".to_string(), 3000i64); let builder = Clapfig::builder::() .app_name("test") .cli_overrides_from(&map); assert_eq!(builder.cli_overrides.len(), 1); assert_eq!(builder.cli_overrides[0].0, "port"); } ``` -------------------------------- ### Set Configuration Values Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates setting configuration values with default and named scopes, including error handling when no persist path is defined. ```rust #[test] fn handle_set_requires_persist_scope() { let dir = TempDir::new().unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .no_env() .handle(&ConfigAction::Set { key: "port".into(), value: "3000".into(), scope: None, }); assert!(matches!(result, Err(ClapfigError::NoPersistPath))); } ``` ```rust #[test] fn handle_set_default_scope() { let dir = TempDir::new().unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .search_paths(vec![SearchPath::Path(dir.path().to_path_buf())]) .persist_scope("local", SearchPath::Path(dir.path().to_path_buf())) .no_env() .handle(&ConfigAction::Set { key: "port".into(), value: "3000".into(), scope: None, }) .unwrap(); assert!(matches!(result, ConfigResult::ValueSet { .. })); let content = fs::read_to_string(dir.path().join("test.toml")).unwrap(); assert!(content.contains("port = 3000")); } ``` ```rust #[test] fn handle_set_named_scope() { let local_dir = TempDir::new().unwrap(); let global_dir = TempDir::new().unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .persist_scope("local", SearchPath::Path(local_dir.path().to_path_buf())) .persist_scope("global", SearchPath::Path(global_dir.path().to_path_buf())) .no_env() .handle(&ConfigAction::Set { key: "port".into(), value: "9999".into(), scope: Some("global".into()), }) .unwrap(); assert!(matches!(result, ConfigResult::ValueSet { .. })); // Written to global dir, not local let content = fs::read_to_string(global_dir.path().join("test.toml")).unwrap(); assert!(content.contains("port = 9999")); assert!(!local_dir.path().join("test.toml").exists()); } ``` -------------------------------- ### Load and prioritize configuration files Source: https://docs.rs/clapfig/0.9.2/src/clapfig/file.rs.html Uses load_all to collect configuration files from a list of paths, ensuring correct priority order. ```rust fs::write(mid.join("app.toml"), "port = 9000\n").unwrap(); let dirs = vec![root.path().to_path_buf(), mid.clone(), deep.clone()]; let files = load_all(&dirs, "app.toml").unwrap(); assert_eq!(files.len(), 2); assert!(files[0].1.contains("root")); // lower priority assert!(files[1].1.contains("9000")); // higher priority } } ``` -------------------------------- ### Format ConfigResult Listing Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Demonstrates formatting a ConfigResult::Listing into a string representation. ```rust let result = ConfigResult::Listing { entries: vec![ ("host".into(), "localhost".into()), ("port".into(), "8080".into()), ], }; let display = format!("{result}"); assert_eq!(display, "host = localhost\nport = 8080"); } ``` -------------------------------- ### Handle missing configuration keys Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Verifies that requesting a non-existent key returns a KeyNotFound error. ```rust #[test] fn get_nonexistent_key() { let config = test_config(); let result = get_value::(&config, "nonexistent"); assert!(matches!(result, Err(ClapfigError::KeyNotFound(_)))); } ``` -------------------------------- ### Configuration Loading Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Methods for building the configuration input and loading the final configuration. ```APIDOC ## Configuration Loading ### Description Methods for building the configuration input and loading the final configuration. ### Methods #### `load() -> Result` ##### Description Load and resolve the configuration through all layers. This method builds the `ResolveInput` from the current builder state and then resolves the configuration. ##### Returns - `Result` - The resolved configuration of type `C` or a `ClapfigError` if resolution fails. ##### Constraints - `C::Layer` must implement `Deserialize` for all lifetimes. #### `handle_and_print(action: &ConfigAction) -> Result<(), ClapfigError>` ##### Description Handle a `ConfigAction` and print the result to stdout. This is useful for actions that produce output, such as displaying the configuration. ##### Parameters - **action** (`&ConfigAction`) - Required - The `ConfigAction` to handle. ##### Returns - `Result<(), ClapfigError>` - Ok if the action was handled and printed successfully, or a `ClapfigError` if an error occurred. ##### Constraints - `C` must implement `Serialize`. - `C::Layer` must implement `Deserialize` for all lifetimes. ``` -------------------------------- ### Load Configuration Files Source: https://docs.rs/clapfig/0.9.2/src/clapfig/file.rs.html Loads configuration files from a list of expanded directory paths, respecting the specified `SearchMode`. Directories are checked in order for `{dir}/{file_name}`. Missing files are silently skipped, but I/O errors are propagated. ```rust pub fn load_config_files( search_paths: &[SearchPath], file_name: &str, app_name: &str, mode: SearchMode, ) -> Result, ClapfigError> { let dirs = expand_search_paths(search_paths, app_name); match mode { SearchMode::Merge => load_all(&dirs, file_name), SearchMode::FirstMatch => load_first_match(&dirs, file_name), } } ``` -------------------------------- ### Expand Search Paths from Specific Directory Source: https://docs.rs/clapfig/0.9.2/src/clapfig/file.rs.html Expands search paths, similar to `expand_search_paths`, but allows specifying an explicit start directory for `Ancestors` expansion instead of using the current working directory. Primarily used in tests. ```rust pub fn expand_search_paths_from( search_paths: &[SearchPath], app_name: &str, ancestors_start: Option<&std::path::Path>, ) -> Vec { let mut dirs = Vec::new(); for sp in search_paths { match sp { SearchPath::Ancestors(boundary) => { let expanded = match ancestors_start { Some(start) => expand_ancestors_from(start.to_path_buf(), boundary), None => expand_ancestors(boundary), }; dirs.extend(expanded); } other => { if let Some(dir) = resolve_search_path(other, app_name) { dirs.push(dir); } } } } dirs } ``` -------------------------------- ### Verify configuration documentation Source: https://docs.rs/clapfig/0.9.2/src/clapfig/ops.rs.html Tests that documentation strings associated with configuration keys are correctly retrieved. ```rust #[test] fn get_includes_doc() { let config = test_config(); let result = get_value::(&config, "host").unwrap(); match result { ConfigResult::KeyValue { doc, .. } => { let doc_text = doc.join(" "); assert!( doc_text.contains("host"), "doc should mention host: {doc_text}" ); } other => panic!("Expected KeyValue, got {other:?}"), } } ``` ```rust #[test] fn get_nested_doc() { let config = test_config(); let result = get_value::(&config, "database.pool_size").unwrap(); match result { ConfigResult::KeyValue { doc, .. } => { let doc_text = doc.join(" "); assert!( doc_text.contains("pool size") || doc_text.contains("Connection pool"), "doc should mention pool: {doc_text}" ); } other => panic!("Expected KeyValue, got {other:?}"), } } ``` -------------------------------- ### ConfigAction Enum Source: https://docs.rs/clapfig/0.9.2/clapfig/types/enum.ConfigAction.html The ConfigAction enum defines various operations that can be performed on configuration settings. Each variant represents a distinct action, such as listing, generating, getting, setting, or unsetting configuration values. Some operations support targeting a specific configuration scope. ```APIDOC ## Enum ConfigAction ### Description A config operation, independent of any CLI framework. The CLI layer converts parsed clap args into this. Operations that target a specific config file accept an optional `scope` name. When `scope` is `None`: * **`List`/`Get`** : return the merged resolved configuration (all layers). * **`Set`/`Unset`** : write to the default (first) persist scope. When `scope` is `Some(name)`: * **`List`/`Get`** : return entries from that scope’s config file only. * **`Set`/`Unset`** : write to that scope’s config file. ### Variants #### List Show configuration key-value pairs. ##### Fields * **`scope`** (Option) - Optional - Target a specific persist scope’s file, or `None` for merged view. #### Gen ##### Fields * **`output`** (Option) - Optional - #### Get Show a single config key’s value. ##### Fields * **`key`** (String) - Required - The configuration key to retrieve. * **`scope`** (Option) - Optional - Target a specific persist scope’s file, or `None` for merged view. #### Set Persist a value to a config file. ##### Fields * **`key`** (String) - Required - The configuration key to set. * **`value`** (String) - Required - The value to set for the key. * **`scope`** (Option) - Optional - Target scope, or `None` for the default (first) scope. #### Unset Remove a value from a config file. ##### Fields * **`key`** (String) - Required - The configuration key to unset. * **`scope`** (Option) - Optional - Target scope, or `None` for the default (first) scope. ``` -------------------------------- ### Handle List with Scope Source: https://docs.rs/clapfig/0.9.2/src/clapfig/builder.rs.html Demonstrates how to list configuration entries within a specific scope. It verifies that only the entries defined within the specified scope are returned. ```rust fn handle_list_with_scope() { let dir = TempDir::new().unwrap(); fs::write(dir.path().join("test.toml"), "port = 3000\n").unwrap(); let result = Clapfig::builder::() .app_name("test") .file_name("test.toml") .persist_scope("local", SearchPath::Path(dir.path().to_path_buf())) .no_env() .handle(&ConfigAction::List { scope: Some("local".into()), }) .unwrap(); match result { ConfigResult::Listing { entries } => { assert_eq!(entries.len(), 1); assert_eq!(entries[0], ("port".into(), "3000".into())); } other => panic!("Expected Listing, got {other:?}"), } } ``` -------------------------------- ### CloneToUninit (Nightly) Implementation Source: https://docs.rs/clapfig/0.9.2/clapfig/enum.ConfigResult.html Nightly-only experimental API for copy-assignment to uninitialized memory. ```rust unsafe fn clone_to_uninit(&self, dest: *mut u8) ``` -------------------------------- ### Set Value in TOML Document Source: https://docs.rs/clapfig/0.9.2/src/clapfig/persist.rs.html Pure function to patch a TOML document string, setting a key to a raw value. If the content is None, it starts from a generated template. Uses `toml_edit` to preserve comments and formatting. Requires the key to be known to the config schema and the value to be compatible with the field's type. ```rust pub fn set_in_document( content: Option<&str>, key: &str, raw_value: &str, ) -> Result where C::Layer: for<'de> Deserialize<'de>, { // Validate key is known to the config schema let valid_keys = crate::overrides::valid_keys(&C::META); if !valid_keys.contains(key) { return Err(ClapfigError::KeyNotFound(key.into())); } // Validate value is compatible with the field's type by round-trip // deserializing a minimal table into C::Layer (all-optional fields). let check_value = parse_toml_value(raw_value); let check_table = crate::overrides::overrides_to_table(&[(key.to_string(), check_value)]); let _: C::Layer = toml::Value::Table(check_table) .try_into() .map_err(|e: toml::de::Error| ClapfigError::InvalidValue { key: key.into(), reason: e.to_string(), })?; let base = match content { Some(c) => c.to_string(), None => { // Start from template or empty let template = crate::ops::generate_template::(); if template.trim().is_empty() { String::new() } else { template } } }; let mut doc: toml_edit::DocumentMut = base.parse() .map_err(|e: toml_edit::TomlError| ClapfigError::InvalidValue { key: key.into(), reason: e.to_string(), })?; let parsed_value = parse_toml_edit_value(raw_value); // Navigate to the key, creating intermediate tables as needed. let segments: Vec<&str> = key.split('.').collect(); let mut current: &mut toml_edit::Item = doc.as_item_mut(); for segment in &segments[..segments.len() - 1] { if current.get(segment).is_none() { current[segment] = toml_edit::Item::Table(toml_edit::Table::new()); } current = &mut current[segment]; } let leaf = segments.last().unwrap(); current[leaf] = toml_edit::value(parsed_value); Ok(doc.to_string()) } ``` -------------------------------- ### Clap Adapter Usage Source: https://docs.rs/clapfig/0.9.2/index.html Shows how to use the optional clap adapter for CLI applications that use the clap framework. This provides `config gen|list|get|set|unset` subcommands with zero boilerplate. ```APIDOC ## Optional clap adapter (`clap` feature, on by default) For CLI apps using clap, clapfig ships an optional adapter behind the **`clap`** Cargo feature (enabled by default). The [`cli`] module provides `ConfigArgs` and `ConfigSubcommand` — ready-made clap derive types that give your app `config gen|list|get|set|unset` subcommands with zero boilerplate. They convert to the framework-agnostic `ConfigAction` via `ConfigArgs::into_action()`. To use clapfig **without** clap, disable default features: ```toml clapfig = { version = "...", default-features = false } ``` ```