File: lib/radiant/config/definition.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Radiant#1
  class: Config#2
inherits from
  Base ( ActiveRecord )
  class: Definition#3
inherits from
  Object ( Builtin-Module )
has properties
attribute: empty [R] #5
attribute: default [R] #5
attribute: type [R] #5
attribute: notes [R] #5
attribute: validate_with [R] #5
attribute: select_from [R] #5
attribute: allow_blank [R] #5
attribute: allow_display [R] #5
attribute: allow_change [R] #5
attribute: units [R] #5
attribute: definer [R] #5
method: initialize / 1 #25
method: empty? #34
method: boolean? #41
method: selector? #47
method: integer? #52
method: selection #59
method: normalize_selection / 1 #72
method: selected / 1 #80
method: validate / 1 #93
method: selectable? / 1 #111
method: allow_blank? #118
method: settable? #124
method: visible? #130
method: hidden? #135

Class Hierarchy

Object ( Builtin-Module )
Base ( ActiveRecord )
  Config ( Radiant ) #2
Definition ( Radiant::Config ) — #3

Code

   1  module Radiant
   2    class Config
   3      class Definition
   4        
   5        attr_reader :empty, :default, :type, :notes, :validate_with, :select_from, :allow_blank, :allow_display, :allow_change, :units, :definer
   6 
   7        # Configuration 'definitions' are metadata held in memory that add restriction and description to individual config entries.
   8        #
   9        # By default radiant's configuration machinery is open and ad-hoc: config items are just globally-accessible variables.
  10        # They're created when first mentioned and then available in all parts of the application. The definition mechanism is a way 
  11        # to place limits on that behavior. It allows you to protect a config entry, to specify the values it can take and to 
  12        # validate it when it changes. In the next update it will also allow you to declare that
  13        # a config item is global or site-specific.
  14        #
  15        # The actual defining is done by Radiant::Config#define and usually in a block like this:
  16        #
  17        #   Radiant::Config.prepare do |config|
  18        #     config.namespace('users', :allow_change => true) do |users|
  19        #       users.define 'allow_password_reset?', :label => 'Allow password reset?'
  20        #     end
  21        #   end
  22        #
  23        # See the method documentation in Radiant::Config for options and conventions.
  24        #
  25        def initialize(options={})
  26          [:empty, :default, :type, :notes, :validate_with, :select_from, :allow_blank, :allow_change, :allow_display, :units, :definer].each do |attribute|
  27            instance_variable_set "@#{attribute}".to_sym, options[attribute]
  28          end
  29        end
  30        
  31        # Returns true if the definition included an :empty flag, which should only be the case for the blank, unrestricting
  32        # definitions created when an undefined config item is set or got.
  33        #
  34        def empty?
  35          !!empty
  36        end
  37        
  38        # Returns true if the definition included a :type => :boolean parameter. Config entries that end in '?' are automatically 
  39        # considered boolean, whether a type is declared or not. config.boolean? may therefore differ from config.definition.boolean?
  40        #
  41        def boolean?
  42          type == :boolean
  43        end
  44        
  45        # Returns true if the definition included a :select_from parameter (either as list or proc).
  46        #
  47        def selector?
  48          !select_from.blank?   
  49        end
  50        
  51        # Returns true if the definition included a :type => :integer parameter
  52        def integer?
  53          type == :integer
  54        end
  55        
  56        # Returns the list of possible values for this config entry in a form suitable for passing to options_for_select.
  57        # if :select_from is a proc it is called first with no arguments and its return value passed through.
  58        #
  59        def selection
  60          if selector?
  61            choices = select_from
  62            choices = choices.call if choices.respond_to? :call
  63            choices = normalize_selection(choices)
  64            choices.unshift ["",""] if allow_blank?
  65            choices
  66          end
  67        end
  68        
  69        # in definitions we accept anything that options_for_select would normally take
  70        # here we standardises on an options array-of-arrays so that it's easier to validate input
  71        #
  72        def normalize_selection(choices)
  73          choices = choices.to_a if Hash === choices
  74          choices = choices.collect{|c| (c.is_a? Array) ? c : [c,c]}
  75        end
  76        
  77        # If the config item is a selector and :select_from specifies [name, value] pairs (as hash or array), 
  78        # this will return the name corresponding to the currently selected value.
  79        #
  80        def selected(value)
  81          if value && selector? && pair = selection.find{|s| s.last == value}
  82            pair.first
  83          end
  84        end
  85        
  86        # Checks the supplied value against the validation rules for this definition.
  87        # There are several ways in which validations might be defined or implied:
  88        # * if :validate_with specifies a block, the setting object is passed to the block
  89        # * if :type is :integer, we test that the supplied string resolves to a valid integer
  90        # * if the config item is a selector we test that its value is one of the permitted options
  91        # * if :allow_blank has been set to false, we test that the value is not blank
  92        #
  93        def validate(setting)
  94          if allow_blank?
  95            return if setting.value.blank?
  96          else
  97            setting.errors.add :value, :blank if setting.value.blank?
  98          end
  99          if validate_with.is_a? Proc
 100            validate_with.call(setting)
 101          end
 102          if selector?
 103            setting.errors.add :value, :not_permitted unless selectable?(setting.value)
 104          end
 105          if integer?
 106            Integer(setting.value) rescue setting.errors.add :value, :not_a_number
 107          end
 108        end
 109        
 110        # Returns true if the value is one of the permitted selections. Not case-sensitive.
 111        def selectable?(value)
 112          return true unless selector?
 113          selection.map(&:last).map(&:downcase).include?(value.downcase)
 114        end
 115        
 116        # Returns true unless :allow_blank has been explicitly set to false. Defaults to true.
 117        # A config item that does not allow_blank must be set or it will not be valid.
 118        def allow_blank?
 119          true unless allow_blank == false
 120        end
 121        
 122        # Returns true unless :allow_change has been explicitly set to false. Defaults to true. 
 123        # A config item that is not settable cannot be changed in the running application.
 124        def settable?
 125          true unless allow_change == false
 126        end
 127        
 128        # Returns true unless :allow_change has been explicitly set to false. Defaults to true.
 129        # A config item that is not visible cannot be displayed in a radius tag.
 130        def visible?
 131          true unless allow_display == false
 132        end
 133        
 134        # Returns true if :allow_display has been explicitly set to false. Defaults to true.
 135        def hidden?
 136          true if allow_display == false
 137        end
 138        
 139      end
 140    end
 141  end
 142