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/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
+