Class: Module::Pluggable::Plugins

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/module/pluggable.rb

Defined Under Namespace

Classes: ClassNotFoundError, NotInheritAbstractClassError, PluginsError

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Plugins

Returns a new instance of Plugins.



53
54
55
56
57
58
# File 'lib/module/pluggable.rb', line 53

def initialize(opts)
	@opts  = opts
	@dir   = Pathname.new(opts[:search_path])
	@plugins = {}
	reload
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Undefined methods are delegated to each plugins. This is alias of call



162
163
164
# File 'lib/module/pluggable.rb', line 162

def method_missing(name, *args)
	call(name, *args)
end

Instance Method Details

#[](klass_name) ⇒ Object

Get instance of klass_name plugin.



98
99
100
# File 'lib/module/pluggable.rb', line 98

def [](klass_name)
	@plugins[klass_name][:instance] if @plugins.key?(klass_name)
end

#call(name, *args) ⇒ Object

Call name method of each plugins with args and returns Hash of the result and its plugin name.



152
153
154
155
156
157
158
# File 'lib/module/pluggable.rb', line 152

def call(name, *args)
	ret = {}
	each do |k,v|
		ret[k] = v.send(name, *args) if v.respond_to?(name)
	end
	ret
end

#each(&block) ⇒ Object

Iterates with plugin name and its instance.



144
145
146
147
148
# File 'lib/module/pluggable.rb', line 144

def each(&block)
	@plugins.each do |k,v|
		yield k, v[:instance]
	end
end

#force_reloadObject

Unload all plugins and reload it.



137
138
139
140
141
# File 'lib/module/pluggable.rb', line 137

def force_reload
	call(:on_unload)
	@plugins.clear
	reload
end

#load(klass_name) ⇒ Object

Load klass_name. The plugin is loaded in anonymous module not order to destroy the environments. And remember loaded time for reloading.

plugin filename must be interconversion with its class name. In this class, the conversion is do with file2klass/klass2file methods.



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
95
# File 'lib/module/pluggable.rb', line 67

def load(klass_name)
	return if @plugins.include?(klass_name)
	
	filename = klass2file(klass_name)
	
	mod = Module.new
	mod.module_eval(File.open("#{@opts[:search_path]}/#{filename}.rb") {|f| f.read}, filename)
	
	c = nil
	begin
		c = mod.const_get(klass_name)
	rescue NameError
		raise ClassNotFoundError.new("#{@opts[:search_path]}/#{filename} must include #{klass_name} class")
	end
	
	if !@opts[:base_class] || c < @opts[:base_class]
		@plugins[klass_name] = {
			:instance => c.new,
			:loaded   => Time.now,
		}
	else
		raise NotInheritAbstractClassError.new("The class #{klass_name} must inherit #{@opts[:base_class]}")
	end

	@plugins[klass_name][:instance].on_load rescue NameError
	@plugins[klass_name][:instance].instance_variable_set(:@plugins, self)
	
	klass_name
end

#reload(klass_name = nil) ⇒ Object

Reload klass_name or load unloaded plugins or reload modified plugins. returns [loaded, unloaded]



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/module/pluggable.rb', line 114

def reload(klass_name=nil)
	if klass_name
		unload(klass_name)
		load(klass_name)
		klass_name
	else
		loaded   = []
		unloaded = []
		Dir.glob("#{@opts[:search_path]}/*.rb") do |f|
			klass_name = file2klass(File.basename(f, ".rb").sub(/^\d+/, ""))
			if @plugins.include?(klass_name)
				if File.mtime(f) > @plugins[klass_name][:loaded]
					loaded << reload(klass_name)
				end
			else
				loaded << reload(klass_name)
			end
		end
		[loaded, unloaded]
	end
end

#unload(klass_name) ⇒ Object

Unload +klass_name



103
104
105
106
107
108
# File 'lib/module/pluggable.rb', line 103

def unload(klass_name)
	if @plugins.key?(klass_name)
		@plugins[klass_name][:instance].on_unload rescue NameError
		@plugins.delete(klass_name)
	end
end