rugui 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/LICENSE +165 -0
  2. data/README +67 -0
  3. data/README.rdoc +67 -0
  4. data/Rakefile +56 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/rugui +16 -0
  7. data/lib/rugui/base_controller.rb +194 -0
  8. data/lib/rugui/base_model.rb +22 -0
  9. data/lib/rugui/base_object.rb +73 -0
  10. data/lib/rugui/base_view.rb +302 -0
  11. data/lib/rugui/base_view_helper.rb +23 -0
  12. data/lib/rugui/configuration.rb +136 -0
  13. data/lib/rugui/framework_adapters/GTK.rb +233 -0
  14. data/lib/rugui/framework_adapters/Qt4.rb +171 -0
  15. data/lib/rugui/framework_adapters/base_framework_adapter.rb +90 -0
  16. data/lib/rugui/framework_adapters/framework_adapter_support.rb +35 -0
  17. data/lib/rugui/gem_builder.rb +21 -0
  18. data/lib/rugui/gem_dependency.rb +282 -0
  19. data/lib/rugui/initialize_hooks.rb +36 -0
  20. data/lib/rugui/initializer.rb +162 -0
  21. data/lib/rugui/log_support.rb +118 -0
  22. data/lib/rugui/observable_property_proxy.rb +73 -0
  23. data/lib/rugui/observable_property_support.rb +251 -0
  24. data/lib/rugui/plugin/loader.rb +77 -0
  25. data/lib/rugui/property_observer.rb +58 -0
  26. data/lib/rugui/signal_support.rb +57 -0
  27. data/lib/rugui/tasks/gems_application.rake +71 -0
  28. data/lib/rugui/tasks/rugui.rb +8 -0
  29. data/lib/rugui/tasks/rugui_framework.rb +4 -0
  30. data/lib/rugui/tasks/runner_application.rake +4 -0
  31. data/lib/rugui/tasks/spec_application.rake +64 -0
  32. data/lib/rugui/tasks/spec_framework.rake +27 -0
  33. data/lib/rugui/tasks/test_application.rake +77 -0
  34. data/lib/rugui/vendor_gem_source_index.rb +140 -0
  35. data/lib/rugui/version.rb +9 -0
  36. data/lib/rugui.rb +37 -0
  37. data/spec/framework/base_controller_spec.rb +48 -0
  38. data/spec/framework/base_model_spec.rb +13 -0
  39. data/spec/framework/base_view_helper_spec.rb +13 -0
  40. data/spec/framework/base_view_spec.rb +92 -0
  41. data/spec/framework/log_support_spec.rb +16 -0
  42. data/spec/framework/observable_property_proxy_spec.rb +67 -0
  43. data/spec/framework/observable_property_support_spec.rb +283 -0
  44. data/spec/framework/property_observer_spec.rb +88 -0
  45. data/spec/helpers/controllers.rb +29 -0
  46. data/spec/helpers/initialize_hooks_helper.rb +18 -0
  47. data/spec/helpers/models.rb +9 -0
  48. data/spec/helpers/observables.rb +210 -0
  49. data/spec/helpers/view_helpers.rb +9 -0
  50. data/spec/helpers/views.rb +72 -0
  51. data/spec/rcov.opts +1 -0
  52. data/spec/resource_files/my_other_view.glade +46 -0
  53. data/spec/resource_files/my_view.glade +46 -0
  54. data/spec/spec.opts +4 -0
  55. data/spec/spec_helper.rb +15 -0
  56. metadata +149 -0
@@ -0,0 +1,162 @@
1
+ require 'rugui'
2
+ require 'rugui/gem_dependency'
3
+
4
+ module RuGUI
5
+ class Initializer
6
+ include RuGUI::LogSupport
7
+
8
+ # The configuration for this application.
9
+ attr_reader :configuration
10
+
11
+ # Whether or not all the gem dependencies have been met
12
+ attr_reader :gems_dependencies_loaded
13
+
14
+ @@processed = false
15
+
16
+ # Runs the initializer.
17
+ #
18
+ # It runs the process procedure by default, by this can be changed by
19
+ # specifying a command when calling this method. A block can be given
20
+ # in order to change the application configuration.
21
+ #
22
+ def self.run(command = :process, configuration = Configuration.new)
23
+ yield configuration if block_given?
24
+ initializer = new configuration
25
+ RuGUI.configuration = configuration
26
+ initializer.send(command)
27
+ @@processed = (command == :process) ? true : false
28
+ initializer
29
+ end
30
+
31
+ # Create a new Initializer instance that references the given Configuration
32
+ # instance.
33
+ def initialize(configuration)
34
+ @configuration = configuration
35
+ end
36
+
37
+ # Sequentially step through all of the available initialization routines,
38
+ # in order (view execution order in source).
39
+ def process
40
+ load_environment
41
+ load_logger
42
+
43
+ start_initialization_process_log
44
+
45
+ set_load_path
46
+ add_gem_load_paths
47
+
48
+ set_autoload_paths
49
+ load_framework_adapter
50
+
51
+ load_gems
52
+ load_plugins
53
+
54
+ # pick up any gems that plugins depend on
55
+ add_gem_load_paths
56
+ load_gems
57
+ check_gem_dependencies
58
+
59
+ # bail out if gems are missing - note that check_gem_dependencies will have
60
+ # already called abort() unless $gems_rake_task is set
61
+ return unless gems_dependencies_loaded
62
+
63
+ finish_initialization_process_log
64
+ end
65
+
66
+ # Set the <tt>$LOAD_PATH</tt> based on the value of
67
+ # Configuration#load_paths. Duplicates are removed.
68
+ def set_load_path
69
+ load_paths = configuration.load_paths
70
+ load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
71
+ $LOAD_PATH.uniq!
72
+ end
73
+
74
+ # Set the paths from which RuGUI will automatically load source files.
75
+ def set_autoload_paths
76
+ ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
77
+ end
78
+
79
+ # Loads the environment specified by Configuration#environment_path, which
80
+ # is typically one of development, or production.
81
+ def load_environment
82
+ return if @environment_loaded
83
+ @environment_loaded = true
84
+
85
+ if File.exist?(configuration.environment_path)
86
+ config = configuration
87
+ constants = self.class.constants
88
+
89
+ eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
90
+
91
+ (self.class.constants - constants).each do |const|
92
+ Object.const_set(const, self.class.const_get(const))
93
+ end
94
+ end
95
+ end
96
+
97
+ def load_plugins
98
+ plugin_loader.load_plugins
99
+ end
100
+
101
+ def add_gem_load_paths
102
+ RuGUI::GemDependency.add_frozen_gem_path
103
+ unless @configuration.gems.empty?
104
+ require "rubygems"
105
+ @configuration.gems.each { |gem| gem.add_load_paths }
106
+ end
107
+ end
108
+
109
+ def load_gems
110
+ unless $gems_build_rake_task
111
+ @configuration.gems.each { |gem| gem.load }
112
+ end
113
+ end
114
+
115
+ def check_gem_dependencies
116
+ unloaded_gems = @configuration.gems.reject { |g| g.loaded? }
117
+ if unloaded_gems.size > 0
118
+ @gems_dependencies_loaded = false
119
+ # don't print if the gems rake tasks are being run
120
+ unless $gems_rake_task
121
+ abort <<-end_error
122
+ Missing these required gems:
123
+ #{unloaded_gems.map { |gem| "#{gem.name} #{gem.requirement}" } * "\n "}
124
+
125
+ You're running:
126
+ ruby #{Gem.ruby_version} at #{Gem.ruby}
127
+ rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
128
+
129
+ Run `rake gems:install` to install the missing gems.
130
+ end_error
131
+ end
132
+ else
133
+ @gems_dependencies_loaded = true
134
+ end
135
+ end
136
+
137
+ def load_logger
138
+ RuGUILogger.logger
139
+ end
140
+
141
+ def start_initialization_process_log
142
+ logger.info "Starting RuGUI application with #{configuration.environment} environment..." unless silence_logs?
143
+ end
144
+
145
+ def finish_initialization_process_log
146
+ logger.info "RuGUI application configurations loaded." unless silence_logs?
147
+ end
148
+
149
+ def plugin_loader
150
+ @plugin_loader || RuGUI::Plugin::Loader.new(self, configuration)
151
+ end
152
+
153
+ def load_framework_adapter
154
+ require "rugui/framework_adapters/#{RuGUI.configuration.framework_adapter}"
155
+ end
156
+
157
+ private
158
+ def silence_logs?
159
+ @@processed or $gems_build_rake_task or $gems_rake_task
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,118 @@
1
+ require 'logger'
2
+
3
+ module RuGUI
4
+ #
5
+ # A simple log support for registering problems, infos and debugs.
6
+ #
7
+ module LogSupport
8
+ # Returns the logger object.
9
+ def logger
10
+ @logger ||= RuGUILogger.logger
11
+ @logger.formatter = RuGUI::LogSupport::Formatter.new(self.class.name)
12
+ @logger
13
+ end
14
+
15
+ module ClassMethods
16
+ def logger
17
+ @@logger ||= RuGUILogger.logger
18
+ @@logger.formatter = RuGUI::LogSupport::Formatter.new(self.name)
19
+ @@logger
20
+ end
21
+ end
22
+
23
+ def self.included(base)
24
+ base.extend(ClassMethods)
25
+ end
26
+
27
+ private
28
+ class Formatter
29
+ def initialize(classname = nil)
30
+ @classname = classname
31
+ end
32
+
33
+ def call(severity, timestamp, progname, msg)
34
+ timestamp = timestamp.strftime(RuGUI.configuration.logger[:format] || "%Y-%m-%d %H:%M:%S")
35
+ "#{timestamp} (#{severity}) (#{@classname}) #{msg}\n"
36
+ end
37
+ end
38
+ end
39
+
40
+ class RuGUILogger
41
+ class << self
42
+ def logger
43
+ @@rugui_logger ||= RuGUILogger.new
44
+ @@rugui_logger.logger
45
+ end
46
+ end
47
+
48
+ def logger
49
+ @@logger
50
+ end
51
+
52
+ private
53
+ def initialize
54
+ setup_logger
55
+ end
56
+
57
+ #
58
+ # Setup a new log support object. If a problem occurs a logger is setted up
59
+ # to warn level.
60
+ #
61
+ def setup_logger
62
+ begin
63
+ @@logger = Logger.new(defined_output)
64
+ @@logger.level = defined_level
65
+ rescue StandardError => e
66
+ @@logger = Logger.new(STDERR)
67
+ @@logger.level = LEVELS[:warn]
68
+ @@logger.warn "Log support problems: The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
69
+ @@logger.error "#{e} #{e.backtrace.join("\n")}"
70
+ end
71
+ end
72
+
73
+ #
74
+ # Defines a output based on params informed by user, params setted up in
75
+ # the configuration file, or default values.
76
+ #
77
+ def defined_output
78
+ output = RuGUI.configuration.logger[:output]
79
+ if output.nil? or [:stdout, :stderr].include?(output)
80
+ DEFAULT_OUTPUT
81
+ else
82
+ File.join(RuGUI.root, 'log', output)
83
+ end
84
+ end
85
+
86
+ #
87
+ # Defines a level based on params informed by user, params setted up in
88
+ # the configuration file, or default values.
89
+ #
90
+ def defined_level
91
+ level = RuGUI.configuration.logger[:level]
92
+ unless level
93
+ level = DEFAULT_LEVEL
94
+ else
95
+ level = LEVELS[level]
96
+ end
97
+ level
98
+ end
99
+
100
+ def defined_classname(classname)
101
+ classname || self.class.name
102
+ end
103
+
104
+ LEVELS = {
105
+ :debug => Logger::DEBUG,
106
+ :info => Logger::INFO,
107
+ :warn => Logger::WARN,
108
+ :error => Logger::ERROR,
109
+ :fatal => Logger::FATAL
110
+ }
111
+
112
+ #
113
+ # Default values to the log support object - aka logger
114
+ #
115
+ DEFAULT_OUTPUT = STDOUT
116
+ DEFAULT_LEVEL = LEVELS[:debug]
117
+ end
118
+ end
@@ -0,0 +1,73 @@
1
+ module RuGUI
2
+ # A proxy class for observable properties.
3
+ #
4
+ # When creating an <code>ObservablePropertyProxy</code> you pass an
5
+ # instance of any object to it (which will now be the context for this
6
+ # proxy), the observable and the property name.
7
+ #
8
+ # The <code>ObservablePropertyProxy</code> instance will work as a
9
+ # proxy for each method send to the context. If the context is changed,
10
+ # it will notify any <code>PropertyObservers</code> registered for its
11
+ # <code>observable</code>, by calling their
12
+ # <code>property_changed</code> method.
13
+ #
14
+ # CAUTION: When using observable string properties as keys in a Hash make
15
+ # sure you call the Object#to_s or Object#to_sym methods before putting
16
+ # the property value as key. Hashes uses the method Object#eql? when
17
+ # comparing keys, and for some unknown reason it is always returning false
18
+ # when comparing observable string properties.
19
+ #
20
+ class ObservablePropertyProxy < BaseObject
21
+ include RuGUI::LogSupport
22
+
23
+ def initialize(context, observable, property)
24
+ @context = context
25
+ @observable = observable
26
+ @property = property
27
+ end
28
+
29
+ private
30
+ NON_DELEGATABLE_METHODS = ['__id__', '__send__']
31
+
32
+ # Delegating Object's methods to context. Since none of these methods
33
+ # really change the object we just send them to the context.
34
+ self.methods.each do |method_name|
35
+ unless NON_DELEGATABLE_METHODS.include?(method_name)
36
+ self.class_eval <<-class_eval
37
+ def #{method_name}(*args)
38
+ @context.send(:#{method_name}, *args)
39
+ end
40
+ class_eval
41
+ end
42
+ end
43
+
44
+ # Here we reimplement the method missing, adding code to notify observers
45
+ # when the property has changed, i.e., when the context before calling the
46
+ # method is different than the context after the method is called.
47
+ def method_missing(method, *args, &block)
48
+ old_context = get_context_copy
49
+ return_value = @context.send(method, *args, &block)
50
+
51
+ context_changed(@context, old_context) unless @context == old_context
52
+ return_value
53
+ end
54
+
55
+ # Returns a copy of the context.
56
+ def get_context_copy
57
+ begin
58
+ return @context.clone
59
+ rescue TypeError
60
+ return @context
61
+ end
62
+ end
63
+
64
+ #
65
+ # Called when the context has changed.
66
+ #
67
+ # Notifies all registered observers
68
+ #
69
+ def context_changed(new_value, old_value)
70
+ @observable.property_changed(@property, new_value, old_value)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,251 @@
1
+ require 'rugui/observable_property_proxy'
2
+
3
+ module RuGUI
4
+ # Adds support to observable properties.
5
+ module ObservablePropertySupport
6
+ # Initializes the observable properties. If you override this method, make
7
+ # sure that you call the <code>initialize_observable_property_support</code>
8
+ # method, so that the observable properties are initialized.
9
+ def initialize(observable_properties_values = {})
10
+ initialize_observable_property_support(observable_properties_values)
11
+ end
12
+
13
+ # Initializes observable properties, setting their initial value.
14
+ def initialize_observable_property_support(observable_properties_values = {})
15
+ self.class.observable_properties_options.each do |property, options|
16
+ value = (observable_properties_values.with_indifferent_access[property] || clone_if_possible(options[:initial_value]))
17
+ send("#{property}=", value)
18
+ end
19
+ end
20
+
21
+ # Registers an observer for this model.
22
+ #
23
+ # The observer must implement a method with this signature:
24
+ #
25
+ # property_updated(observable, property, new_value, old_value)
26
+ #
27
+ # This method is called whenever a property has changed its value. One
28
+ # option is to include the PropertyObserver module in the observer class.
29
+ #
30
+ # Optionally, if <code>observable_name</code> can be given, a method with
31
+ # this signature will also be called:
32
+ #
33
+ # named_observable_property_updated(observable_name, observable, property, new_value, old_value)
34
+ #
35
+ def register_observer(observer, observable_name = nil)
36
+ initialize_observers_if_needed
37
+ @observers << observer
38
+ @named_observers[observable_name] = observer unless observable_name.nil?
39
+ end
40
+
41
+ # Called whenver the a property has changed.
42
+ def property_changed(property, new_value, old_value)
43
+ initialize_observers_if_needed
44
+ @observers.each do |observer|
45
+ observer.property_updated(self, property, new_value, old_value) if observer.respond_to?(:property_updated)
46
+ end
47
+ @named_observers.each do |observable_name, observer|
48
+ observer.named_observable_property_updated(observable_name, self, property, new_value, old_value) if observer.respond_to?(:named_observable_property_updated)
49
+ end
50
+ end
51
+
52
+ # Resets all observable properties for this observer.
53
+ #
54
+ # Since an observable property may be another observable there may exist
55
+ # some observers observing this other observable. In this scenario one
56
+ # should not attempt to set a new object into the observable property,
57
+ # because the observers would still be looking for the old observable.
58
+ #
59
+ # By calling <code>reset!</code> all observable properties are reset to the
60
+ # values specified when creating it. Also if the property respond to reset
61
+ # the method will be called, unless a *reset_value* is configured, i.e., it
62
+ # is not <code>nil</code>. Also, if *prevent_reset* is true, that property
63
+ # will not be reseted, even if it has a *reset_value* configured.
64
+ def reset!
65
+ self.class.observable_properties_options.each do |property, options|
66
+ unless options[:prevent_reset]
67
+ property_value = send(property)
68
+ if options[:reset_value].nil? and property_value.respond_to?(:reset!)
69
+ property_value.reset!
70
+ else
71
+ send("#{property}=", clone_if_possible(options[:reset_value]))
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ # Returns <code>true</code> if <code>obj</code> is equals to
78
+ # <code>self</code>.
79
+ #
80
+ # This method checks if <code>obj</code> is of the same type of
81
+ # <code>self</code> and if all *core* observable_properties are equals.
82
+ def ==(obj)
83
+ if obj.is_a?(self.class)
84
+ self.class.core_observable_properties.each do |property|
85
+ return false unless obj.respond_to?(property) and respond_to?(property)
86
+ return false unless send(property) == obj.send(property)
87
+ end
88
+ return true
89
+ end
90
+ end
91
+
92
+ # Copies all observable properties from _other_observable_ to _self_
93
+ def copy_observable_properties_from(other_observable, deep = true)
94
+ self.class.observable_properties.each do |property|
95
+ if other_observable.respond_to?(property)
96
+ other_property_value = other_observable.send(property)
97
+ if other_property_value.class.include?(ObservablePropertySupport)
98
+ send(property).copy_observable_properties_from(other_property_value) if deep
99
+ else
100
+ send("#{property}=", other_property_value)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ # Returns a map of all observable properties with theirs values.
107
+ def observable_properties
108
+ self.class.observable_properties.inject({}) { |properties, property| properties.merge!({ property => send(property) }) }
109
+ end
110
+
111
+ # Update observable properties values given a map of values
112
+ def update_observable_properties(values = {})
113
+ values.each { |property, value| send("#{property}=", value) if self.respond_to?("#{property}=") }
114
+ end
115
+
116
+ module ClassMethods
117
+ # Creates the necessary class inheritable attributes an initializes them.
118
+ def create_class_inheritable_attributes
119
+ self.class_inheritable_accessor :observable_properties_options
120
+
121
+ self.observable_properties_options = {}
122
+ end
123
+
124
+ # Register a observable properties for this model.
125
+ #
126
+ # Properties may be given as symbols, or strings. You can pass some
127
+ # options, in a hash, which will be used when the observable is created:
128
+ #
129
+ # - *initial_value*: The initial value for the property. This value will
130
+ # be set when the observable instance is initialized (i.e., when the
131
+ # <code>initialize</code> method is called). Defaults to <code>nil</code>.
132
+ # - *reset_value*: The reset value for the property. This value will be
133
+ # set when the observable instance is reset (i.e., when the
134
+ # <code>reset!</code> method is called). If this is not given, the
135
+ # <code>initial_value</code> will be used instead.
136
+ # - *core*: Defines whether the property should be used when comparing two
137
+ # observables. Defaults to <code>false</code>.
138
+ # - *prevent_reset*: If this is <code>true</code> the property will not be
139
+ # reseted. Defaults to false.
140
+ # - *boolean*: If this is <code>true</code> a "question" method will be
141
+ # created for the property (i.e., for a property named <code>foo</code>
142
+ # a method named <code>foo?</code> will be created).
143
+ #
144
+ # Examples:
145
+ #
146
+ # class MyObservable
147
+ # include RuGUI::ObservablePropertySupport
148
+ #
149
+ # observable_property :foo, :initial_value => "bar"
150
+ # observable_property :bar, :initial_value => "foo", :reset_value => "bar"
151
+ # observable_property :core_property, :core => true
152
+ # observable_property :non_resetable_property, :prevent_reset => true
153
+ #
154
+ # # And so on...
155
+ # end
156
+ def observable_property(property, options = {})
157
+ create_observable_property_options(property, options)
158
+ create_observable_property_accessors(property)
159
+ create_observable_property_boolean_readers(property, options)
160
+ end
161
+
162
+ # Returns the names of core observable properties for this class.
163
+ def core_observable_properties
164
+ core_observable_properties = []
165
+ observable_properties_options.each do |property, options|
166
+ core_observable_properties << property if options[:core] == true
167
+ end
168
+ core_observable_properties
169
+ end
170
+
171
+ # Returns the names of all observable properties for this class.
172
+ def observable_properties
173
+ observable_properties_options.keys
174
+ end
175
+
176
+ private
177
+ def create_observable_property_options(property, options = {})
178
+ self.observable_properties_options[property.to_sym] = prepare_options(options)
179
+ end
180
+
181
+ def create_observable_property_accessors(property)
182
+ self.class_eval <<-class_eval
183
+ def #{property}
184
+ @#{property}
185
+ end
186
+
187
+ def #{property}=(value)
188
+ old_value = get_old_value(@#{property})
189
+ if has_changed?(value, old_value)
190
+ @#{property} = ObservablePropertyProxy.new(value, self, '#{property}')
191
+ property_changed('#{property}', value, old_value)
192
+ end
193
+ end
194
+ class_eval
195
+ end
196
+
197
+ def create_observable_property_boolean_readers(property, options)
198
+ if options[:boolean]
199
+ self.class_eval <<-class_eval
200
+ def #{property}?
201
+ self.#{property} == true
202
+ end
203
+ class_eval
204
+ end
205
+ end
206
+
207
+ def prepare_options(options)
208
+ options = default_options.merge(options)
209
+ if options[:reset_value].nil? and not options[:initial_value].class.include?(ObservablePropertySupport)
210
+ options[:reset_value] = options[:initial_value]
211
+ end
212
+ options
213
+ end
214
+
215
+ def default_options
216
+ { :core => false,
217
+ :initial_value => nil,
218
+ :reset_value => nil }
219
+ end
220
+ end
221
+
222
+ def self.included(base)
223
+ base.extend(ClassMethods)
224
+ base.create_class_inheritable_attributes
225
+ end
226
+
227
+ private
228
+ def initialize_observers_if_needed
229
+ @observers = [] if not defined?(@observers) or @observers.nil?
230
+ @named_observers = {} if not defined?(@named_observers) or @named_observers.nil?
231
+ end
232
+
233
+ def get_old_value(property)
234
+ begin
235
+ return property.clone
236
+ rescue TypeError
237
+ return property
238
+ end
239
+ end
240
+
241
+ def has_changed?(new_value, old_value)
242
+ !(new_value.kind_of?(old_value.class) && old_value == new_value)
243
+ end
244
+
245
+ def clone_if_possible(value)
246
+ value.clone
247
+ rescue TypeError
248
+ value
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,77 @@
1
+ module RuGUI
2
+ module Plugin
3
+ class Loader
4
+ attr_accessor :initializer
5
+ attr_accessor :configurations
6
+ cattr_accessor :located_plugins
7
+
8
+ def initialize(initializer, configurations)
9
+ self.initializer = initializer
10
+ self.configurations = configurations
11
+ @@located_plugins ||= []
12
+ end
13
+
14
+ def load_plugins
15
+ plugins.each do |plugin|
16
+ plugin.load unless plugin.loaded?
17
+ register_as_loaded(plugin)
18
+ end
19
+ end
20
+
21
+ def plugins
22
+ @plugins ||= locate_plugins
23
+ end
24
+
25
+ protected
26
+ # Locate all plugins in APPLICATION_ROOT/vendor/plugins
27
+ def locate_plugins
28
+ Dir.glob(File.join(APPLICATION_ROOT, "vendor", "plugins", "*")).each do |dir|
29
+ @@located_plugins << Location.new(dir)
30
+ end
31
+ @@located_plugins
32
+ end
33
+
34
+ # Register plugins as loaded.
35
+ def register_as_loaded(plugin)
36
+ plugin.loaded = true
37
+ end
38
+ end
39
+
40
+ # This class is a representation of RuGUI plugins.
41
+ class Location
42
+ attr_accessor :plugin_name
43
+ attr_accessor :dir
44
+ attr_accessor :loaded
45
+
46
+ include RuGUI::LogSupport
47
+
48
+ def initialize(dir)
49
+ self.dir = dir
50
+ self.plugin_name = dir.split(File::SEPARATOR).last
51
+ end
52
+
53
+ # Load plugins.
54
+ def load
55
+ $LOAD_PATH.unshift(File.join(self.dir, "lib")) if File.directory?(self.dir)
56
+ $LOAD_PATH.uniq!
57
+
58
+ init_file = File.expand_path(File.join(self.dir, "init.rb"))
59
+ if File.exist?(init_file)
60
+ require_for init_file
61
+ else
62
+ logger.warn "The init file for (#{self.plugin_name}) was not found."
63
+ end
64
+ end
65
+
66
+ def require_for(init_file)
67
+ require init_file
68
+ rescue Exception
69
+ logger.error "An error occurred while loading #{self.plugin_name}. Checks its init file: #{$!}"
70
+ end
71
+
72
+ def loaded?
73
+ self.loaded ||= false
74
+ end
75
+ end
76
+ end
77
+ end