require 'active_support' require 'active_support/core_ext/array' module Plate # The Dsl class provides the methods available in plugin files in order to extend # the functionality a generated site. class Dsl class << self # Evaluate the given file path into the {Plate::Dsl dsl} instance. def evaluate_plugin(file_path) instance_eval_plugin(read_plugin_file(file_path)) end # Performs evaluation of the file's content def instance_eval_plugin(content) new.instance_eval(content) end # Read the given plugin file path into a string # # @return [String] The plugin file's contents def read_plugin_file(file_path) File.read(file_path) rescue raise PluginNotReadable end end # Used for writing dynamic pages. Allows for calling: # # title "Test" # layout "default" # # Instead of: # # self.title = "Test" # self.layout = "default" # class PageProxy def initialize(page, site) @page = page @site = site end %w( category month year month_name ).each do |m| class_eval <<-META def _#{m}=(val) # def _category=(val) @_#{m} = val # @_category = val end # end def #{m} # def category defined?(@_#{m}) ? @_#{m} : nil # defined?(@_category) ? @_category : nil end # end META end def site @site end def method_missing(method, *args) if @page.respond_to?("#{method}=") @page.send("#{method}=", *args) else @page.send(method, *args) end end def to_url(*args) @site.to_url(*args) end end # Loop through the given item name to generate archive pages. # # Available item types are: # # * :category # * :tag # * :year # * :month # * :day # def archives(item_type, options = {}, &block) # If there is a method to return the list of items if self.respond_to?("archive_#{item_type}_items") self.send("archive_#{item_type}_items", options, &block) end end # Register a new callback for the given object and event. # # @example Run block after rendering a site # callback :site, :after_render do # puts 'done!' # end # # @example Run block before rendering a page # callback :page, :before_render do |page| # puts "Rendering page #{page.path}" # end # # @example Run a method on the site after write # class Site # def finished! # log('All done.') # end # end # # callback :site, :after_write, :finished! # def callback(object, event, method_name = nil, &block) if Symbol === object object = "Plate::#{object.to_s.classify}".constantize end object.register_callback(event, method_name, &block) end alias :register_callback :callback # Set up a new engine designed for rendering dynamic assets. # Engines should be compatible with the Tilt::Template syntax. def register_asset_engine(extension, klass) Plate.register_asset_engine(extension, klass) end # Set up a new engine designed for rendering dynamic assets. # Engines should be compatible with the Tilt::Template syntax. def register_template_engine(extension, klass) Plate.register_template_engine(extension, klass) end # Create and write a dynamic page. Pages are written during the Site.after_render # callback. def write_page(path, site = nil, &block) delayed_write = lambda { |site| page = DynamicPage.new(site, path) proxy = PageProxy.new(page, site) proxy.instance_eval(&block) page.write! proxy = nil page = nil } # If a site was passed to the write method, use it. if site delayed_write.call(site) # If no site was sent to the write method, run it after site render else callback :site, :after_render do |rendered_site| delayed_write.call(rendered_site) end end end alias :write :write_page protected # Category archives def archive_category_items(options, &block) callback :site, :after_render do |site| site.categories.each do |category| page = DynamicPage.new(site, "/categories/#{category}") proxy = PageProxy.new(page, site) proxy._category = category page.meta[:category] = category proxy.instance_eval(&block) page.write! proxy = nil page = nil end end end # Monthly archive rendering def archive_month_items(options, &block) filter_year = options[:year] || nil filter_category = options[:category] || nil callback :site, :after_render do |site| site.posts.archives.keys.each do |year| if filter_year == nil or filter_year == year site.posts.archives[year].keys.each do |month| posts = [] site.posts.archives[year][month].each_value do |day| posts << day.select { |post| filter_category == nil or post.category == filter_category } end posts = posts.flatten.sort { |x,y| x.name <=> y.name } if posts.size > 0 page = DynamicPage.new(site, "/archives/#{year}/#{month}") proxy = PageProxy.new(page, site) proxy._year = year proxy._month = month proxy._month_name = Date.new(year.to_i, month.to_i, 1).strftime('%B %Y') proxy._category = filter_category if filter_category proxy.locals = { :monthly_posts => posts, :month => month, :year => year } proxy.instance_eval(&block) page.write! proxy = nil page = nil end end end end end end # Yearly archive rendering def archive_year_items(options, &block) filter_category = options[:category] || nil callback :site, :after_render do |site| site.posts.archives.keys.each do |year| posts = [] site.posts.archives[year].keys.each do |month| site.posts.archives[year][month].each_value do |day| posts << day.select { |post| filter_category == nil or post.category == filter_category } end end posts = posts.flatten.sort { |x,y| x.name <=> y.name } if posts.size > 0 page = DynamicPage.new(site, "/archives/#{year}") proxy = PageProxy.new(page, site) proxy._year = year proxy._category = filter_category if filter_category proxy.locals = { :yearly_posts => posts, :year => year } proxy.instance_eval(&block) page.write! proxy = nil page = nil end end end end # Paged archived posts def archive_paged_items(options, &block) filter_category = options[:category] || nil per_page = options[:per_page] || 10 callback :site, :after_render do |site| posts = [] current_page = 1 site.posts.archives.keys.each do |year| site.posts.archives[year].keys.each do |month| site.posts.archives[year][month].each_value do |day| posts << day.select { |post| filter_category == nil or post.category == filter_category } end end end posts = posts.flatten.sort { |x,y| x.name <=> y.name } groups = posts.reverse.in_groups_of(per_page, false) groups.each do |group| page = DynamicPage.new(site, "/page/#{current_page}") proxy = PageProxy.new(page, site) proxy._category = filter_category if filter_category proxy.locals = { :current_page => current_page, :previous_page => (current_page > 1 ? (current_page - 1) : nil), :next_page => (current_page < groups.size ? (current_page + 1) : nil), :paged_posts => group, :page => current_page } proxy.instance_eval(&block) page.write! proxy = nil page = nil current_page = current_page + 1 end end end end end