require 'active_record' module ActiveRecord # :nodoc: module Acts # :nodoc: module AsMarkup def self.included(base) # :nodoc: base.extend(ClassMethods) end module ClassMethods # This allows you to specify columns you want to define as containing # Markdown, Textile, Wikitext or RDoc content. # Then you can simply call .to_html method on the attribute. # # You can also specify the language as :variable. The language used # to process the column will be based on another column. By default a column # named "markup_language" is used, but this can be changed by providing # a :language_column option. When a value is accessed it will create # the correct object (Markdown, Textile, Wikitext or RDoc) based on the value # of the language column. If any value besides markdown, textile, wikitext, or # RDoc is supplied for the markup language the text will pass through as a string. # # You can specify additional options to pass to the markup library by using # :markdown_options, :textile_options or :wikitext_options. # RDoc does not support any useful options. The options should be given as an array # of arguments. You can specify options for more than one language when using # :variable. See each library's documentation for more details on what # options are available. # # # ==== Examples # # ===== Using Markdown language # # class Post < ActiveRecord # acts_as_markup :language => :markdown, :columns => [:body] # end # # @post = Post.find(:first) # @post.body.to_s # => "## Markdown Headline" # @post.body.to_html # => "

Markdown Headline

" # # # ===== Using variable language # # class Post < ActiveRecord # acts_as_markup :language => :variable, :columns => [:body], :language_column => 'language_name' # end # # @post = Post.find(:first) # @post.language_name # => "markdown" # @post.body.to_s # => "## Markdown Headline" # @post.body.to_html # => "

Markdown Headline

" # # # ===== Using options # # class Post < ActiveRecord # acts_as_markup :language => :markdown, :columns => [:body], :markdown_options => [ :filter_html ] # end # # class Post < ActiveRecord # acts_as_markup :language => :textile, :columns => [:body], :textile_options => [ [ :filter_html ] ] # end # # class Post < ActiveRecord # acts_as_markup :language => :wikitext, :columns => [:body], :wikitext_options => [ { :space_to_underscore => true } ] # end # # def acts_as_markup(options) case options[:language].to_sym when :markdown, :textile, :wikitext, :rdoc klass = require_library_and_get_class(options[:language].to_sym) when :variable markup_klasses = {} [:textile, :wikitext, :rdoc, :markdown].each do |language| markup_klasses[language] = require_library_and_get_class(language) end options[:language_column] ||= :markup_language else raise ActsAsMarkup::UnsupportedMarkupLanguage, "#{options[:langauge]} is not a currently supported markup language." end unless options[:language].to_sym == :variable markup_options = options["#{options[:language]}_options".to_sym] || [] options[:columns].each do |col| define_method col do if instance_variable_defined?("@#{col}") unless send("#{col}_changed?") return instance_variable_get("@#{col}") end end instance_variable_set("@#{col}", klass.new(self[col].to_s, *markup_options)) end end else options[:columns].each do |col| define_method col do if instance_variable_defined?("@#{col}") unless send("#{col}_changed?") || send("#{options[:language_column]}_changed?") return instance_variable_get("@#{col}") end end instance_variable_set("@#{col}", case send(options[:language_column]) when /markdown/i markup_klasses[:markdown].new self[col].to_s, *(options[:markdown_options] || []) when /textile/i markup_klasses[:textile].new self[col].to_s, *(options[:textile_options] || []) when /wikitext/i markup_klasses[:wikitext].new self[col].to_s, *(options[:wikitext_options] || []) when /rdoc/i markup_klasses[:rdoc].new self[col].to_s else self[col] end) end end end end # This is a convenience method for # `acts_as_markup :language => :markdown, :columns => [:body]` # Additional options can be given at the end, if necessary. # def acts_as_markdown(*columns) options = columns.extract_options! acts_as_markup options.merge(:language => :markdown, :columns => columns) end # This is a convenience method for # `acts_as_markup :language => :textile, :columns => [:body]` # Additional options can be given at the end, if necessary. # def acts_as_textile(*columns) options = columns.extract_options! acts_as_markup options.merge(:language => :textile, :columns => columns) end # This is a convenience method for # `acts_as_markup :language => :wikitext, :columns => [:body]` # Additional options can be given at the end, if necessary. # def acts_as_wikitext(*columns) options = columns.extract_options! acts_as_markup options.merge(:language => :wikitext, :columns => columns) end # This is a convenience method for # `acts_as_markup :language => :rdoc, :columns => [:body]` # Additional options can be given at the end, if necessary. # def acts_as_rdoc(*columns) options = columns.extract_options! acts_as_markup options.merge(:language => :rdoc, :columns => columns) end private def get_markdown_class if ActsAsMarkup::MARKDOWN_LIBS.keys.include? ActsAsMarkup.markdown_library markdown_library_names = ActsAsMarkup::MARKDOWN_LIBS[ActsAsMarkup.markdown_library] require markdown_library_names[:lib_name] require_extensions(markdown_library_names[:lib_name]) return markdown_library_names[:class_name].constantize else raise ActsAsMarkup::UnsportedMarkdownLibrary, "#{ActsAsMarkup.markdown_library} is not currently supported." end end def require_extensions(library)# :nodoc: if ActsAsMarkup::LIBRARY_EXTENSIONS.include? library.to_s require "#{ActsAsMarkup::LIBPATH}/acts_as_markup/exts/#{library}" end end def require_library_and_get_class(language) case language when :markdown return get_markdown_class when :textile require 'redcloth' return RedCloth when :wikitext require 'wikitext' require_extensions 'wikitext' return WikitextString when :rdoc require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' require_extensions 'rdoc' return RDocText else return String end end end end end end ActiveRecord::Base.send :include, ActiveRecord::Acts::AsMarkup