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_file      - 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

config_file, config_file=

Instance Method Details

#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



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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/lapis_lazuli/world/config.rb', line 197

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



254
255
256
257
258
# File 'lib/lapis_lazuli/world/config.rb', line 254

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)



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/lapis_lazuli/world/config.rb', line 263

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 = nil) ⇒ Object

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



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/lapis_lazuli/world/config.rb', line 300

def env_or_config(variable, default=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, default)
  elsif self.has_config?(variable)
    return self.config(variable, default)
  else
    return default
  end
end

#has_config?(variable) ⇒ Boolean

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

Returns:

  • (Boolean)


177
178
179
180
181
182
183
184
185
186
187
# File 'lib/lapis_lazuli/world/config.rb', line 177

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)


242
243
244
245
246
247
248
249
250
# File 'lib/lapis_lazuli/world/config.rb', line 242

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)


290
291
292
293
294
295
# File 'lib/lapis_lazuli/world/config.rb', line 290

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.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/lapis_lazuli/world/config.rb', line 41

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

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

  load_config(Config.config_file)

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

#load_config(config_name) ⇒ 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



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
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/lapis_lazuli/world/config.rb', line 82

def load_config(config_name)
  # 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 = [
    "debug",
    "test",
    "local"
  ]

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

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

  # Turn suffixes into files to try
  files = []
  suffixes.each do |suffix|
    files << "#{dir}#{File::SEPARATOR}#{basename}-#{suffix}#{ext}"
  end
  files << config_name

  # Try all files in order
  files.each do |file|
    begin
      # Try to load a config file
      return self.load_config_from_file(file)
    rescue
      # Do nothing, load the next file
    end
  end
end

#load_config_from_file(filename) ⇒ Object

Loads a config file

Supports: YML, JSON

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



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
164
165
166
167
168
169
170
# File 'lib/lapis_lazuli/world/config.rb', line 133

def load_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"
      @config = YAML.load_file(filename)
    elsif ext == ".json"
      json = File.read(filename)
      @config = JSON.parse(json)
    end
  rescue RuntimeError => err
    # Can't help you
    raise "Error loading file: #{filename} #{err}"
  end

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

  # If we have an environment this config should have it
  if not @env.nil? and not self.has_config?(@env)
    raise "Environment doesn't exist in config file"
  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
    else
      raise "Default environment not present in config file"
    end
  end
end

#metadataObject



59
60
61
62
63
64
# File 'lib/lapis_lazuli/world/config.rb', line 59

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

#var_from_env(var, default = nil) ⇒ Object



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
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
# File 'lib/lapis_lazuli/world/config.rb', line 320

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