require 'find' require 'fileutils' require 'erb' module Webby # The Builder class performs the work of scanning the content folder, # creating Resource objects, and converting / copying the contents to the # output folder as needed. # class Builder class << self # call-seq: # Builder.run( :rebuild => false ) # # Create a new instance of the Builder class and invoke the run method. # If the :rebuild option is given as +true+, then all pages # will be recreated / copied. # def run( opts = {} ) self.new.run opts end # call-seq: # Builder.create( page, :from => template, :locals => {} ) # # This mehod is used to create a new _page_ in the content folder based # on the specified template. _page_ is the relative path to the new page # from the content/ folder. The _template_ is the name of # the template to use from the templates/ folder. # def create( page, opts = {} ) tmpl = opts[:from] raise Error, "template not given" unless tmpl name = ::Webby::Resources.basename(page) ext = ::Webby::Resources.extname(page) dir = ::File.dirname(page) dir = '' if dir == '.' if tmpl.pathmap('%n') =~ %r/^_/ page = ::File.join(::Webby.site.content_dir, dir, '_'+name) page << '.' << (ext.empty? ? 'txt' : ext) elsif ::Webby.site.create_mode == 'directory' and name != 'index' page = ::File.join(::Webby.site.content_dir, dir, name, 'index') page << '.' << (ext.empty? ? 'txt' : ext) else page = ::File.join(::Webby.site.content_dir, page) page << '.txt' if ext.empty? end raise Error, "#{page} already exists" if test ?e, page Logging::Logger[self].info "creating #{page}" FileUtils.mkdir_p ::File.dirname(page) context = scope opts[:locals].each do |k,v| Thread.current[:value] = v definition = "#{k} = Thread.current[:value]" eval(definition, context) end if opts.has_key?(:locals) str = ERB.new(::File.read(tmpl), nil, '-').result(context) ::File.open(page, 'w') {|fd| fd.write str} page end # call-seq: # Builder.new_page_info => [page, title, directory] # def new_page_info args = Webby.site.args # TODO: maybe even get rid of this method altogether raise "Usage: webby #{args.rake.first} 'path'" if args.raw.empty? [args.page, args.title, args.dir] end private # Returns the binding in the scope of the Builder class object. # def scope() binding end end # class << self # call-seq: # Builder.new # # Creates a new Builder object for creating pages from the content and # layout directories. # def initialize @logger = Logging::Logger[self] end # call-seq: # run( :rebuild => false, :load_files => true ) # # Runs the Webby builder by loading in the layout files from the # layouts/ folder and the content from the # contents/ folder. Content is analyzed, and those that need # to be copied or compiled (filtered using ERB, Texttile, Markdown, etc.) # are handled. The results are placed in the output/ folder. # # If the :rebuild flag is set to +true+, then all content is # copied and/or compiled to the output folder. # # A content file can mark itself as dirty by setting the +dirty+ flag to # +true+ in the meta-data of the file. This will cause the contenet to # always be compiled when the builder is run. Conversely, setting the # dirty flag to +false+ will cause the content to never be compiled or # copied to the output folder. # # A content file needs to be built if the age of the file is less then the # age of the output product -- i.e. the content file has been modified # more recently than the output file. # def run( opts = {} ) opts[:load_files] = true unless opts.has_key?(:load_files) verbose = opts.getopt(:verbose, true) unless test(?d, output_dir) journal.create output_dir FileUtils.mkdir output_dir end ::Webby.load_files if opts[:load_files] Resources.pages.each do |page| unless page.dirty? or opts[:rebuild] journal.identical(page.destination) if verbose next end # copy the resource to the output directory if it is static if page.instance_of? Resources::Static FileUtils.mkdir_p ::File.dirname(page.destination) journal.create_or_update(page) FileUtils.cp page.path, page.destination FileUtils.chmod 0644, page.destination # otherwise, layout the resource and write the results to # the output directory else Renderer.write(page) end end # touch the cairn so we know when the website was last generated FileUtils.touch ::Webby.cairn nil end def load_files ::Webby.deprecated "load_files", "it is being replaced by the Webby#load() method" ::Webby.load_files end %w(output_dir layout_dir content_dir).each do |key| self.class_eval <<-CODE def #{key}( ) ::Webby.site.#{key} end CODE end end # class Builder end # module Webby # EOF