Module: Aquarium::Utils::OptionsUtils

Includes:
ArrayUtils, SetUtils
Included in:
Aspects::Aspect, Aspects::Pointcut, Finders::MethodFinder, Finders::PointcutFinder, Finders::TypeFinder
Defined in:
lib/aquarium/utils/options_utils.rb

Overview

OptionsUtils

Support parsing and processing of key-value pairs of options, where the values are always converted to Sets. Types including this module should have their initialize methods call this module’s #init_specification to do the options processing. See its documentation for more details.

Several class methods are included for defining convenience instance methods. For example, for options :foo and :bar, calling:

canonical_options_given_methods :foo, :bar

will define several methods for each option specified, e.g.,:

foo_given    # => returns the value of @specification[:foo]
foo_given?   # => returns true "foo_given" is not nil or empty.
bar_given    # etc...
bar_given?

If you would like corresponding reader and writer methods, pass a list of the keys for which you want these methods defined to one of the following methods:

canonical_option_reader   :foo, :bar   # analogous to attr_reader
canonical_option_writer   :foo, :bar   # analogous to attr_writer
canonical_option_accessor :foo, :bar   # analogous to attr_accessor

For all of these methods, you can also pass CANONICAL_OPTIONS (discussed below) to define methods for all of the “canonical” options, e.g.,

canonical_option_accessor CANONICAL_OPTIONS

These methods are not defined by default to prevent accidentally overriding other methods that you might have defined with the same names. Also, note that the writer methods will convert the inputs to sets, following the conventions for the options and the readers will return the sets. If you want different handling, you’ll have to provide custom implementations.

Note that special-case accessor methods are already defined for the :noop and :logger options (discussed below) where the writers expect single values, not sets, and the readers return the single values. (Yea, it’s a bit inconsistent…)

Finally, these canonical_option_* methods should only be called with the keys for the CANONICAL_OPTIONS. The keys are considered the “canonical options”, while the values for the keys are synonyms that can be used instead.

This module also defines several universal options that will be available to all types that include this module:

:logger

A Ruby standard library Logger used for any messages. A default system-wide logger is used otherwise. The corresponding logger and logger= accessors are defined.

:logger_stream

An an alternative to defining the logger, you can define just the output stream where log output will be written. If this option is specified, a new logger will be created for the instance with this output stream. There are no corresponding accessors; use the appropriate methods on the logger object instead.

:severity

The logging severity level, one of the Logger::Severity values or a corresponding integer value. If this option is specified, a new logger will be created for the instance with this output stream. There are no corresponding accessors; use the corresponding methods on the logger object instead.

:noop => options_hash[:noop] || false

If true, don’t do “anything”, the interpretation of which will vary with the type receiving the option. For example, a type might go through some initialization, such as parsng its options, but do nothing after that. Primarily useful for debugging and testing.

The value can be accessed through the noop and noop= accessors.

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ArrayUtils

#make_array, make_array, #strip_array_nils, strip_array_nils

Methods included from SetUtils

#make_set, #strip_set_nils, strip_set_nils

Instance Attribute Details

#specificationObject (readonly)

Returns the value of attribute specification.



82
83
84
# File 'lib/aquarium/utils/options_utils.rb', line 82

def specification
  @specification
end

Class Method Details

.append_features(clazz) ⇒ Object



227
228
229
230
# File 'lib/aquarium/utils/options_utils.rb', line 227

def self.append_features clazz
  super
  ClassMethods.send :append_features, (class << clazz; self; end)
end

.universal_optionsObject



74
75
76
# File 'lib/aquarium/utils/options_utils.rb', line 74

def self.universal_options
  [:logger_stream, :logger, :severity, :noop]
end

.universal_prepositionsObject



78
79
80
# File 'lib/aquarium/utils/options_utils.rb', line 78

def self.universal_prepositions
  [:for, :on, :in, :within]
end

Instance Method Details

#hashify(options) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/aquarium/utils/options_utils.rb', line 125

def hashify options
  return options if options.kind_of?(Hash)
  new_options = {}
  options = [options] unless options.kind_of?(Array)
  options.each do |x|
    if x.kind_of?(Hash)
      new_options.merge!(x)
    else
      new_options[x] = Set.new([])
    end
  end
  new_options
end

#init_specification(options, canonical_options, additional_allowed_options = []) ⇒ Object

Class #initialize methods call this method to process the input options. Pass an optional block to the method that takes no parameters if you want to do additional processing of the options before init_specification validates the options. The block will have access to the @specification hash built up by init_specification and to a new attribute @original_options, which will be a copy of the original options passed to init_specification (it will be either a hash or an array). Finally, if the block returns a value or an array of values, they will be treated as keys to ignore in the options when they are validated. This is a way of dynamically treating an option as valid that can’t be known in advance. (See Aspect and Pointcut for examples of this feature in use.)



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
122
123
# File 'lib/aquarium/utils/options_utils.rb', line 95

def init_specification options, canonical_options, additional_allowed_options = []
  @canonical_options = canonical_options
  @additional_allowed_options = additional_allowed_options.map{|x| x.respond_to?(:intern) ? x.intern : x}
  @original_options = options.nil? ? {} : options.dup 
  @specification = {}
  options ||= {} 
  options_hash = hashify options
  @canonical_options.keys.each do |key|
    all_related_options = make_array(options_hash[key.intern]) || []
    @canonical_options[key].inject(all_related_options) do |ary, o| 
      ary << options_hash[o.intern] if options_hash[o.intern]
      ary
    end
    @specification[key.intern] = Set.new(all_related_options.flatten)
  end
  
  OptionsUtils::universal_options.each do |uopt| 
    @specification[uopt] = Set.new(make_array(options_hash[uopt])) unless options_hash[uopt].nil? 
  end
  @specification[:noop] ||= Set.new([false])
  set_logger_if_stream_specified     
  set_logger_severity_if_specified   
  set_default_logger_if_not_specified 
  
  ignorables = yield if block_given?
  ignorables = [] if ignorables.nil? 
  ignorables = [ignorables] unless ignorables.kind_of? Array
  validate_options(options_hash.reject {|k,v| ignorables.include?(k)})
end

#validate_options(options) ⇒ Object



139
140
141
142
# File 'lib/aquarium/utils/options_utils.rb', line 139

def validate_options options
  unknowns = options.keys - all_allowed_option_symbols - OptionsUtils::universal_options
  raise Aquarium::Utils::InvalidOptions.new("Unknown options specified: #{unknowns.inspect}") if unknowns.size > 0
end