Module: RConfig::CoreMethods

Includes:
Constants
Included in:
RConfig
Defined in:
lib/rconfig/core_methods.rb

Constant Summary

Constants included from Constants

RConfig::Constants::CNF_FILE_TYPES, RConfig::Constants::CONFIG_FILE_TYPES, RConfig::Constants::CONFIG_ROOT, RConfig::Constants::EMPTY_ARRAY, RConfig::Constants::ENV_TIER, RConfig::Constants::HOSTNAME, RConfig::Constants::HOSTNAME_SHORT, RConfig::Constants::SUFFIXES, RConfig::Constants::XML_FILE_TYPES, RConfig::Constants::YML_FILE_TYPES

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

Short-hand access to config file by its name.

Example:

RConfig.provider(:foo) => RConfig.with_file(:provider).foo
RConfig.provider.foo   => RConfig.with_file(:provider).foo


268
269
270
271
272
# File 'lib/rconfig/core_methods.rb', line 268

def method_missing(method, * args)
  value = with_file(method, * args)
  logger.debug "#{self}.method_missing(#{method.inspect}, #{args.inspect}) => #{value.inspect}"
  value
end

Instance Method Details

#[](key, file = :application) ⇒ Object

This method provides shorthand to retrieve configuration data that is global in scope, and used on an application or environment-wide level. The default location that it checks is the application file. The application config file is a special config file that should be used for config data that is broad in scope and used throughout the application. Since RConfig gives special regard to the application config file, thought should be given to whatever config information is placed there.

Most config data will be specific to particular part of the application (i.e. database, web service), and should therefore be placed in its own specific config file, such as database.yml, or services.xml

This method also acts as a wrapper for ENV. If no value is returned from the application config, it will also check ENV for a value matching the specified key.

Ex.1 RConfig =>

RConfig.application[:test_mode] ||
RConfig.application.test_mode

Ex.2 RConfig => ENV

NOTE: The application config file can be in any of

the supported formats (yml, xml, conf, etc.)


224
225
226
# File 'lib/rconfig/core_methods.rb', line 224

def [](key, file=:application)
  with_file(file, key) || ENV[key.to_s.upcase]
end

#check_for_changes(name = nil) ⇒ Object

If name is specified, checks that file for changes and reloads it if there are. Otherwise, checks all files in the cache, reloading the changed files.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rconfig/core_methods.rb', line 164

def check_for_changes(name=nil)
  changed = []
  if name == nil
    self.cache_hash.keys.dup.each do |name|
      if reload_on_change(name)
        changed << name
      end
    end
  else
    name = name.to_s
    if reload_on_change(name)
      changed << name
    end
  end
  logger.debug "check_for_changes(#{name.inspect}) => #{changed.inspect}"
  changed
end

#config_changed?(name) ⇒ Boolean

Returns whether or not the config for the given config name has changed since it was last loaded.

Returns true if any files for config have changes since last load.

Returns:

  • (Boolean)


131
132
133
134
135
# File 'lib/rconfig/core_methods.rb', line 131

def config_changed?(name)
  logger.debug "config_changed?(#{name.inspect})"
  name = name.to_s
  !(self.cache_files[name] === get_config_files(name))
end

#config_files(name) ⇒ Object

Return the config file information for the given config name.



120
121
122
# File 'lib/rconfig/core_methods.rb', line 120

def config_files(name)
  self.cache_files[name] ||= get_config_files(name)
end

#config_for(name) ⇒ Object

Get a hash of merged config data. Will auto check every 5 minutes, for longer running apps, unless reload is disabled.



252
253
254
255
256
257
258
# File 'lib/rconfig/core_methods.rb', line 252

def config_for(name)
  name = name.to_s
  check_for_changes(name) if auto_check?(name)
  data = get_config_data(name)
  logger.debug "config_for(#{name.inspect}) => #{data.inspect}"
  data
end

#get_config_data(name) ⇒ Object

Get the merged config hash for the named file. Returns a cached indifferent access faker hash merged from all config files for a name.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rconfig/core_methods.rb', line 143

def get_config_data(name)
  logger.debug "get_config_data(#{name.inspect})"

  name = name.to_s
  unless result = self.cache_hash[name]
    result = self.cache_hash[name] =
        make_indifferent(
            merge_hashes(
                load_config_files(name)
            )
        )
    logger.debug "get_config_data(#{name.inspect}): reloaded"
  end

  result
end

#get_config_files(name) ⇒ Object

Returns a list of all relevant config files as specified by suffixes list. Each element is an Array, containing:

[ 
  "server",              # The base name of the 
  "server_production",   # The suffixed name
  "/path/to/server.yml", # The absolute path to the file 
  <Wed Apr 09 08:53:14>  # The last modified time of the file or nil, if it doesn't exist.
]


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rconfig/core_methods.rb', line 95

def get_config_files(name)
  files = []

  self.load_paths.reverse.each do |directory|
    # splatting *suffix allows us to deal with multipart suffixes
    name_no_overlay, suffixes = suffixes_for(name)
    suffixes.map { |suffix| [name_no_overlay, *suffix].compact.join('_') }.each do |name_with_suffix|
      self.file_types.each do |ext|
        filename = filename_for_name(name_with_suffix, directory, ext)
        if File.exists?(filename)
          modified_time = File.stat(filename).mtime
          files << [name, name_with_suffix, filename, ext, modified_time]
        end
      end
    end
  end

  logger.debug "get_config_files(#{name}) => #{files.select { |x| x[3] }.inspect}"

  files
end

#load_config_files(name, force = false) ⇒ Object

Get each config file’s yaml hash for the given config name, to be merged later. Files will only be loaded if they have not been loaded before or the files have changed within the last five minutes, or force is explicitly set to true.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rconfig/core_methods.rb', line 14

def load_config_files(name, force=false)
  name = name.to_s

  # Return last config file hash list loaded,
  # if reload is disabled and files have already been loaded.
  return self.cache_config_files[name] if self.reload_disabled? && self.cache_config_files[name]

  logger.info "Loading config files for: #{name}"
  logger.debug "load_config_files(#{name.inspect})"

  # Get current time for checking last loaded status.
  now = Time.now

  # Get array of all the existing files file the config name.
  config_files = self.get_config_files(name)

  # Get all the data from all yaml files into as configs
  configs = config_files.collect do |f|
    name, name_with_suffix, filename, ext, modified_time = * f

    # Get the cached file info the specific file, if
    # it's been loaded before.
    config_data, last_modified, last_loaded = self.cache[filename]

    logger.debug "f = #{f.inspect}\n" +
      "cache #{name_with_suffix} filename      = #{filename.inspect}\n" +
      "cache #{name_with_suffix} config_data   = #{config_data.inspect}\n" +
      "cache #{name_with_suffix} last_modified = #{last_modified.inspect}\n" +
      "cache #{name_with_suffix} last_loaded   = #{last_loaded.inspect}\n"

    # Load the file if its never been loaded or its been more than
    # so many minutes since last load attempt. (default: 5 minutes)
    if config_data.blank? || (now - last_loaded > self.reload_interval)
      if force || config_data.blank? || modified_time != last_modified

        logger.debug "modified_time #{name.inspect} #{filename.inspect} " +
          "changed #{modified_time != last_modified} : #{modified_time.inspect} #{last_modified.inspect}"

        logger.debug "RConfig: loading #{filename.inspect}"

        config_data = read(filename, name, ext)  # Get contents from config file

        logger.debug "RConfig: loaded #{filename.inspect} => #{config_data.inspect}"

        (self.config_loaded ||= {})[name] = config_files  # add files to the loaded files cache

        self.cache[filename] = [config_data, modified_time, now]  # Save cached config file contents, and modified_time.

        logger.debug "cache[#{filename.inspect}] = #{self.cache[filename].inspect}"

        self.cache_hash[name] = nil # Flush merged hash cache.

        self.cache_files[name] = config_files  # Config files changed or disappeared.

      end # if config_data == nil || (now - last_loaded > self.reload_interval)
    end # if force || config_data == nil || modified_time != last_modified

    config_data
  end # config_files.collect
  configs.compact!

  logger.debug "load_config_files(#{name.inspect}) => #{configs.inspect}"

  # Keep last loaded config files around in case self.reload_dsabled.
  self.cache_config_files[name] = configs #unless configs.empty?

  configs
end

#reload_on_change(name) ⇒ Object

If config files have changed, caches are flushed, on_load triggers are run.



184
185
186
187
188
189
190
191
192
193
# File 'lib/rconfig/core_methods.rb', line 184

def reload_on_change(name)
  logger.debug "reload_on_change(#{name.inspect}), reload_disabled=#{self.reload_disabled?}"
  if changed = config_changed?(name) && reload?
    if self.cache_hash[name]
      flush_cache(name)  # flush cached config values.
      fire_on_load(name) # force on_load triggers.
    end
  end
  changed
end

#with_file(name, *args) ⇒ Object

Get the value specified by the args, in the file specified by th name



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/rconfig/core_methods.rb', line 231

def with_file(name, *args)
  logger.debug "with_file(#{name.inspect}, #{args.inspect})"
  result = args.inject(config_for(name)) { |v, i|
    logger.debug "v = #{v.inspect}, i = #{i.inspect}"
    case v
      when Hash
        v[i.to_s]
      when Array
        i.is_a?(Integer) ? v[i] : nil
      else
        nil
    end
  }
  logger.debug "with_file(#{name.inspect}, #{args.inspect}) => #{result.inspect}"
  result
end