Module: Smplkit::ConfigResolution Private
- Defined in:
- lib/smplkit/config_resolution.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
SDK configuration resolution: defaults -> file -> env vars -> constructor args.
Defined Under Namespace
Classes: ResolvedClientConfig, ResolvedConfig
Constant Summary collapse
- CONFIG_KEYS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
{ "api_key" => "SMPLKIT_API_KEY", "base_domain" => "SMPLKIT_BASE_DOMAIN", "scheme" => "SMPLKIT_SCHEME", "environment" => "SMPLKIT_ENVIRONMENT", "service" => "SMPLKIT_SERVICE", "debug" => "SMPLKIT_DEBUG", "telemetry" => "SMPLKIT_TELEMETRY" }.freeze
- BOOL_TRUE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[true 1 yes].freeze
- BOOL_FALSE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[false 0 no].freeze
- DEFAULTS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
{ "api_key" => nil, "base_domain" => "smplkit.com", "scheme" => "https", "environment" => nil, "service" => nil, "debug" => false, "telemetry" => true }.freeze
Class Method Summary collapse
- .missing_required(resolved, key, profile) ⇒ Object private
- .parse_bool(value, key) ⇒ Object private
-
.parse_ini(text) ⇒ Object
private
Minimal INI parser.
- .read_config_file(profile, home_dir: nil) ⇒ Object private
- .resolve_client_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, debug: nil, home_dir: nil) ⇒ Object private
- .resolve_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, environment: nil, service: nil, debug: nil, telemetry: nil, home_dir: nil) ⇒ Object private
-
.service_url(scheme, subdomain, base_domain) ⇒ Object
private
Build a service URL: scheme://subdomain.base_domain.
Class Method Details
.missing_required(resolved, key, profile) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
204 205 206 207 208 209 210 211 212 213 |
# File 'lib/smplkit/config_resolution.rb', line 204 def missing_required(resolved, key, profile) return if resolved[key] env_var = CONFIG_KEYS[key] raise Error, "No #{key} provided. Set one of:\n " \ "1. Pass #{key} to the constructor\n " \ "2. Set the #{env_var} environment variable\n " \ "3. Add #{key} to the [#{profile}] section in ~/.smplkit" end |
.parse_bool(value, key) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
45 46 47 48 49 50 51 52 53 |
# File 'lib/smplkit/config_resolution.rb', line 45 def parse_bool(value, key) lower = value.to_s.strip.downcase return true if BOOL_TRUE.include?(lower) return false if BOOL_FALSE.include?(lower) raise Error, "Invalid boolean value for #{key}: #{value.inspect}. " \ "Expected one of: true, false, 1, 0, yes, no" end |
.parse_ini(text) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Minimal INI parser. Returns { section_name => { key => value, … } }.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/smplkit/config_resolution.rb', line 61 def parse_ini(text) sections = {} current = nil text.each_line do |line| line = line.strip next if line.empty? || line.start_with?("#", ";") if line.start_with?("[") && line.end_with?("]") name = line[1..-2].strip current = (sections[name] ||= {}) elsif current key, _, value = line.partition("=") next if value.empty? && !line.include?("=") current[key.strip] = value.strip end end sections end |
.read_config_file(profile, home_dir: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/smplkit/config_resolution.rb', line 81 def read_config_file(profile, home_dir: nil) home_dir ||= Dir.home path = File.join(home_dir, ".smplkit") return {} unless File.file?(path) sections = begin # Force UTF-8 — the file may contain comments with non-ASCII bytes # (em dashes, smart quotes) and the system's default external # encoding is locale-dependent. parse_ini(File.read(path, encoding: "UTF-8")) rescue StandardError return {} end values = {} sections.fetch("common", {}).each { |k, v| values[k] = v unless v.empty? } if sections.key?(profile) sections[profile].each { |k, v| values[k] = v unless v.empty? } else non_common = sections.keys.reject { |s| s == "common" } if !non_common.empty? && profile != "default" raise Error, "Profile [#{profile}] not found in ~/.smplkit. Available profiles: #{non_common.join(", ")}" end end values end |
.resolve_client_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, debug: nil, home_dir: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/smplkit/config_resolution.rb', line 162 def resolve_client_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, debug: nil, home_dir: nil) resolved = { "api_key" => nil, "base_domain" => "smplkit.com", "scheme" => "https", "debug" => false } active_profile = profile || ENV["SMPLKIT_PROFILE"] || "default" file_values = read_config_file(active_profile, home_dir: home_dir) %w[api_key base_domain scheme debug].each do |key| next unless file_values.key?(key) val = file_values[key] resolved[key] = key == "debug" ? parse_bool(val, key) : val end [ %w[api_key SMPLKIT_API_KEY], %w[base_domain SMPLKIT_BASE_DOMAIN], %w[scheme SMPLKIT_SCHEME], %w[debug SMPLKIT_DEBUG] ].each do |key, env_var| env_val = ENV.fetch(env_var, "") next if env_val.empty? resolved[key] = key == "debug" ? parse_bool(env_val, env_var) : env_val end ctor = { "api_key" => api_key, "base_domain" => base_domain, "scheme" => scheme, "debug" => debug } ctor.each { |k, v| resolved[k] = v unless v.nil? } missing_required(resolved, "api_key", active_profile) ResolvedClientConfig.new( api_key: resolved["api_key"].to_s, base_domain: resolved["base_domain"].to_s, scheme: resolved["scheme"].to_s, debug: resolved["debug"] ? true : false ) end |
.resolve_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, environment: nil, service: nil, debug: nil, telemetry: nil, home_dir: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/smplkit/config_resolution.rb', line 112 def resolve_config(profile: nil, api_key: nil, base_domain: nil, scheme: nil, environment: nil, service: nil, debug: nil, telemetry: nil, home_dir: nil) resolved = DEFAULTS.dup active_profile = profile || ENV["SMPLKIT_PROFILE"] || "default" file_values = read_config_file(active_profile, home_dir: home_dir) CONFIG_KEYS.each_key do |key| next unless file_values.key?(key) val = file_values[key] resolved[key] = %w[debug telemetry].include?(key) ? parse_bool(val, key) : val end CONFIG_KEYS.each do |key, env_var| env_val = ENV.fetch(env_var, "") next if env_val.empty? resolved[key] = %w[debug telemetry].include?(key) ? parse_bool(env_val, env_var) : env_val end ctor = { "api_key" => api_key, "base_domain" => base_domain, "scheme" => scheme, "environment" => environment, "service" => service, "debug" => debug, "telemetry" => telemetry } ctor.each { |k, v| resolved[k] = v unless v.nil? } # Validate required fields. # # +environment+ and +service+ are OPTIONAL: an audit-only or jobs-only # customer needs neither, and when +environment+ is absent the server # derives it from the API key (the key can be scoped to an environment). # config/flags/logging simply send no environment signal when it's unset. # +api_key+ remains required. missing_required(resolved, "api_key", active_profile) ResolvedConfig.new( api_key: resolved["api_key"].to_s, base_domain: resolved["base_domain"].to_s, scheme: resolved["scheme"].to_s, # Preserve nil rather than coercing to the literal string "". environment: resolved["environment"]&.to_s, service: resolved["service"]&.to_s, debug: resolved["debug"] ? true : false, telemetry: resolved["telemetry"] ? true : false ) end |
.service_url(scheme, subdomain, base_domain) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build a service URL: scheme://subdomain.base_domain
56 57 58 |
# File 'lib/smplkit/config_resolution.rb', line 56 def service_url(scheme, subdomain, base_domain) "#{scheme}://#{subdomain}.#{base_domain}" end |