Use less threads, they're expensive [#9 state:closed]
[amazing.git] / lib / amazing / widget.rb
bloba454159ec593bf4dfe698cab1348ee1e195a6423
1 # Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 #    http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 require 'amazing/helpers/lazy_data'
16 require 'amazing/helpers/pango_markup'
17 require 'erb'
19 module Amazing
21   # Raised by widgets, and is then rescued and logged
22   class WidgetError < Exception
23   end
25   # Parent class for widget construction, example:
26   #
27   #   class Clock < Widget
28   #     description "Displays date and time"
29   #     dependency "some/library", "how to get the library (url, gem name...)"
30   #     option :time_format, "Time format as described in DATE(1)", "%R"
31   #     field :time, "Formatted time"
32   #     default "@time"
33   # 
34   #     init do
35   #       @time = Time.now.strftime(@time_format)
36   #       raise WidgetError, "An error occured!" if some_error?
37   #     end
38   #   end
39   class Widget
40     include Helpers::LazyData
41     include Helpers::PangoMarkup
42     include ERB::Util
44     def initialize(opts={})
45       self.class.dependencies.each do |name, description|
46         begin
47           require name
48         rescue LoadError
49           begin
50             require 'rubygems'
51             require name
52           rescue LoadError
53             raise WidgetError, "Missing dependency #{name.inspect}#{if description then " [#{description}]" end}"
54           end
55         end
56       end
57       self.class.options.each do |key, value|
58         instance_variable_set "@#{key}".to_sym, value[:default]
59       end
60       opts.each do |key, value|
61         instance_variable_set "@#{key}".to_sym, value
62       end
63       self.class.fields.each do |key, value|
64         instance_variable_set "@#{key}".to_sym, value[:default]
65       end
66       self.class.init.each do |block|
67         instance_eval(&block)
68       end
69       @default = case self.class.default
70       when Proc
71         instance_eval(&self.class.default)
72       when String
73         instance_eval(self.class.default)
74       end
75     end
77     def self.description(description=nil)
78       if description
79         @description = description
80       else
81         @description
82       end
83     end
85     def self.dependency(name, description=nil)
86       @dependencies ||= {}
87       @dependencies[name] = description
88     end
90     def self.dependencies
91       @dependencies || {}
92     end
94     def self.option(name, description=nil, default=nil)
95       @options ||= {}
96       @options[name] = {:description => description, :default => default}
97     end
99     def self.options
100       @options || {}
101     end
103     def self.field(name, description=nil, default=nil)
104       @fields ||= {}
105       @fields[name] = {:description => description, :default => default}
106     end
108     def self.fields
109       @fields || {}
110     end
112     def self.default(format=nil, &block) # :yields:
113       if format
114         @default = format
115       elsif block
116         @default = block
117       else
118         @default
119       end
120     end
122     def self.init(&block) # :yields:
123       if block
124         @init ||= []
125         @init << block
126       else
127         @init
128       end
129     end
131     def formatize(format=nil)
132       ERB.new(case format
133       when Proc
134         instance_eval(&format)
135       when String
136         instance_eval(format)
137       else
138         case self.class.default
139         when Proc
140           instance_eval(&self.class.default)
141         when String
142           instance_eval(self.class.default)
143         end
144       end.to_s).result(binding())
145     end
146   end