Add comments to Timer
[god.git] / lib / god / contact.rb
blob5de3181da22bceba5d1af404f3139586b6cdfcde
1 module God
2   
3   class Contact
4     include Configurable
5     
6     attr_accessor :name, :group, :info
7     
8     def self.generate(kind)
9       sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
10       c = God::Contacts.const_get(sym).new
11       
12       unless c.kind_of?(Contact)
13         abort "Contact '#{c.class.name}' must subclass God::Contact" 
14       end
15       
16       c
17     rescue NameError
18       raise NoSuchContactError.new("No Contact found with the class name God::Contacts::#{sym}")
19     end
20     
21     def self.valid?(contact)
22       valid = true
23       valid &= Configurable.complain("Attribute 'name' must be specified", contact) if contact.name.nil?
24       valid
25     end
26     
27     # Normalize the given notify specification into canonical form.
28     #   +spec+ is the notify spec as a String, Array of Strings, or Hash
29     #
30     # Canonical form looks like:
31     # {:contacts => ['fred', 'john'], :priority => '1', :category => 'awesome'}
32     # Where :contacts will be present and point to an Array of Strings. Both
33     # :priority and :category may not be present but if they are, they will each
34     # contain a single String.
35     # 
36     # Returns normalized notify spec
37     # Raises ArgumentError on invalid spec (message contains details)
38     def self.normalize(spec)
39       case spec
40         when String
41           {:contacts => Array(spec)}
42         when Array
43           unless spec.select { |x| !x.instance_of?(String) }.empty?
44             raise ArgumentError.new("contains non-String elements")
45           end
46           {:contacts => spec}
47         when Hash
48           copy = spec.dup
49           
50           # check :contacts
51           if contacts = copy.delete(:contacts)
52             case contacts
53               when String
54                 # valid
55               when Array
56                 unless contacts.select { |x| !x.instance_of?(String) }.empty?
57                   raise ArgumentError.new("has a :contacts key containing non-String elements")
58                 end
59                 # valid
60               else
61                 raise ArgumentError.new("must have a :contacts key pointing to a String or Array of Strings")
62             end
63           else
64             raise ArgumentError.new("must have a :contacts key")
65           end
66           
67           # remove priority and category
68           copy.delete(:priority)
69           copy.delete(:category)
70           
71           # check for invalid keys
72           unless copy.empty?
73             raise ArgumentError.new("contains extra elements: #{copy.inspect}")
74           end
75           
76           # normalize
77           spec[:contacts] &&= Array(spec[:contacts])
78           spec[:priority] &&= spec[:priority].to_s
79           spec[:category] &&= spec[:category].to_s
80           
81           spec
82         else
83           raise ArgumentError.new("must be a String (contact name), Array (of contact names), or Hash (contact specification)")
84       end
85     end
86     
87     # Abstract
88     # Send the message to the external source
89     #   +message+ is the message body returned from the condition
90     #   +time+ is the Time at which the notification was made
91     #   +priority+ is the arbitrary priority String
92     #   +category+ is the arbitrary category String
93     #   +host+ is the hostname of the server
94     def notify(message, time, priority, category, host)
95       raise AbstractMethodNotOverriddenError.new("Contact#notify must be overridden in subclasses")
96     end
97     
98     # Construct the friendly name of this Contact, looks like:
99     #
100     # Contact FooBar
101     def friendly_name
102       super + " Contact '#{self.name}'"
103     end
104   end
105