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/rake/manual.rb
ADDED
@@ -0,0 +1,384 @@
|
|
1
|
+
#
|
2
|
+
# Manual-generation Rake tasks and classes
|
3
|
+
# $Id: manual.rb 10 2008-07-18 15:52:48Z deveiant $
|
4
|
+
#
|
5
|
+
# Author: Michael Granger <ged@FaerieMUD.org>
|
6
|
+
#
|
7
|
+
# This was born out of a frustration with other static HTML generation modules
|
8
|
+
# and systems. I've tried webby, webgen, rote, staticweb, staticmatic, and
|
9
|
+
# nanoc, but I didn't find any of them really suitable (except rote, which was
|
10
|
+
# excellent but apparently isn't maintained and has a fundamental
|
11
|
+
# incompatibilty with Rake because of some questionable monkeypatching.)
|
12
|
+
#
|
13
|
+
# So, since nothing seemed to scratch my itch, I'm going to scratch it myself.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'pathname'
|
17
|
+
require 'singleton'
|
18
|
+
require 'rake/tasklib'
|
19
|
+
require 'erb'
|
20
|
+
|
21
|
+
|
22
|
+
### Namespace for Manual-generation classes
|
23
|
+
module Manual
|
24
|
+
|
25
|
+
### Manual page-generation class
|
26
|
+
class Page
|
27
|
+
|
28
|
+
### An abstract filter class for manual content transformation.
|
29
|
+
class Filter
|
30
|
+
include Singleton
|
31
|
+
|
32
|
+
# A list of inheriting classes, keyed by normalized name
|
33
|
+
@derivatives = {}
|
34
|
+
class << self; attr_reader :derivatives; end
|
35
|
+
|
36
|
+
### Inheritance callback -- keep track of all inheriting classes for
|
37
|
+
### later.
|
38
|
+
def self::inherited( subclass )
|
39
|
+
key = subclass.name.
|
40
|
+
sub( /^.*::/, '' ).
|
41
|
+
gsub( /[^[:alpha:]]+/, '_' ).
|
42
|
+
downcase.
|
43
|
+
sub( /filter$/, '' )
|
44
|
+
|
45
|
+
self.derivatives[ key ] = subclass
|
46
|
+
self.derivatives[ key.to_sym ] = subclass
|
47
|
+
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
### Process the +page+'s source with the filter and return the altered content.
|
53
|
+
def process( source, page, metadata )
|
54
|
+
raise NotImplementedError,
|
55
|
+
"%s does not implement the #process method" % [ self.class.name ]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
### The default page configuration if none is specified.
|
61
|
+
DEFAULT_CONFIG = {
|
62
|
+
'filters' => [ 'textile', 'erb' ],
|
63
|
+
'layout' => 'default.page',
|
64
|
+
}.freeze
|
65
|
+
|
66
|
+
# Pattern to match a source page with a YAML header
|
67
|
+
PAGE_WITH_YAML_HEADER = /
|
68
|
+
\A---\s*$ # It should should start with three hyphens
|
69
|
+
(.*?) # ...have some YAML stuff
|
70
|
+
^---\s*$ # then have another three-hyphen line,
|
71
|
+
(.*)\Z # then the rest of the document
|
72
|
+
/xm
|
73
|
+
|
74
|
+
# Options to pass to libtidy
|
75
|
+
TIDY_OPTIONS = {
|
76
|
+
:show_warnings => true,
|
77
|
+
:indent => false,
|
78
|
+
:indent_attributes => false,
|
79
|
+
:indent_spaces => 4,
|
80
|
+
:vertical_space => true,
|
81
|
+
:tab_size => 4,
|
82
|
+
:wrap_attributes => true,
|
83
|
+
:wrap => 100,
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
### Create a new page-generator for the given +sourcefile+, which will use
|
88
|
+
### ones of the templates in +layouts_dir+ as a wrapper.
|
89
|
+
def initialize( sourcefile, layouts_dir )
|
90
|
+
@sourcefile = Pathname.new( sourcefile )
|
91
|
+
@layouts_dir = Pathname.new( layouts_dir )
|
92
|
+
|
93
|
+
rawsource = @sourcefile.read
|
94
|
+
@config, @source = self.read_page_config( rawsource )
|
95
|
+
# $stderr.puts "Config is: %p" % [@config],
|
96
|
+
# "Source is: %p" % [ @source[0,100] ]
|
97
|
+
@filters = self.load_filters( @config['filters'] )
|
98
|
+
|
99
|
+
super()
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
######
|
104
|
+
public
|
105
|
+
######
|
106
|
+
|
107
|
+
# The Pathname object that specifys the page source file
|
108
|
+
attr_reader :sourcefile
|
109
|
+
|
110
|
+
# The configured layouts directory as a Pathname object.
|
111
|
+
attr_reader :layouts_dir
|
112
|
+
|
113
|
+
# The page configuration, as read from its YAML header
|
114
|
+
attr_reader :config
|
115
|
+
|
116
|
+
# The raw source of the page
|
117
|
+
attr_reader :source
|
118
|
+
|
119
|
+
# The filters the page will use to render itself
|
120
|
+
attr_reader :filters
|
121
|
+
|
122
|
+
|
123
|
+
### Generate HTML output from the page and return it.
|
124
|
+
def generate( metadata )
|
125
|
+
content = self.generate_content( @source, metadata )
|
126
|
+
|
127
|
+
# :TODO: Read config from page for layout, filters, etc.
|
128
|
+
templatepath = @layouts_dir + 'default.page'
|
129
|
+
template = ERB.new( templatepath.read )
|
130
|
+
page = self
|
131
|
+
|
132
|
+
html = template.result( binding() )
|
133
|
+
|
134
|
+
# return self.cleanup( html )
|
135
|
+
return html
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
### Run the various filters on the given input and return the transformed
|
140
|
+
### content.
|
141
|
+
def generate_content( input, metadata )
|
142
|
+
return @filters.inject( input ) do |source, filter|
|
143
|
+
filter.process( source, self, metadata )
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
### Trim the YAML header from the provided page +source+, convert it to
|
149
|
+
### a Ruby object, and return it.
|
150
|
+
def read_page_config( source )
|
151
|
+
unless source =~ PAGE_WITH_YAML_HEADER
|
152
|
+
return DEFAULT_CONFIG.dup, source
|
153
|
+
end
|
154
|
+
|
155
|
+
pageconfig = YAML.load( $1 )
|
156
|
+
source = $2
|
157
|
+
|
158
|
+
return DEFAULT_CONFIG.merge( pageconfig ), source
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
### Clean up and return the given HTML +source+.
|
163
|
+
def cleanup( source )
|
164
|
+
require 'tidy'
|
165
|
+
|
166
|
+
Tidy.path = '/usr/lib/libtidy.dylib'
|
167
|
+
Tidy.open( TIDY_OPTIONS ) do |tidy|
|
168
|
+
tidy.options.output_xhtml = true
|
169
|
+
|
170
|
+
xml = tidy.clean( source )
|
171
|
+
puts tidy.errors
|
172
|
+
puts tidy.diagnostics
|
173
|
+
return xml
|
174
|
+
end
|
175
|
+
rescue LoadError => err
|
176
|
+
trace "No cleanup: " + err.message
|
177
|
+
return source
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
### Get (singleton) instances of the filters named in +filterlist+ and return them.
|
182
|
+
def load_filters( filterlist )
|
183
|
+
filterlist.flatten.collect do |key|
|
184
|
+
raise ArgumentError, "filter '#{key}' is not loaded" unless
|
185
|
+
Manual::Page::Filter.derivatives.key?( key )
|
186
|
+
Manual::Page::Filter.derivatives[ key ].instance
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
### A Textile filter for the manual generation tasklib, implemented using RedCloth.
|
194
|
+
class TextileFilter < Manual::Page::Filter
|
195
|
+
|
196
|
+
### Load RedCloth when the filter is first created
|
197
|
+
def initialize( *args )
|
198
|
+
require 'redcloth'
|
199
|
+
super
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
### Process the given +source+ as Textile and return the resulting HTML
|
204
|
+
### fragment.
|
205
|
+
def process( source, *ignored )
|
206
|
+
return RedCloth.new( source ).to_html
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
### An ERB filter for the manual generation tasklib, implemented using Erubis.
|
213
|
+
class ErbFilter < Manual::Page::Filter
|
214
|
+
|
215
|
+
### Process the given +source+ as ERB and return the resulting HTML
|
216
|
+
### fragment.
|
217
|
+
def process( source, page, metadata )
|
218
|
+
template_name = page.sourcefile.basename
|
219
|
+
template = ERB.new( source )
|
220
|
+
return template.result( binding() )
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
### Manual generation task library
|
227
|
+
class GenTask < Rake::TaskLib
|
228
|
+
|
229
|
+
# Default values for task config variables
|
230
|
+
DEFAULT_NAME = :manual
|
231
|
+
DEFAULT_BASE_DIR = Pathname.new( 'docs/manual' )
|
232
|
+
DEFAULT_SOURCE_DIR = 'source'
|
233
|
+
DEFAULT_LAYOUTS_DIR = 'layouts'
|
234
|
+
DEFAULT_OUTPUT_DIR = 'output'
|
235
|
+
DEFAULT_RESOURCE_DIR = 'resources'
|
236
|
+
DEFAULT_LIB_DIR = 'lib'
|
237
|
+
DEFAULT_METADATA = OpenStruct.new
|
238
|
+
|
239
|
+
|
240
|
+
### Define a new manual-generation task with the given +name+.
|
241
|
+
def initialize( name=:manual )
|
242
|
+
@name = name
|
243
|
+
|
244
|
+
@source_dir = DEFAULT_SOURCE_DIR
|
245
|
+
@layouts_dir = DEFAULT_LAYOUTS_DIR
|
246
|
+
@output_dir = DEFAULT_OUTPUT_DIR
|
247
|
+
@resource_dir = DEFAULT_RESOURCE_DIR
|
248
|
+
@lib_dir = DEFAULT_LIB_DIR
|
249
|
+
@metadata = DEFAULT_METADATA
|
250
|
+
|
251
|
+
yield( self ) if block_given?
|
252
|
+
|
253
|
+
self.define
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
######
|
258
|
+
public
|
259
|
+
######
|
260
|
+
|
261
|
+
attr_accessor :base_dir,
|
262
|
+
:source_dir,
|
263
|
+
:layouts_dir,
|
264
|
+
:output_dir,
|
265
|
+
:resource_dir,
|
266
|
+
:lib_dir,
|
267
|
+
:metadata
|
268
|
+
|
269
|
+
attr_reader :name
|
270
|
+
|
271
|
+
### Load the filter libraries provided in the given +libdir+
|
272
|
+
def load_filter_libraries( libdir )
|
273
|
+
Pathname.glob( libdir + '*.rb' ) do |filterlib|
|
274
|
+
trace " loading filter library #{filterlib}"
|
275
|
+
require( filterlib )
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
### Set up the main HTML-generation task that will convert files in the given +sourcedir+ to
|
281
|
+
### HTML in the +outputdir+
|
282
|
+
def setup_page_conversion_tasks( sourcedir, outputdir, layoutsdir )
|
283
|
+
source_glob = sourcedir + '**/*.page'
|
284
|
+
trace "Looking for sources that match: %s" % [ source_glob ]
|
285
|
+
|
286
|
+
# Find the list of source .page files
|
287
|
+
manual_sources = FileList[ source_glob ]
|
288
|
+
trace " found %d source files" % [ manual_sources.length ]
|
289
|
+
|
290
|
+
# Map .page files to their equivalent .html output
|
291
|
+
html_pathmap = "%%{%s,%s}X.html" % [ sourcedir, outputdir ]
|
292
|
+
manual_pages = manual_sources.pathmap( html_pathmap )
|
293
|
+
trace "Mapping sources like so: \n %p -> %p" %
|
294
|
+
[ manual_sources.first, manual_pages.first ]
|
295
|
+
|
296
|
+
# Output directory task
|
297
|
+
directory( outputdir.to_s )
|
298
|
+
file outputdir.to_s do
|
299
|
+
touch outputdir + '.buildtime'
|
300
|
+
end
|
301
|
+
|
302
|
+
# Rule to generate .html files from .page files
|
303
|
+
rule(
|
304
|
+
%r{#{outputdir}/.*\.html$} => [
|
305
|
+
proc {|name| name.sub(/\.[^.]+$/, '.page').sub( outputdir, sourcedir) },
|
306
|
+
outputdir.to_s
|
307
|
+
]) do |task|
|
308
|
+
|
309
|
+
source = Pathname.new( task.source ).relative_path_from( Pathname.getwd )
|
310
|
+
target = Pathname.new( task.name ).relative_path_from( Pathname.getwd )
|
311
|
+
log " #{ source } -> #{ target }"
|
312
|
+
|
313
|
+
page = Manual::Page.new( source, layoutsdir )
|
314
|
+
|
315
|
+
target.dirname.mkpath
|
316
|
+
target.open( File::WRONLY|File::CREAT|File::TRUNC ) do |io|
|
317
|
+
io.write( page.generate(metadata) )
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
return manual_pages
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
### Set up a rule for copying files from the resources directory to the output dir.
|
326
|
+
def setup_resource_copy_tasks( resourcedir, outputdir )
|
327
|
+
|
328
|
+
task :copy_resources => [ outputdir.to_s ] do
|
329
|
+
when_writing( "Copying resources" ) do
|
330
|
+
verbose do
|
331
|
+
files = FileList[ resourcedir + '*' ]
|
332
|
+
files.exclude( /\.svn/ )
|
333
|
+
unless files.empty?
|
334
|
+
trace " Copying resource files: #{files}"
|
335
|
+
cp_r files, outputdir, :verbose => true
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
### Set up the tasks for building the manual
|
344
|
+
def define
|
345
|
+
|
346
|
+
# Set up a description if the caller hasn't already defined one
|
347
|
+
unless Rake.application.last_comment
|
348
|
+
desc "Generate the manual"
|
349
|
+
end
|
350
|
+
|
351
|
+
# Make Pathnames of the directories relative to the base_dir
|
352
|
+
basedir = Pathname.new( @base_dir )
|
353
|
+
sourcedir = basedir + @source_dir
|
354
|
+
layoutsdir = basedir + @layouts_dir
|
355
|
+
outputdir = basedir + @output_dir
|
356
|
+
resourcedir = basedir + @resource_dir
|
357
|
+
libdir = basedir + @lib_dir
|
358
|
+
|
359
|
+
load_filter_libraries( libdir )
|
360
|
+
|
361
|
+
# Declare the tasks outside the namespace that point in
|
362
|
+
task @name => "#@name:build"
|
363
|
+
task "clobber_#@name" => "#@name:clobber"
|
364
|
+
|
365
|
+
namespace( self.name ) do
|
366
|
+
setup_resource_copy_tasks( resourcedir, outputdir )
|
367
|
+
manual_pages = setup_page_conversion_tasks( sourcedir, outputdir, layoutsdir )
|
368
|
+
|
369
|
+
task :build => [ :copy_resources, *manual_pages ]
|
370
|
+
|
371
|
+
task :clobber do
|
372
|
+
RakeFileUtils.verbose( $verbose ) do
|
373
|
+
rm_f manual_pages.to_a
|
374
|
+
end
|
375
|
+
remove_dir( outputdir ) if ( outputdir + '.buildtime' ).exist?
|
376
|
+
end
|
377
|
+
task :rebuild => [ :clobber, :build ]
|
378
|
+
end
|
379
|
+
|
380
|
+
end # def define
|
381
|
+
|
382
|
+
end # class Manual::GenTask
|
383
|
+
|
384
|
+
end
|
data/rake/packaging.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#
|
2
|
+
# Packaging Rake Tasks
|
3
|
+
# $Id: packaging.rb 21 2008-08-07 23:45:52Z deveiant $
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'rbconfig'
|
7
|
+
require 'rake/packagetask'
|
8
|
+
require 'rake/gempackagetask'
|
9
|
+
|
10
|
+
include Config
|
11
|
+
|
12
|
+
### Task: gem
|
13
|
+
### Task: package
|
14
|
+
Rake::PackageTask.new( PKG_NAME, PKG_VERSION ) do |task|
|
15
|
+
task.need_tar_gz = true
|
16
|
+
task.need_tar_bz2 = true
|
17
|
+
task.need_zip = true
|
18
|
+
task.package_dir = PKGDIR.to_s
|
19
|
+
task.package_files = RELEASE_FILES.
|
20
|
+
collect {|f| f.relative_path_from(BASEDIR).to_s }
|
21
|
+
end
|
22
|
+
task :package => [:gem]
|
23
|
+
|
24
|
+
|
25
|
+
### Task: gem
|
26
|
+
gempath = PKGDIR + GEM_FILE_NAME
|
27
|
+
|
28
|
+
desc "Build a RubyGem package (#{GEM_FILE_NAME})"
|
29
|
+
task :gem => gempath.to_s
|
30
|
+
file gempath.to_s => [PKGDIR.to_s] + GEMSPEC.files do
|
31
|
+
when_writing( "Creating GEM" ) do
|
32
|
+
Gem::Builder.new( GEMSPEC ).build
|
33
|
+
verbose( true ) do
|
34
|
+
mv GEM_FILE_NAME, gempath
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
### Task: install
|
40
|
+
desc "Install #{PKG_NAME} as a conventional library"
|
41
|
+
task :install do
|
42
|
+
log "Installing #{PKG_NAME} as a conventional library"
|
43
|
+
sitelib = Pathname.new( CONFIG['sitelibdir'] )
|
44
|
+
sitearch = Pathname.new( CONFIG['sitearchdir'] )
|
45
|
+
Dir.chdir( LIBDIR ) do
|
46
|
+
LIB_FILES.each do |libfile|
|
47
|
+
relpath = libfile.relative_path_from( LIBDIR )
|
48
|
+
target = sitelib + relpath
|
49
|
+
FileUtils.mkpath target.dirname,
|
50
|
+
:mode => 0755, :verbose => true, :noop => $dryrun unless target.dirname.directory?
|
51
|
+
FileUtils.install relpath, target,
|
52
|
+
:mode => 0644, :verbose => true, :noop => $dryrun
|
53
|
+
end
|
54
|
+
end
|
55
|
+
if EXTDIR.exist?
|
56
|
+
Dir.chdir( EXTDIR ) do
|
57
|
+
Pathname.glob( EXTDIR + Config::CONFIG['DLEXT'] ) do |dl|
|
58
|
+
target = sitearch + dl.basename
|
59
|
+
FileUtils.install dl, target,
|
60
|
+
:mode => 0755, :verbose => true, :noop => $dryrun
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
### Task: install_gem
|
69
|
+
desc "Install #{PKG_NAME} from a locally-built gem"
|
70
|
+
task :install_gem => [:package] do
|
71
|
+
$stderr.puts
|
72
|
+
installer = Gem::Installer.new( %{pkg/#{PKG_FILE_NAME}.gem} )
|
73
|
+
installer.install
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
### Task: uninstall
|
78
|
+
desc "Uninstall #{PKG_NAME} if it's been installed as a conventional library"
|
79
|
+
task :uninstall do
|
80
|
+
log "Uninstalling conventionally-installed #{PKG_NAME} library files"
|
81
|
+
sitelib = Pathname.new( CONFIG['sitelibdir'] )
|
82
|
+
sitearch = Pathname.new( CONFIG['sitearchdir'] )
|
83
|
+
|
84
|
+
Dir.chdir( LIBDIR ) do
|
85
|
+
LIB_FILES.each do |libfile|
|
86
|
+
relpath = libfile.relative_path_from( LIBDIR )
|
87
|
+
target = sitelib + relpath
|
88
|
+
FileUtils.rm_f target, :verbose => true, :noop => $dryrun
|
89
|
+
FileUtils.rm_rf( target.dirname, :verbose => true, :noop => $dryrun ) if
|
90
|
+
target.dirname.entries.empty?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
if EXTDIR.exist?
|
94
|
+
Dir.chdir( EXTDIR ) do
|
95
|
+
Pathname.glob( EXTDIR + Config::CONFIG['DLEXT'] ) do |dl|
|
96
|
+
target = sitearch + dl.basename
|
97
|
+
FileUtils.rm target, :verbose => true, :noop => $dryrun
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
### Task: uninstall_gem
|
105
|
+
desc "Install the #{PKG_NAME} gem"
|
106
|
+
task :uninstall_gem => [:clean] do
|
107
|
+
uninstaller = Gem::Uninstaller.new( PKG_FILE_NAME )
|
108
|
+
uninstaller.uninstall
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
|