Module: LapisLazuli::WorldModule::Config

Extended by:
ClassMethods
Included in:
LapisLazuli, Browser, Logging, Proxy, Variable
Defined in:
lib/lapis_lazuli/world/config.rb

Overview

Module with configuration loading related functions

Manages the following:

@config          - internal configuration representation
config_files     - Needs to be set before config can be accessed.
@env             - loaded/detected config/test environment

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Methods included from ClassMethods

add_config, config_file, config_file=, config_files

Instance Method Details

#add_config_from_file(filename) ⇒ Object

Loads a config file

Supports: YML, JSON

Adds the possibility to merge multiple config files.



172
173
174
175
176
# File 'lib/lapis_lazuli/world/config.rb', line 172

def add_config_from_file(filename)
  @config = {} if @config.nil?
  # Add the data to the global config
  @config.deep_merge! get_config_from_file(filename)
end

#config(variable = false, default = (no_default_set=true; nil)) ⇒ Object

Get the configuration from the config, uses a dot seperator for object traversing

Example: ll.config(“test.google.url”) => “www.google.com

Raises error if traversing the object is impossible



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/lapis_lazuli/world/config.rb', line 227

def config(variable=false, default=(no_default_set=true; nil))
  # Make sure the configured configuration is loaded, if possible
  init

  # No variable given? Return the entire object.
  result = @config
  if not variable
    return result
  end

  # Environment variables for known options override the option.
  if CONFIG_OPTIONS.has_key? variable
    var = variable.upcase
    if ENV.has_key? var
      return ENV[var]
    end
  end

  # Otherwise try to find it in the configuration object
  variable.split(".").each do |part|
    if no_default_set == true && result.nil?
      raise "Unknown configuration variable '#{variable}' and no default given!"
    end
    break if result.nil?
    begin
      result = result[part]
    rescue TypeError, NoMethodError => ex
      warn "Could not read configuration variable #{variable}: #{ex}"
      break
    end
  end

  if default.nil? and result.nil?
    if CONFIG_OPTIONS.has_key? variable
      return CONFIG_OPTIONS[variable][0]
    elsif no_default_set == true
      raise "Unknown configuration variable '#{variable}' and no default given!"
    end
  else
    return result || default
  end
end

#current_envObject

Returns current environment



284
285
286
287
288
# File 'lib/lapis_lazuli/world/config.rb', line 284

def current_env
  init

  return @env
end

#env(variable = false, default = (no_default_set=true; nil)) ⇒ Object

Get a environment variable from the config file Alias for ll.config(ll.env + “.” + variable)



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/lapis_lazuli/world/config.rb', line 293

def env(variable=false, default=(no_default_set=true; nil))
  # Make sure the configured configuration is loaded, if possible
  init

  if not variable
    return self.config(@env)
  end

  # Environment variables for known options override environment specific
  # options, too
  env_var = var_from_env(variable, default)
  if env_var != default
    return env_var
  end

  result = self.config("#{@env}.#{variable}", default)

  if no_default_set == true and result.nil?
    raise "Unknown environment variable '#{@env}.#{variable}' and no default given"
  end

  return result

end

#env_or_config(variable, default = (no_default_set=true; nil)) ⇒ Object

Get a variable from the config First checks the environment section, before it checks the global part



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/lapis_lazuli/world/config.rb', line 330

def env_or_config(variable, default=(no_default_set=true; nil))
  # Make sure the configured configuration is loaded, if possible
  init

  # Environment variables for known options override environment specific
  # options, too
  env_var = var_from_env(variable, default)
  if env_var != default
    return env_var
  end

  if self.has_env?(variable)
    return self.env(variable)
  elsif self.has_config?(variable)
    return self.config(variable)
  else
    if no_default_set == true
      raise "Unknown environment or configuration variable '(#{@env}.)#{variable}' and no default given"
    end
    return default
  end
end

#get_config_from_file(filename) ⇒ Object

returns the data that’s loaded from a config file. Supports YAML and JSON



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/lapis_lazuli/world/config.rb', line 180

def get_config_from_file(filename)
  # Try to load the file from disk
  begin
    # Determine the extension
    ext = File.extname(filename)
    # Use the correct loader
    if ext == ".yml"
      data = YAML.load_file(filename)
    elsif ext == ".json"
      json = File.read(filename)
      data = JSON.parse(json)
    end
  rescue Exception => e
    raise "Error loading file: #{filename} #{e}"
  end

  # Fix up empty files
  if data.nil? or data == false
    warn "Could not load configuration from '#{Config.config_files}'; it might be empty or malformed."
    data = {}
  end
  return data
end

#has_config?(variable) ⇒ Boolean

Does the config have a variable? Uses config and catches any errors it raises

Returns:

  • (Boolean)


207
208
209
210
211
212
213
214
215
216
217
# File 'lib/lapis_lazuli/world/config.rb', line 207

def has_config?(variable)
  # Make sure the configured configuration is loaded, if possible
  init

  begin
    value = self.config(variable)
    return (not value.nil?)
  rescue RuntimeError => err
    return false
  end
end

#has_env?(variable) ⇒ Boolean

Does the environment have a certain config variable

Returns:

  • (Boolean)


272
273
274
275
276
277
278
279
280
# File 'lib/lapis_lazuli/world/config.rb', line 272

def has_env?(variable)
  # Make sure the configured configuration is loaded, if possible
  init

  if @env.nil?
    return false
  end
  return self.has_config?("#{@env}.#{variable}")
end

#has_env_or_config?(variable) ⇒ Boolean

Checks if a variabl exist in the env or config

Returns:

  • (Boolean)


320
321
322
323
324
325
# File 'lib/lapis_lazuli/world/config.rb', line 320

def has_env_or_config?(variable)
  # Make sure the configured configuration is loaded, if possible
  init

  return self.has_env?(variable) || self.has_config?(variable)
end

#initObject

The configuration is not a singleton, precisely, but it does not need to be created more than once. Note that explicitly calling load_config will still work to overwrite an existing configuration.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/lapis_lazuli/world/config.rb', line 56

def init
  # Guard against doing this more than once.
  unless @config.nil?
    return
  end

  if Config.config_files.nil?
    raise "No configuration file provided, set LapisLazuli::WorldModule::Config.config_files"
  end

  load_config(Config.config_files)
  # In case there was no config file found an empty @config needs to be set to prevent infinite looping.
  if @config.nil?
    warn 'Unable to find a configuration file, defaulting to empty config.yml.'
    @config = {}
  end

  @metadata = Runtime.instance.set_if(self, :metadata) do
    log.debug "Creating metadata storage"
    Storage.new("metadata")
  end
end

#load_config(config_names) ⇒ Object

Loads a config based on a filename

Supports: YML, JSON

Example:

ENV['TEST_ENV'] = 'production'
load_config("config/config.yml")

Will try to load the following files:

  • config/config-production.yml

  • config/config-debug.yml

  • config/config-test.yml

  • config/config-local.yml

  • config/config.yml

Throws errors if:

  • Config file isn’t readable

  • Environment doesn’t exist in config

  • Default environment not set in config if no environment is set



107
108
109
110
111
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
161
162
163
# File 'lib/lapis_lazuli/world/config.rb', line 107

def load_config(config_names)
  # Go trough each config_name
  config_names.each do |config_name|
    files = []
    # Split the filename
    ext = File.extname(config_name)
    dir, filename = File.split(config_name)
    basename = File.basename(filename, ext)

    # What are the suffixes to check
    suffixes = %w(debug test local)

    if ENV["TEST_ENV"]
      @env = ENV["TEST_ENV"]
    end

    # Do we have an environment
    unless @env.nil?
      # Add it to the suffixes
      suffixes.unshift(@env)
    end

    # Turn suffixes into files to try
    suffixes.each do |suffix|
      files << "#{dir}#{File::SEPARATOR}#{basename}-#{suffix}#{ext}"
    end
    files << config_name
    # Try all files in order
    files.each do |file|
      # Check if files exist
      if File.file?(file)
        begin
          # Try to load a config file
          self.add_config_from_file(file)
          break
        rescue Exception => e
          raise e
        end
      end
    end
  end
  # If we have an environment, the config should contain it
  if not @env.nil? and not self.has_config?(@env)
    raise "Environment `#{@env}` doesn't exist in any of the config files"
  end

  # If we don't have one then load the default
  if @env.nil? and self.has_config?("default_env")
    tmp = self.config("default_env")
    if self.has_config?(tmp)
      @env = tmp
      ENV['TEST_ENV'] = tmp
    else
      raise "Default environment not present in any of the config files"
    end
  end
end

#metadataObject



79
80
81
82
83
84
# File 'lib/lapis_lazuli/world/config.rb', line 79

def 
  if @metadata.nil?
    raise "No metadata available"
  end
  return @metadata
end

#var_from_env(var, default = nil) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/lapis_lazuli/world/config.rb', line 353

def var_from_env(var, default=nil)
  # Simple solution for single depth variables like "browser"
  if ENV.has_key? var
    return ENV[var]
  end

  value = default

  # Variables like:
  #  var_from_env("remote.url","http://test.test")
  if var.is_a? String and
    not default.is_a? Hash

    # Env variables cannot contain a . replace them by _
    key_wanted = var.gsub(".", "__")

    # Do a case insensitive compare
    ENV.keys.each do |key|
      if key.casecmp(key_wanted) == 0
        value = ENV[key]
        break
      end
    end

    # Environment:
    #   REMOTE__USER=test
    #   REMOTE__PASS=test
    #   REMOTE__PROXY__HTTP=http://test.com
    #
    # Call:
    #   var_from_env("remote",{})
    #
    # Result:
    #   {"USER" => "test",
    #    "PASS" => "test",
    #    "proxy" => {"HTTP" => "http://test.con"}}
  elsif default.is_a? Hash
    # Env variables cannot contain a . replace them by _
    key_wanted = var.gsub(".", "__")
    # Use a regular expression starting with the wanted key
    rgx = Regexp.new("^#{key_wanted}", "i")

    result = {}
    # For each key check if it matched the regexp
    ENV.keys.each do |key|
      if (key =~ rgx) == 0
        tmp = result
        # Remove start and split into parts
        parts = key.sub(rgx, "").split("__")
        # Remove empty start if needed
        if parts[0].to_s.empty?
          parts.shift
        end

        # For each part
        parts.each_with_index do |part, index|
          # Final part should store the value in the hash
          if index == parts.length - 1
            tmp[part] = ENV[key]
          else
            # Otherwise, downcase the partname
            part.downcase!
            # Set it to an object if needed
            if !tmp.has_key? part
              tmp[part] = {}
            end
            # Assign tmp to the new hash
            tmp = tmp[part]
          end
        end
      end
    end

    # If we have set keys in the result return it
    if result.keys.length > 0
      return result
    end
  end

  return value
end