Class: CheapAdvice::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/cheap_advice/configuration.rb

Defined Under Namespace

Classes: Error

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = nil) ⇒ Configuration

Returns a new instance of Configuration.



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cheap_advice/configuration.rb', line 26

def initialize opts = nil
  opts ||= EMPTY_Hash
  @verbose = false
  opts.each do | k, v |
    send(:"#{k}=", v)
  end
  @advice ||= { }
  @targets = [ ]
  @advised = [ ]
  @required = { }
end

Instance Attribute Details

#adviceObject

Hash mapping advice names to CheapAdvice objects.



12
13
14
# File 'lib/cheap_advice/configuration.rb', line 12

def advice
  @advice
end

#advisedObject

Array of CheapAdvice::Advised methods.



15
16
17
# File 'lib/cheap_advice/configuration.rb', line 15

def advised
  @advised
end

#configObject

Configuration input hash.



9
10
11
# File 'lib/cheap_advice/configuration.rb', line 9

def config
  @config
end

#config_changedObject Also known as: config_changed?

Flag



21
22
23
# File 'lib/cheap_advice/configuration.rb', line 21

def config_changed
  @config_changed
end

#requiredObject

Hash of file names that were explicity required before applying advice.



18
19
20
# File 'lib/cheap_advice/configuration.rb', line 18

def required
  @required
end

#verboseObject

Returns the value of attribute verbose.



24
25
26
# File 'lib/cheap_advice/configuration.rb', line 24

def verbose
  @verbose
end

Instance Method Details

#_log(msg = nil) ⇒ Object



144
145
146
147
148
149
# File 'lib/cheap_advice/configuration.rb', line 144

def _log msg = nil
  return self unless @verbose
  msg ||= yield if block_given?
  $stderr.puts "#{self.class}: #{msg}"
  self
end

#annotate_error(x) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/cheap_advice/configuration.rb', line 151

def annotate_error x
  yield
rescue Exception => err
  msg = "in #{x.inspect}: #{err.inspect}"
  _log { "ERROR: #{msg}\n  #{err.backtrace * "\n  "}" }
  raise Error, msg, err.backtrace
end

#as_array(x) ⇒ Object



170
171
172
173
174
175
# File 'lib/cheap_advice/configuration.rb', line 170

def as_array x
  x = EMPTY_Array if x == nil
  x = x.split(/\s+|\s*,\s*/) if String === x
  raise "Unexpected Hash" if Hash === x
  x
end

#config_changed!Object



38
39
40
41
# File 'lib/cheap_advice/configuration.rb', line 38

def config_changed!
  @config_changed = true
  self
end

#configure!Object



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
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/cheap_advice/configuration.rb', line 51

def configure!
  disable!

  # First pass: parse target and defaults.
  c = [ ]
  d = { }
  get_config.each do | target_name, target_config |
    annotate_error "target=#{target_name}" do
      t = parse_target(target_name)
      # _log { "#{target_name.inspect} => #{t.inspect}" }
      case target_config
      when true, false
        target_config = { :enabled => target_config }
      end
      t.update(target_config) if target_config
      [ :advice, :require ].each do | k |
        t[k] = as_array(t[k]) if t.key?(k)
      end
      case
      when t[:meth].nil? && t[:mod].nil? # global default.
        d[nil] = t
      when t[:meth].nil? # module default.
        d[t[:mod]] = t
      else
        c << t # real target
      end
    end
  end
  d[nil] ||= { }

  # Second pass: merge defaults with target.
  @targets = [ ]
  c.each do | t |
    x = merge!(d[nil].dup, d[t[:mod]] || EMPTY_Hash)
    t = merge!(x, t)
    # _log { "target = #{t.inspect}" }
    next if t[:enabled] == false
    @targets << t
  end

  enable!

  self
end

#configure_if_changed!Object



43
44
45
46
47
48
49
# File 'lib/cheap_advice/configuration.rb', line 43

def configure_if_changed!
  if config_changed?
    configure!
    @config_changed = false
  end
  self
end

#disable!Object



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cheap_advice/configuration.rb', line 96

def disable!
  @targets.each do | t |
    (t[:advice] || EMPTY_Array).each do | advice_name |
      advice_name = advice_name.to_sym
      if advised = (t[:advised] || EMPTY_Hash)[advice_name]
        advised.disable!
      end
    end
  end
  @advised.clear
  self
end

#enable!Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/cheap_advice/configuration.rb', line 109

def enable!
  @advised.clear
  @targets.each do | t |
    t_str = target_as_string(t)
    annotate_error "target=#{t_str.inspect}" do
      (t[:require] || EMPTY_Array).each do | r |
        _log { "#{t_str}: require #{r}" }
        unless @required[r]
          require r
          @required[r] = true
        end
      end
    end
        
    (t[:advice] || EMPTY_Array).each do | advice_name |
      advice_name = advice_name.to_sym
      annotate_error "target=#{target_as_string(t)} advice=#{advice_name.inspect}" do
        unless advice = @advice[advice_name]
          raise Error, "no advice by that name"
        end
        options = t[:options][nil]
        options = merge!(options, t[:options][advice_name])
        # _log { "#{t.inspect} options => #{options.inspect}" }
        
        advised = advice.advise!(t[:mod], t[:meth], t[:kind], options)

        (t[:advised] ||= { })[advice_name] = advised

        @advised << advised
      end
    end
  end
  self
end

#get_configObject



159
160
161
162
163
164
165
166
167
168
# File 'lib/cheap_advice/configuration.rb', line 159

def get_config
  case @config
  when Hash
    @config
  when Proc
    @config.call(self)
  when nil
    raise Error, "no config"
  end
end

#merge!(dst, src) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/cheap_advice/configuration.rb', line 198

def merge! dst, src
  case dst
  when nil, Hash
    case src
    when Hash
      dst = dst ? dst.dup : { }
      src.each do | k, v |
        dst[k] = merge!(dst[k], v)
      end
    else
      dst = src
    end
  else
    dst = src
  end
  dst
end

#parse_target(x) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/cheap_advice/configuration.rb', line 177

def parse_target x
  case x
  when nil
    { }
  when Hash
    x
  when String, Symbol
    if x.to_s =~ /\A([a-z0-9_:]+)(?:([#\.])([a-z0-9_]+[=\!\?]?))?\Z/i
      { :mod => $1,
        :kind => $2 && ($2 == '.' ? :module : :instance),
        :meth => $3,
      }
    else
      raise Error, "cannot parse #{x.inspect}"
    end
  end
end

#target_as_string(t) ⇒ Object



194
195
196
# File 'lib/cheap_advice/configuration.rb', line 194

def target_as_string t
  "#{t[:mod]}#{t[:kind] == :instance ? '#' : '.'}#{t[:meth]}"
end