pluginfactory 1.0.2 → 1.0.3
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.
- data/ChangeLog +293 -70
- data/LICENSE +27 -0
- data/README +189 -24
- data/Rakefile +252 -0
- data/lib/pluginfactory.rb +126 -128
- data/rake/dependencies.rb +62 -0
- data/rake/helpers.rb +382 -0
- data/rake/manual.rb +384 -0
- data/rake/packaging.rb +112 -0
- data/rake/publishing.rb +303 -0
- data/rake/rdoc.rb +30 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +461 -0
- data/rake/testing.rb +191 -0
- data/rake/verifytask.rb +64 -0
- data/spec/pluginfactory_spec.rb +223 -0
- metadata +62 -43
- data/COPYRIGHT +0 -131
- data/install.rb +0 -172
- data/test.rb +0 -72
- data/tests/dir/deepsubofmybase.rb +0 -3
- data/tests/mybase.rb +0 -11
- data/tests/othersub.rb +0 -5
- data/tests/subofmybase.rb +0 -5
- data/utils.rb +0 -672
data/Rakefile
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
#!rake
|
2
|
+
#
|
3
|
+
# PluginFactory rakefile
|
4
|
+
#
|
5
|
+
# Based on various other Rakefiles, especially one by Ben Bleything
|
6
|
+
#
|
7
|
+
# Copyright (c) 2008 The FaerieMUD Consortium
|
8
|
+
#
|
9
|
+
# Authors:
|
10
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
11
|
+
#
|
12
|
+
|
13
|
+
BEGIN {
|
14
|
+
require 'pathname'
|
15
|
+
basedir = Pathname.new( __FILE__ ).dirname
|
16
|
+
|
17
|
+
libdir = basedir + "lib"
|
18
|
+
extdir = basedir + "ext"
|
19
|
+
|
20
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
21
|
+
$LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
require 'rbconfig'
|
26
|
+
require 'rubygems'
|
27
|
+
require 'rake'
|
28
|
+
require 'rake/rdoctask'
|
29
|
+
require 'rake/testtask'
|
30
|
+
require 'rake/packagetask'
|
31
|
+
require 'rake/clean'
|
32
|
+
|
33
|
+
$dryrun = false
|
34
|
+
|
35
|
+
### Config constants
|
36
|
+
BASEDIR = Pathname.new( __FILE__ ).dirname.relative_path_from( Pathname.getwd )
|
37
|
+
LIBDIR = BASEDIR + 'lib'
|
38
|
+
EXTDIR = BASEDIR + 'ext'
|
39
|
+
DOCSDIR = BASEDIR + 'docs'
|
40
|
+
PKGDIR = BASEDIR + 'pkg'
|
41
|
+
|
42
|
+
PKG_NAME = 'pluginfactory'
|
43
|
+
PKG_SUMMARY = 'A mixin for making plugin classes'
|
44
|
+
VERSION_FILE = LIBDIR + 'pluginfactory.rb'
|
45
|
+
PKG_VERSION = VERSION_FILE.read[ /VERSION = '(\d+\.\d+\.\d+)'/, 1 ]
|
46
|
+
PKG_FILE_NAME = "#{PKG_NAME.downcase}-#{PKG_VERSION}"
|
47
|
+
GEM_FILE_NAME = "#{PKG_FILE_NAME}.gem"
|
48
|
+
|
49
|
+
ARTIFACTS_DIR = Pathname.new( ENV['CC_BUILD_ARTIFACTS'] || 'artifacts' )
|
50
|
+
|
51
|
+
TEXT_FILES = %w( Rakefile ChangeLog README LICENSE ).collect {|filename| BASEDIR + filename }
|
52
|
+
LIB_FILES = Pathname.glob( LIBDIR + '**/*.rb' ).delete_if {|item| item =~ /\.svn/ }
|
53
|
+
EXT_FILES = Pathname.glob( EXTDIR + '**/*.{c,h,rb}' ).delete_if {|item| item =~ /\.svn/ }
|
54
|
+
|
55
|
+
SPECDIR = BASEDIR + 'spec'
|
56
|
+
SPEC_FILES = Pathname.glob( SPECDIR + '**/*_spec.rb' ).delete_if {|item| item =~ /\.svn/ }
|
57
|
+
|
58
|
+
TESTDIR = BASEDIR + 'tests'
|
59
|
+
TEST_FILES = Pathname.glob( TESTDIR + '**/*.tests.rb' ).delete_if {|item| item =~ /\.svn/ }
|
60
|
+
|
61
|
+
RAKE_TASKDIR = BASEDIR + 'rake'
|
62
|
+
RAKE_TASKLIBS = Pathname.glob( RAKE_TASKDIR + '*.rb' )
|
63
|
+
|
64
|
+
LOCAL_RAKEFILE = BASEDIR + 'Rakefile.local'
|
65
|
+
|
66
|
+
EXTRA_PKGFILES = []
|
67
|
+
|
68
|
+
RELEASE_FILES = TEXT_FILES +
|
69
|
+
SPEC_FILES +
|
70
|
+
TEST_FILES +
|
71
|
+
LIB_FILES +
|
72
|
+
EXT_FILES +
|
73
|
+
RAKE_TASKLIBS +
|
74
|
+
EXTRA_PKGFILES
|
75
|
+
|
76
|
+
RELEASE_FILES << LOCAL_RAKEFILE if LOCAL_RAKEFILE.exist?
|
77
|
+
|
78
|
+
COVERAGE_MINIMUM = ENV['COVERAGE_MINIMUM'] ? Float( ENV['COVERAGE_MINIMUM'] ) : 85.0
|
79
|
+
RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib'
|
80
|
+
RCOV_OPTS = [
|
81
|
+
'--exclude', RCOV_EXCLUDES,
|
82
|
+
'--xrefs',
|
83
|
+
'--save',
|
84
|
+
'--callsites',
|
85
|
+
#'--aggregate', 'coverage.data' # <- doesn't work as of 0.8.1.2.0
|
86
|
+
]
|
87
|
+
|
88
|
+
|
89
|
+
# Subversion constants -- directory names for releases and tags
|
90
|
+
SVN_TRUNK_DIR = 'trunk'
|
91
|
+
SVN_RELEASES_DIR = 'releases'
|
92
|
+
SVN_BRANCHES_DIR = 'branches'
|
93
|
+
SVN_TAGS_DIR = 'tags'
|
94
|
+
|
95
|
+
SVN_DOTDIR = BASEDIR + '.svn'
|
96
|
+
SVN_ENTRIES = SVN_DOTDIR + 'entries'
|
97
|
+
|
98
|
+
|
99
|
+
### Load some task libraries that need to be loaded early
|
100
|
+
require RAKE_TASKDIR + 'helpers.rb'
|
101
|
+
require RAKE_TASKDIR + 'svn.rb'
|
102
|
+
require RAKE_TASKDIR + 'verifytask.rb'
|
103
|
+
|
104
|
+
# Define some constants that depend on the 'svn' tasklib
|
105
|
+
PKG_BUILD = get_svn_rev( BASEDIR ) || 0
|
106
|
+
SNAPSHOT_PKG_NAME = "#{PKG_FILE_NAME}.#{PKG_BUILD}"
|
107
|
+
SNAPSHOT_GEM_NAME = "#{SNAPSHOT_PKG_NAME}.gem"
|
108
|
+
|
109
|
+
# Documentation constants
|
110
|
+
RDOC_OPTIONS = [
|
111
|
+
'-w', '4',
|
112
|
+
'-SHN',
|
113
|
+
'-i', '.',
|
114
|
+
'-m', 'README',
|
115
|
+
'-W', 'http://deveiate.org/projects/PluginFactory//browser/trunk/'
|
116
|
+
]
|
117
|
+
|
118
|
+
# Release constants
|
119
|
+
SMTP_HOST = 'mail.faeriemud.org'
|
120
|
+
SMTP_PORT = 465 # SMTP + SSL
|
121
|
+
|
122
|
+
# Project constants
|
123
|
+
PROJECT_HOST = 'deveiate.org'
|
124
|
+
PROJECT_PUBDIR = "/usr/local/www/public/code"
|
125
|
+
PROJECT_DOCDIR = "#{PROJECT_PUBDIR}/#{PKG_NAME}"
|
126
|
+
PROJECT_SCPURL = "#{PROJECT_HOST}:#{PROJECT_DOCDIR}"
|
127
|
+
|
128
|
+
# Rubyforge stuff
|
129
|
+
RUBYFORGE_GROUP = 'deveiate'
|
130
|
+
RUBYFORGE_PROJECT = 'pluginfactory'
|
131
|
+
|
132
|
+
# Gem dependencies: gemname => version
|
133
|
+
DEPENDENCIES = {
|
134
|
+
}
|
135
|
+
|
136
|
+
# Non-gem requirements: packagename => version
|
137
|
+
REQUIREMENTS = {
|
138
|
+
}
|
139
|
+
|
140
|
+
# RubyGem specification
|
141
|
+
GEMSPEC = Gem::Specification.new do |gem|
|
142
|
+
gem.name = PKG_NAME.downcase
|
143
|
+
gem.version = PKG_VERSION
|
144
|
+
|
145
|
+
gem.summary = PKG_SUMMARY
|
146
|
+
gem.description = <<-EOD
|
147
|
+
PluginFactory is a mixin module that turns an including class into a factory for
|
148
|
+
its derivatives, capable of searching for and loading them by name. This is
|
149
|
+
useful when you have an abstract base class which defines an interface and basic
|
150
|
+
functionality for a part of a larger system, and a collection of subclasses
|
151
|
+
which implement the interface for different underlying functionality.
|
152
|
+
EOD
|
153
|
+
|
154
|
+
gem.authors = 'Michael Granger'
|
155
|
+
gem.email = 'ged@FaerieMUD.org'
|
156
|
+
gem.homepage = 'http://deveiate.org/projects/PluginFactory/'
|
157
|
+
gem.rubyforge_project = RUBYFORGE_PROJECT
|
158
|
+
|
159
|
+
gem.has_rdoc = true
|
160
|
+
gem.rdoc_options = RDOC_OPTIONS
|
161
|
+
|
162
|
+
gem.files = RELEASE_FILES.
|
163
|
+
collect {|f| f.relative_path_from(BASEDIR).to_s }
|
164
|
+
gem.test_files = SPEC_FILES.
|
165
|
+
collect {|f| f.relative_path_from(BASEDIR).to_s }
|
166
|
+
|
167
|
+
DEPENDENCIES.each do |name, version|
|
168
|
+
version = '>= 0' if version.length.zero?
|
169
|
+
gem.add_dependency( name, version )
|
170
|
+
end
|
171
|
+
|
172
|
+
REQUIREMENTS.each do |name, version|
|
173
|
+
gem.requirements << [ name, version ].compact.join(' ')
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
$trace = Rake.application.options.trace ? true : false
|
178
|
+
$dryrun = Rake.application.options.dryrun ? true : false
|
179
|
+
|
180
|
+
|
181
|
+
# Load any remaining task libraries
|
182
|
+
RAKE_TASKLIBS.each do |tasklib|
|
183
|
+
next if tasklib =~ %r{/(helpers|svn|verifytask)\.rb$}
|
184
|
+
begin
|
185
|
+
require tasklib
|
186
|
+
rescue ScriptError => err
|
187
|
+
fail "Task library '%s' failed to load: %s: %s" %
|
188
|
+
[ tasklib, err.class.name, err.message ]
|
189
|
+
trace "Backtrace: \n " + err.backtrace.join( "\n " )
|
190
|
+
rescue => err
|
191
|
+
log "Task library '%s' failed to load: %s: %s. Some tasks may not be available." %
|
192
|
+
[ tasklib, err.class.name, err.message ]
|
193
|
+
trace "Backtrace: \n " + err.backtrace.join( "\n " )
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Load any project-specific rules defined in 'Rakefile.local' if it exists
|
198
|
+
import LOCAL_RAKEFILE if LOCAL_RAKEFILE.exist?
|
199
|
+
|
200
|
+
|
201
|
+
#####################################################################
|
202
|
+
### T A S K S
|
203
|
+
#####################################################################
|
204
|
+
|
205
|
+
### Default task
|
206
|
+
task :default => [:clean, :local, :spec, :rdoc, :package]
|
207
|
+
|
208
|
+
### Task the local Rakefile can append to -- no-op by default
|
209
|
+
task :local
|
210
|
+
|
211
|
+
|
212
|
+
### Task: clean
|
213
|
+
CLEAN.include 'coverage'
|
214
|
+
CLOBBER.include 'artifacts', 'coverage.info', PKGDIR
|
215
|
+
|
216
|
+
# Target to hinge on ChangeLog updates
|
217
|
+
file SVN_ENTRIES
|
218
|
+
|
219
|
+
### Task: changelog
|
220
|
+
file 'ChangeLog' => SVN_ENTRIES.to_s do |task|
|
221
|
+
log "Updating #{task.name}"
|
222
|
+
|
223
|
+
changelog = make_svn_changelog()
|
224
|
+
File.open( task.name, 'w' ) do |fh|
|
225
|
+
fh.print( changelog )
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
### Task: cruise (Cruisecontrol task)
|
231
|
+
desc "Cruisecontrol build"
|
232
|
+
task :cruise => [:clean, :spec, :package] do |task|
|
233
|
+
raise "Artifacts dir not set." if ARTIFACTS_DIR.to_s.empty?
|
234
|
+
artifact_dir = ARTIFACTS_DIR.cleanpath
|
235
|
+
artifact_dir.mkpath
|
236
|
+
|
237
|
+
$stderr.puts "Copying coverage stats..."
|
238
|
+
FileUtils.cp_r( 'coverage', artifact_dir )
|
239
|
+
|
240
|
+
$stderr.puts "Copying packages..."
|
241
|
+
FileUtils.cp_r( FileList['pkg/*'].to_a, artifact_dir )
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
desc "Update the build system to the latest version"
|
246
|
+
task :update_build do
|
247
|
+
log "Updating the build system"
|
248
|
+
sh 'svn', 'up', RAKE_TASKDIR
|
249
|
+
log "Updating the Rakefile"
|
250
|
+
sh 'rake', '-f', RAKE_TASKDIR + 'Metarakefile'
|
251
|
+
end
|
252
|
+
|
data/lib/pluginfactory.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby -w
|
2
|
-
|
2
|
+
|
3
|
+
### An exception class for PluginFactory specific errors.
|
4
|
+
class FactoryError < RuntimeError; end
|
5
|
+
|
3
6
|
# This module contains the PluginFactory mixin. Including PluginFactory in your
|
4
7
|
# class turns it into a factory for its derivatives, capable of searching for
|
5
8
|
# and loading them by name. This is useful when you have an abstract base class
|
@@ -18,7 +21,9 @@
|
|
18
21
|
#
|
19
22
|
# == Creation Argument Variants
|
20
23
|
#
|
21
|
-
# The +create+ class method added to your class by PluginFactory searches for
|
24
|
+
# The +create+ class method added to your class by PluginFactory searches for
|
25
|
+
# your module using the $LOAD_PATH that require uses. See the README for a
|
26
|
+
# detailed explanation.
|
22
27
|
#
|
23
28
|
# == Synopsis
|
24
29
|
#
|
@@ -60,38 +65,24 @@
|
|
60
65
|
#
|
61
66
|
# == Subversion ID
|
62
67
|
#
|
63
|
-
# $Id: pluginfactory.rb
|
68
|
+
# $Id: pluginfactory.rb 52 2008-08-13 21:58:41Z deveiant $
|
64
69
|
#
|
65
70
|
# == Authors
|
66
71
|
#
|
67
72
|
# * Martin Chase <stillflame@FaerieMUD.org>
|
68
73
|
# * Michael Granger <ged@FaerieMUD.org>
|
69
74
|
#
|
70
|
-
|
75
|
+
# :include: LICENSE
|
71
76
|
#
|
72
77
|
#---
|
73
78
|
#
|
74
|
-
# Please see the file
|
79
|
+
# Please see the file LICENSE for licensing details.
|
75
80
|
#
|
76
|
-
|
77
|
-
|
78
|
-
### An exception class for PluginFactory specific errors.
|
79
|
-
class FactoryError < RuntimeError
|
80
|
-
def initialize( *args )
|
81
|
-
if ! args.empty?
|
82
|
-
msg = args.collect {|a| a.to_s}.join
|
83
|
-
super( msg )
|
84
|
-
else
|
85
|
-
super( message )
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end # class FactoryError
|
89
|
-
|
90
|
-
|
91
|
-
### A mixin that adds PluginFactory class methods to a base class, so that
|
92
|
-
### subclasses may be instantiated by name.
|
93
81
|
module PluginFactory
|
94
82
|
|
83
|
+
VERSION = '1.0.3'
|
84
|
+
|
85
|
+
|
95
86
|
### A callback for logging the various debug and information this module
|
96
87
|
### has to log. Should take two arguments, the log level, possibly as a
|
97
88
|
### symbol, and the log message itself.
|
@@ -100,24 +91,24 @@ module PluginFactory
|
|
100
91
|
attr_accessor :logger_callback
|
101
92
|
end
|
102
93
|
|
103
|
-
### If the logger callback is set, use it to pass on a log entry. First
|
104
|
-
|
105
|
-
|
94
|
+
### If the logger callback is set, use it to pass on a log entry. First
|
95
|
+
### argument is a 'level' which is passed to the logging callback. Any
|
96
|
+
### remaining arguments will be joined and passed as a single second
|
97
|
+
### argument to the callback.
|
98
|
+
def self::log( level, *msg )
|
99
|
+
@logger_callback.call( level, msg.join ) if @logger_callback
|
106
100
|
end
|
107
101
|
|
108
102
|
|
109
|
-
### Inclusion callback -- extends the including class.
|
103
|
+
### Inclusion callback -- extends the including class. This is here so you can
|
104
|
+
### either 'include' or 'extend'.
|
110
105
|
def self::included( klass )
|
111
106
|
klass.extend( self )
|
112
107
|
end
|
113
108
|
|
114
109
|
|
115
|
-
###
|
116
|
-
### class.
|
110
|
+
### Add the @derivatives instance variable to including classes.
|
117
111
|
def self::extend_object( obj )
|
118
|
-
unless obj.is_a?( Class )
|
119
|
-
raise TypeError, "Cannot extend a #{obj.class.name}", caller(1)
|
120
|
-
end
|
121
112
|
obj.instance_variable_set( :@derivatives, {} )
|
122
113
|
super
|
123
114
|
end
|
@@ -130,23 +121,23 @@ module PluginFactory
|
|
130
121
|
### Return the Hash of derivative classes, keyed by various versions of
|
131
122
|
### the class name.
|
132
123
|
def derivatives
|
133
|
-
ancestors.each
|
124
|
+
ancestors.each do |klass|
|
134
125
|
if klass.instance_variables.include?( "@derivatives" )
|
135
|
-
|
126
|
+
return klass.instance_variable_get( :@derivatives )
|
136
127
|
end
|
137
|
-
|
128
|
+
end
|
138
129
|
end
|
139
130
|
|
140
131
|
|
141
132
|
### Returns the type name used when searching for a derivative.
|
142
133
|
def factory_type
|
143
134
|
base = nil
|
144
|
-
self.ancestors.each
|
135
|
+
self.ancestors.each do |klass|
|
145
136
|
if klass.instance_variables.include?( "@derivatives" )
|
146
137
|
base = klass
|
147
138
|
break
|
148
139
|
end
|
149
|
-
|
140
|
+
end
|
150
141
|
|
151
142
|
raise FactoryError, "Couldn't find factory base for #{self.name}" if
|
152
143
|
base.nil?
|
@@ -172,11 +163,12 @@ module PluginFactory
|
|
172
163
|
keys << subclass.name.sub( /.*::/, '' ).downcase
|
173
164
|
end
|
174
165
|
|
175
|
-
keys.uniq.each
|
176
|
-
|
177
|
-
|
166
|
+
keys.uniq.each do |key|
|
167
|
+
PluginFactory.log :info, "Registering %s derivative of %s as %p" %
|
168
|
+
[ subclass.name, self.name, key ]
|
178
169
|
self.derivatives[ key ] = subclass
|
179
|
-
|
170
|
+
end
|
171
|
+
|
180
172
|
super
|
181
173
|
end
|
182
174
|
|
@@ -188,56 +180,57 @@ module PluginFactory
|
|
188
180
|
alias_method :derivativeClasses, :derivative_classes
|
189
181
|
|
190
182
|
|
191
|
-
### Given the <tt>
|
183
|
+
### Given the <tt>class_name</tt> of the class to instantiate, and other
|
192
184
|
### arguments bound for the constructor of the new object, this method
|
193
185
|
### loads the derivative class if it is not loaded already (raising a
|
194
186
|
### LoadError if an appropriately-named file cannot be found), and
|
195
|
-
### instantiates it with the given <tt>args</tt>. The <tt>
|
187
|
+
### instantiates it with the given <tt>args</tt>. The <tt>class_name</tt>
|
196
188
|
### may be the the fully qualified name of the class, the class object
|
197
189
|
### itself, or the unique part of the class name. The following examples
|
198
190
|
### would all try to load and instantiate a class called "FooListener"
|
199
191
|
### if Listener included Factory
|
200
|
-
### obj = Listener
|
201
|
-
### obj = Listener
|
202
|
-
### obj = Listener
|
203
|
-
def create(
|
204
|
-
subclass = get_subclass(
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
192
|
+
### obj = Listener.create( 'FooListener' )
|
193
|
+
### obj = Listener.create( FooListener )
|
194
|
+
### obj = Listener.create( 'Foo' )
|
195
|
+
def create( class_name, *args, &block )
|
196
|
+
subclass = get_subclass( class_name )
|
197
|
+
|
198
|
+
begin
|
199
|
+
return subclass.new( *args, &block )
|
200
|
+
rescue => err
|
201
|
+
nicetrace = err.backtrace.reject {|frame| /#{__FILE__}/ =~ frame}
|
202
|
+
msg = "When creating '#{class_name}': " + err.message
|
203
|
+
Kernel.raise( err, msg, nicetrace )
|
204
|
+
end
|
211
205
|
end
|
212
206
|
|
213
207
|
|
214
|
-
### Given a <tt>
|
208
|
+
### Given a <tt>class_name</tt> like that of the first argument to
|
215
209
|
### #create, attempt to load the corresponding class if it is not
|
216
210
|
### already loaded and return the class object.
|
217
|
-
def get_subclass(
|
218
|
-
return self if ( self.name ==
|
219
|
-
|
211
|
+
def get_subclass( class_name )
|
212
|
+
return self if ( self.name == class_name || class_name == '' )
|
213
|
+
if class_name.is_a?( Class )
|
214
|
+
return class_name if class_name <= self
|
215
|
+
raise ArgumentError, "%s is not a descendent of %s" % [class_name, self]
|
216
|
+
end
|
220
217
|
|
221
|
-
|
222
|
-
self.load_derivative( className )
|
218
|
+
class_name = class_name.to_s
|
223
219
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
"registry for %s" %
|
228
|
-
[ className, className.downcase, self.name ]
|
229
|
-
end
|
220
|
+
# If the derivatives hash doesn't already contain the class, try to load it
|
221
|
+
unless self.derivatives.has_key?( class_name.downcase )
|
222
|
+
self.load_derivative( class_name )
|
230
223
|
|
231
|
-
subclass = self.derivatives[
|
224
|
+
subclass = self.derivatives[ class_name.downcase ]
|
232
225
|
unless subclass.is_a?( Class )
|
233
226
|
raise FactoryError,
|
234
227
|
"load_derivative(%s) added something other than a class "\
|
235
228
|
"to the registry for %s: %p" %
|
236
|
-
[
|
229
|
+
[ class_name, self.name, subclass ]
|
237
230
|
end
|
238
231
|
end
|
239
232
|
|
240
|
-
return self.derivatives[
|
233
|
+
return self.derivatives[ class_name.downcase ]
|
241
234
|
end
|
242
235
|
alias_method :getSubclass, :get_subclass
|
243
236
|
|
@@ -251,42 +244,39 @@ module PluginFactory
|
|
251
244
|
### <tt>class.derivativeDirs</tt> returns <tt>['foo','bar']</tt> the
|
252
245
|
### require line is tried with both <tt>'foo/'</tt> and <tt>'bar/'</tt>
|
253
246
|
### prepended to it.
|
254
|
-
def load_derivative(
|
255
|
-
|
256
|
-
|
257
|
-
#PluginFactory::log :debug, "Loading derivative #{className}"
|
247
|
+
def load_derivative( class_name )
|
248
|
+
PluginFactory.log :debug, "Loading derivative #{class_name}"
|
258
249
|
|
259
250
|
# Get the unique part of the derived class name and try to
|
260
251
|
# load it from one of the derivative subdirs, if there are
|
261
252
|
# any.
|
262
|
-
mod_name = self.get_module_name(
|
263
|
-
self.require_derivative( mod_name )
|
253
|
+
mod_name = self.get_module_name( class_name )
|
254
|
+
result = self.require_derivative( mod_name )
|
264
255
|
|
265
256
|
# Check to see if the specified listener is now loaded. If it
|
266
257
|
# is not, raise an error to that effect.
|
267
|
-
unless self.derivatives[
|
268
|
-
|
269
|
-
|
258
|
+
unless self.derivatives[ class_name.downcase ]
|
259
|
+
errmsg = "Require of '%s' succeeded, but didn't load a %s named '%s' for some reason." % [
|
260
|
+
result,
|
270
261
|
self.factory_type,
|
271
|
-
|
272
|
-
|
273
|
-
|
262
|
+
class_name.downcase,
|
263
|
+
]
|
264
|
+
PluginFactory.log :error, errmsg
|
265
|
+
raise FactoryError, errmsg, caller(3)
|
274
266
|
end
|
275
|
-
|
276
|
-
return true
|
277
267
|
end
|
278
268
|
alias_method :loadDerivative, :load_derivative
|
279
269
|
|
280
270
|
|
281
|
-
### Build and return the unique part of the given <tt>
|
271
|
+
### Build and return the unique part of the given <tt>class_name</tt>
|
282
272
|
### either by stripping leading namespaces if the name already has the
|
283
273
|
### name of the factory type in it (eg., 'My::FooService' for Service,
|
284
274
|
### or by appending the factory type if it doesn't.
|
285
|
-
def get_module_name(
|
286
|
-
if
|
287
|
-
mod_name =
|
275
|
+
def get_module_name( class_name )
|
276
|
+
if class_name =~ /\w+#{self.factory_type}/
|
277
|
+
mod_name = class_name.sub( /(?:.*::)?(\w+)(?:#{self.factory_type})/, "\\1" )
|
288
278
|
else
|
289
|
-
mod_name =
|
279
|
+
mod_name = class_name
|
290
280
|
end
|
291
281
|
|
292
282
|
return mod_name
|
@@ -294,7 +284,7 @@ module PluginFactory
|
|
294
284
|
alias_method :getModuleName, :get_module_name
|
295
285
|
|
296
286
|
|
297
|
-
### If the factory responds to the #
|
287
|
+
### If the factory responds to the #derivative_dirs method, call
|
298
288
|
### it and use the returned array as a list of directories to
|
299
289
|
### search for the module with the specified <tt>mod_name</tt>.
|
300
290
|
def require_derivative( mod_name )
|
@@ -313,48 +303,53 @@ module PluginFactory
|
|
313
303
|
end
|
314
304
|
|
315
305
|
subdirs = [ subdirs ] unless subdirs.is_a?( Array )
|
316
|
-
PluginFactory
|
306
|
+
PluginFactory.log :debug, "Subdirs are: %p" % [subdirs]
|
317
307
|
fatals = []
|
308
|
+
tries = []
|
318
309
|
|
319
310
|
# Iterate over the subdirs until we successfully require a
|
320
311
|
# module.
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
end
|
344
|
-
}
|
312
|
+
subdirs.collect {|dir| dir.strip}.each do |subdir|
|
313
|
+
self.make_require_path( mod_name, subdir ).each do |path|
|
314
|
+
PluginFactory.log :debug, "Trying #{path}..."
|
315
|
+
tries << path
|
316
|
+
|
317
|
+
# Try to require the module, saving errors and jumping
|
318
|
+
# out of the catch block on success.
|
319
|
+
begin
|
320
|
+
require( path.untaint )
|
321
|
+
rescue LoadError => err
|
322
|
+
PluginFactory.log :debug,
|
323
|
+
"No module at '%s', trying the next alternative: '%s'" %
|
324
|
+
[ path, err.message ]
|
325
|
+
rescue Exception => err
|
326
|
+
fatals << err
|
327
|
+
PluginFactory.log :error,
|
328
|
+
"Found '#{path}', but encountered an error: %s\n\t%s" %
|
329
|
+
[ err.message, err.backtrace.join("\n\t") ]
|
330
|
+
else
|
331
|
+
PluginFactory.log :info, "Loaded '#{path}' without error."
|
332
|
+
return path
|
333
|
+
end
|
345
334
|
end
|
335
|
+
end
|
346
336
|
|
347
|
-
|
348
|
-
|
349
|
-
# Re-raise is there was a file found, but it didn't load for
|
350
|
-
# some reason.
|
351
|
-
if ! fatals.empty?
|
352
|
-
#PluginFactory::log :debug, "Re-raising first fatal error"
|
353
|
-
Kernel::raise( fatals.first )
|
354
|
-
end
|
337
|
+
PluginFactory.log :debug, "fatals = %p" % [ fatals ]
|
355
338
|
|
356
|
-
|
357
|
-
|
339
|
+
# Re-raise is there was a file found, but it didn't load for
|
340
|
+
# some reason.
|
341
|
+
if fatals.empty?
|
342
|
+
errmsg = "Couldn't find a %s named '%s': tried %p" % [
|
343
|
+
self.factory_type,
|
344
|
+
mod_name,
|
345
|
+
tries
|
346
|
+
]
|
347
|
+
PluginFactory.log :error, errmsg
|
348
|
+
raise FactoryError, errmsg
|
349
|
+
else
|
350
|
+
PluginFactory.log :debug, "Re-raising first fatal error"
|
351
|
+
Kernel.raise( fatals.first )
|
352
|
+
end
|
358
353
|
end
|
359
354
|
alias_method :requireDerivative, :require_derivative
|
360
355
|
|
@@ -371,17 +366,20 @@ module PluginFactory
|
|
371
366
|
# Make permutations of the two parts
|
372
367
|
path << modname
|
373
368
|
path << modname.downcase
|
374
|
-
path << modname
|
375
|
-
path << modname.downcase
|
376
|
-
path << modname.downcase
|
369
|
+
path << modname + myname
|
370
|
+
path << modname.downcase + myname
|
371
|
+
path << modname.downcase + myname.downcase
|
372
|
+
path << modname + '_' + myname
|
373
|
+
path << modname.downcase + '_' + myname
|
374
|
+
path << modname.downcase + '_' + myname.downcase
|
377
375
|
|
378
376
|
# If a non-empty subdir was given, prepend it to all the items in the
|
379
377
|
# path
|
380
378
|
unless subdir.nil? or subdir.empty?
|
381
|
-
path.collect! {|m| File
|
379
|
+
path.collect! {|m| File.join(subdir, m)}
|
382
380
|
end
|
383
381
|
|
384
|
-
PluginFactory
|
382
|
+
PluginFactory.log :debug, "Path is: #{path.uniq.reverse.inspect}..."
|
385
383
|
return path.uniq.reverse
|
386
384
|
end
|
387
385
|
alias_method :makeRequirePath, :make_require_path
|