module CushionDefaults

h2. The Basics

Base module. Should be included in any class that needs the functionality offered by CushionDefaults.

For a detailed introduction, you are strongly encouraged to consult the “README”:file.readme.html.

There are also several short example programs in the @examples/@ folder. (If anyone has any more examples to include, please pass them along!)

And if you would like to run a very simple benchmark of how CushionDefaults compares to similar methods, run @benchmarks/simple_benchmark.rb@.

h2. Automatic Inclusion in Child Classes

When included in a superclass @Klass@, CushionDefaults automatically includes itself in all subclassses that subsequently subclass @Klass@. @example Inclusion in Child Class

class Klass
  include CushionDefaults
end
class SubKlass < Klass
  # includes CushionDefaults automatically
end

Constants

CALLING_PATH

The path of the first file that includes CushionDefaults.

CONFIG_LOCATION

Location CushionDefaults looks here for an (optional) config file, as well as off of the {CALLING_PATH}.

VERSION

Version constant

Public Class Methods

conf() click to toggle source

Return CushionDefaults’ {Configuration} object. @return [Configuration] the module’s configuration object @see Configuration

# File lib/cushion_defaults.rb, line 48
def self.conf
  @conf
end
configuration() click to toggle source

Return CushionDefaults’ {Configuration} object. @return [Configuration] the module’s configuration object @see Configuration

# File lib/cushion_defaults.rb, line 55
def self.configuration
  @conf
end
configure() { |conf| ... } click to toggle source

Yield the module’s configuration object for manipulation.

@yieldparam conf [Configuration] CushionDefault’s {Configuration} object

@example Automatically add and remove {ClassMethods#cushion_reader cushion_reader}s and {ClassMethods#cushion_writer cushion_writer}s.

CushionDefaults.configure do |conf|
  conf.update_readers = true
  conf.update_writers = true
end

@example Configure CushionDefaults for testing or development

CushionDefaults.configure do |conf|
  conf.testing!
end

@see Configuration

# File lib/cushion_defaults.rb, line 119
def self.configure
  yield(@conf)
end
included(base) click to toggle source

Add class methods and set up an @defaults {DefaultsHash} when the module is included in a class. Called automatically.

If {Configuration#auto_load_from_yaml}, then it also searches for a YAML configuration file for the class in the by calling {ClassMethods#defaults_from_yaml defaults_from_yaml}.

@param base [Class] class in which CushionDefaults is included

@api private

# File lib/cushion_defaults.rb, line 132
def self.included(base)

  log("CushionDefaults has been included in #{base}.")

  base.extend(ClassMethods)

  base.send :_set_up_cushion_method_sets

  if @conf.auto_load_from_yaml
    base.defaults_from_yaml
  else
    base.initialize_defaults_hash
  end
end
log(str, level=:debug, caller_method_name=caller[0].to_s) click to toggle source

Logs a message to the logger at {Configuration#logger} as long as {Configuration#record_in_log} is true. @param str [String] message to log. will have caller_method_name, level, and time automatically appended. @param level [Symbol/int] level to log at. Accepts integers (0 to 5) or one of the following symbols: :debug, :info,

:warn, :error, :fatal, :unknown

@param caller_method_name [String] name of the method whose actions are being logged. If nil, the name is determined

programmatically.
# File lib/cushion_defaults.rb, line 65
def self.log(str, level=:debug, caller_method_name=caller[0].to_s)

  # @conf.record_in_log tells us whether we should be logging at all
  return unless @conf.record_in_log

  # If caller_method_name is nil, magically get the name of the calling method
  @conf.logger.progname = caller_method_name unless caller_method_name == ''

  case level
    when :debug, 0
      @conf.logger.debug {str}
    when :fatal, 4
      @conf.logger.fatal {str}
    when :error, 3
      @conf.logger.error {str}
    when :warn, 2
      @conf.logger.warn {str}
    when :info, 1
      @conf.logger.info {str}
    else
      @conf.logger.unknown {str}
  end
end
nilish?(value) click to toggle source

Determine whether a value should be treated as nil or nil-like. If {Configuration#ignore_attempts_to_set_nil} is false, this method always returns false. If that setting is true, then it examines {Configuration#blank_str_is_nil}. If that setting is true, it returns true if value is nil or ” (like ActiveSupport’s @#blank?@) @param value [Object] value to examine @return [boolean] as specified above

@api private

# File lib/cushion_defaults.rb, line 96
def self.nilish?(value)
  # @conf is guaranteed to be defined by the call to self.preliminary_setup below
  # Using the instance variable here gives us surprising performance gains

  @conf.ignore_attempts_to_set_nil && (value.nil? || (value.is_a?(String) && @conf.blank_str_is_nil && value.empty?))
end

Private Class Methods

preliminary_setup() click to toggle source

Loads the optional config file, looking at the various locations specified therein.

# File lib/cushion_defaults.rb, line 193
def self.preliminary_setup
  local_conf_path = CALLING_PATH + @conf.yaml_source_folder + 'cushion_defaults.yaml'
  if File.exists?(CONFIG_LOCATION)
    t = File.open(CONFIG_LOCATION)
    log("Found and opened config file at #{CONFIG_LOCATION}", :info)
  elsif File.exists?(local_conf_path)
    t = File.open(local_conf_path)
    log("Found and opened config file at #{local_conf_path}", :info)
  else
    t = nil
    log("No config file found. Looked at #{CONFIG_LOCATION} and #{local_conf_path}.", :info)
  end

  @conf.from_hash(YAML::load(t)) if t
end

Public Instance Methods

crystallize_default(default_key, act_if_nilish=true) click to toggle source

‘Crystallize’ the default: i.e., if this instance does not have @sym@ specified, then set the value of @sym@ explicitly to the default value.

This is most useful if you want to update the default value for @sym@ but do not want to affect one or more already exsiting instances of the class.

@param default_key [#to_sym] default to crystallize for this object @param act_if_nilish [boolean] if true, allows for {CushionDefaults.nilish?} checks. If false, #{CushionDefaults.nilish?}

is not called at all.
# File lib/cushion_defaults.rb, line 178
def crystallize_default(default_key, act_if_nilish=true)
  default_key = default_key.to_sym
  # crystallize if either (1) there is no value specified for :default_key, or (2) there is a value specified, but we are
  # acting if a nilish value is specified and the value for :default_key is nilish.
  if !has_specified? default_key || (act_if_nilish && CushionDefaults.nilish?(instance_variable_get("@#{default_key}")))
    default_value = default(default_key)
    instance_variable_set("@#{default_key}", default_value.respond_to?(:call) ? default_value.call(self, default_key) : default_value)
  else
    log("Did not update #{default_key}")
  end
end
default(sym) click to toggle source

Returns the default value for sym, going up the chain of cascaded defaults. @param sym [Symbol] the variable whose default value is desired. @return [Object] the default specified for sym in self.class @example Default for :first

Klass.new.default(:first) == Klass.defaults[:first] # true
# File lib/cushion_defaults.rb, line 158
def default(sym)
  defaults[sym]
end
defaults() click to toggle source

Get class {DefaultsHash}. If @x@ is a @Klass@, then @x#defaults@ returns @Klass.defaults@. @return [DefaultsHash] the defaults for self.class

# File lib/cushion_defaults.rb, line 149
def defaults
  self.class.defaults
end
has_specified?(sym) click to toggle source

Wraps (in somewhat more convenient form) @Object#instance_variable_defined?@. @param sym [#to_s] String or coercable object that denotes the instance variable in question @return [boolean] true if the instance variable denoted by sym is defined, false otherwise

# File lib/cushion_defaults.rb, line 165
def has_specified?(sym)
  instance_variable_defined?("@#{sym}")
end