Class: EnvParser
- Inherits:
-
Object
- Object
- EnvParser
- Defined in:
- lib/env_parser.rb,
lib/env_parser/errors.rb,
lib/env_parser/version.rb
Overview
The EnvParser class simplifies parsing of environment variables as different data types.
Defined Under Namespace
Modules: Types Classes: AutoregisterFileNotFound, Error, TypeAlreadyDefinedError, UnknownTypeError, UnparseableAutoregisterSpec, ValueNotAllowedError, ValueNotConvertibleError
Constant Summary collapse
- AUTOREGISTER_FILE =
The default filename to use for autoregister requests.
'.env_parser.yml'.freeze
- VERSION =
'1.6.1'.freeze
Class Method Summary collapse
-
.add_env_bindings ⇒ ENV
Creates ENV bindings for EnvParser.parse and EnvParser.register proxy methods.
-
.autoregister(filename = nil) ⇒ Hash
Reads an “autoregister” file and registers the ENV constants defined therein.
-
.define_type(name, options = {}) {|value| ... } ⇒ nil
Defines a new type for use as the “as” option on a subsequent EnvParser.parse or EnvParser.register call.
-
.parse(value, options = {}) {|value| ... } ⇒ Object
Interprets the given value as the specified type.
-
.register(name, options = {}) {|value| ... } ⇒ Object
Parses the referenced value and creates a matching constant in the requested context.
Class Method Details
.add_env_bindings ⇒ ENV
Creates ENV bindings for parse and register proxy methods.
The sole difference between these proxy methods and their EnvParser counterparts is that ENV.parse will interpret any value given as an ENV key (as a String), not the given value itself. i.e. ENV.parse(‘XYZ’, …) is equivalent to EnvParser.parse(ENV[‘XYZ’], …)
232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/env_parser.rb', line 232 def add_env_bindings ENV.instance_eval do def parse(name, = {}, &validation_block) EnvParser.parse(self[name.to_s], , &validation_block) end def register(*args) EnvParser.register(*args) end end ENV end |
.autoregister(filename = nil) ⇒ Hash
Reads an “autoregister” file and registers the ENV constants defined therein.
The “autoregister” file is read, parsed as YAML, sanitized for use as a parameter to register_all, and then passed along for processing. The return value from that register_all call is passed through.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/env_parser.rb', line 261 def autoregister(filename = nil) filename ||= AUTOREGISTER_FILE autoregister_spec = Psych.load_file(filename) autoregister_spec.deep_symbolize_keys! autoregister_spec.transform_values! do |spec| sanitized = spec.slice(:as, :named, :within, :if_unset, :from_set) sanitized[:as] = sanitized[:as].to_sym if sanitized.key? :as sanitized[:within] = sanitized[:within].constantize if sanitized.key? :within sanitized end register_all autoregister_spec # Psych raises an Errno::ENOENT on file-not-found. # rescue Errno::ENOENT raise EnvParser::AutoregisterFileNotFound, %(file not found: "#{filename}") # Psych raises a Psych::SyntaxError on unparseable YAML. # rescue Psych::SyntaxError => e raise EnvParser::UnparseableAutoregisterSpec, "malformed YAML in spec file: #{e.}" end |
.define_type(name, options = {}) {|value| ... } ⇒ nil
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/env_parser.rb', line 44 def define_type(name, = {}, &parser) raise(ArgumentError, 'no parsing block given') unless block_given? given_types = (Array(name) + Array([:aliases])).map(&:to_s).map(&:to_sym) given_types.each do |type| raise(TypeAlreadyDefinedError, "cannot redefine #{type.inspect}") if known_types.key?(type) known_types[type] = { parser: parser, if_unset: [:if_unset] } end nil end |
.parse(value, options = {}) {|value| ... } ⇒ Object
Interprets the given value as the specified type.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/env_parser.rb', line 112 def parse(value, = {}, &validation_block) value = ENV[value.to_s] if value.is_a? Symbol value = value.to_s type = known_types[[:as]] raise(ArgumentError, 'missing `as` parameter') unless .key?(:as) raise(UnknownTypeError, "invalid `as` parameter: #{[:as].inspect}") unless type return (.key?(:if_unset) ? [:if_unset] : type[:if_unset]) if value.blank? value = type[:parser].call(value) check_for_set_inclusion(value, set: [:from_set]) if .key?(:from_set) check_user_defined_validations(value, proc: [:validated_by], block: validation_block) value end |
.register(name, options = {}) {|value| ... } ⇒ Object
Parses the referenced value and creates a matching constant in the requested context.
Multiple calls to register may be shortcutted by passing in a Hash whose keys are the variable names and whose values are the options set for each variable’s register call.
# Example shortcut usage:
EnvParser.register :A, from: one_hash, as: :integer
EnvParser.register :B, from: another_hash, as: :string, if_unset: 'none'
# ... is equivalent to ...
EnvParser.register(
A: { from: one_hash, as: :integer }
B: { from: another_hash, as: :string, if_unset: 'none' }
)
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/env_parser.rb', line 191 def register(name, = {}, &validation_block) # Allow for registering multiple variables simultaneously via a single call. if name.is_a? Hash raise(ArgumentError, 'cannot register multiple values with one block') if block_given? return register_all(name) end from = .fetch(:from, ENV) within = .fetch(:within, Kernel) named = name named = .fetch(:named, name) if .key? :within # ENV *seems* like a Hash and it does *some* Hash-y things, but it is NOT a Hash and that can # bite you in some cases. Making sure we're working with a straight-up Hash saves a lot of # sanity checks later on. This is also a good place to make sure we're working with a String # key. if from == ENV from = from.to_h name = name.to_s end raise ArgumentError, "invalid `from` parameter: #{from.class}" unless from.is_a? Hash raise ArgumentError, "invalid `within` parameter: #{within.inspect}" unless within.is_a?(Module) || within.is_a?(Class) value = from[name] value = parse(value, , &validation_block) within.const_set(named.upcase.to_sym, value.dup.freeze) value end |