module Crawlable class Feed class << self attr_accessor :options, :call_options, :feeds def feeds @feeds ||= [] @feeds end def paths feeds.map(&:path) end def define!(*args, &block) self.options = args.extract_options!#.merge(:run => args.shift) instance_eval(&block) if block_given? end def find(path, directory) if path =~ /(\/feed\/?)(atom|rss2|rss|rdf)?$/i feed = $1 format = $2 format = format.blank? ? "rss" : format.to_s file = path.gsub(format, "").split("/").delete_if {|i| i.blank? }[0..-2].join("/") return unless self.paths.include?(file) file = file.split("/").join("_") file = File.join(directory, "feeds", "#{file}.#{format}") return file end end def parse!(path, options = {}) path ||= File.join(::Rails.root, 'config/initializers/feeds.rb') self.call_options = options.symbolize_keys eval(IO.read(path)) self.call_options = nil end def write(to, *formats) self.feeds.each { |feed| feed.write(to, *formats) } end def process!(from, to, *formats, &block) parse!(from) write(to, *formats) end def method_missing(meth, *args, &block) if block_given? if !self.call_options.blank? if call_options.has_key?(meth.to_sym) self.feeds << self.new(meth, *args, &block) else super(meth, *args, &block) end else self.feeds << self.new(meth, *args, &block) end else super(meth, *args, &block) end end end attr_accessor :name, :title, :url, :description, :master, :copyright, :updated_at, :path def initialize(*args, &block) options = args.extract_options! self.name = args.shift options.each do |k, v| self.send(k, v) if self.respond_to?(k) end instance_eval(&block) self end def path(value = nil) @path = value if value @path ||= name.to_s @path end def copyright(string = nil) @copyright = string unless string.nil? @copyright end def title(string = nil) @title = string unless string.nil? @title end def description(string = nil) @description = string unless string.nil? @description end def url(string = nil) @url = string unless string.nil? @url end def author(string = nil) @author = string unless string.nil? @author end def master(string = nil) @master = string unless string.nil? @master end def entries @entries ||= [] end def entry(path, *args, &block) options = args.extract_options! result = options.dup result.merge!(:url => path) self.entries.push(result) end def to_rss builder = Nokogiri::XML::Builder.new do |xml| xml.rss "xmlns:dc" => "http://purl.org/dc/elements/1.1/" do xml.channel do xml.title self.title xml.link self.url xml.description self.description self.entries.each do |entry| xml.item do xml.title entry[:title] xml.link entry[:url] xml.description entry[:description] xml.guid entry[:guid] || entry[:url] xml.author entry[:author] unless entry[:author].blank? entry[:categories].each do |category| xml.category category end unless entry[:categories].blank? xml.comments entry[:comments] unless entry[:comments].blank? xml.enclosure( :url => entry[:asset], :length => IO.size(entry[:asset]).to_s, :type => entry[:asset_type] ) unless entry[:asset].blank? xml.webMaster self.master unless self.master.blank? end end end end end builder.to_xml end def to_atom builder = Nokogiri::XML::Builder.new do |xml| xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do xml.title self.title #xml.link "rel" => "self", "href" => url_for(:only_path => false, :controller => 'feeds', :action => 'atom') #xml.link "rel" => "alternate", "href" => url_for(:only_path => false, :controller => 'posts') #xml.id url_for(:only_path => false, :controller => 'posts') xml.updated self.updated_at.strftime "%Y-%m-%dT%H:%M:%SZ" if self.updated_at xml.author { xml.name self.author } self.entries.each do |entry| xml.entry do xml.title entry[:title] #xml.link "rel" => "alternate", "href" => url_for(:only_path => false, :controller => 'posts', :action => 'show', :id => entry[:id]) #xml.id url_for(:only_path => false, :controller => 'posts', :action => 'show', :id => entry[:id]) xml.updated entry[:updated_at].strftime "%Y-%m-%dT%H:%M:%SZ" xml.author { xml.name entry[:author] } if entry[:author] xml.summary "Post summary" xml.content "type" => "html" do #xml.text! render(:partial => "posts/post", :post => post) end end end end end builder.to_xml end def write(to, *formats) formats.each do |format| FileUtils.mkdir_p(File.dirname(to)) File.open("#{to}.#{format.to_s}", 'wb') do |file| file.puts send("to_#{format.to_s}") end end end end end