Chris@0: module CodeRay
Chris@0: module Encoders
Chris@0:
Chris@0: class HTML
Chris@0:
Chris@0: # This module is included in the output String from thew HTML Encoder.
Chris@0: #
Chris@0: # It provides methods like wrap, div, page etc.
Chris@0: #
Chris@0: # Remember to use #clone instead of #dup to keep the modules the object was
Chris@0: # extended with.
Chris@0: #
Chris@0: # TODO: more doc.
Chris@0: module Output
Chris@0:
Chris@0: require 'coderay/encoders/html/numerization.rb'
Chris@0:
Chris@0: attr_accessor :css
Chris@0:
Chris@0: class << self
Chris@0:
Chris@0: # This makes Output look like a class.
Chris@0: #
Chris@0: # Example:
Chris@0: #
Chris@0: # a = Output.new 'Code'
Chris@0: # a.wrap! :page
Chris@0: def new string, css = CSS.new, element = nil
Chris@0: output = string.clone.extend self
Chris@0: output.wrapped_in = element
Chris@0: output.css = css
Chris@0: output
Chris@0: end
Chris@0:
Chris@0: # Raises an exception if an object that doesn't respond to to_str is extended by Output,
Chris@0: # to prevent users from misuse. Use Module#remove_method to disable.
Chris@0: def extended o
Chris@0: warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str
Chris@0: end
Chris@0:
Chris@0: def make_stylesheet css, in_tag = false
Chris@0: sheet = css.stylesheet
Chris@0: sheet = <<-CSS if in_tag
Chris@0:
Chris@0: CSS
Chris@0: sheet
Chris@0: end
Chris@0:
Chris@0: def page_template_for_css css
Chris@0: sheet = make_stylesheet css
Chris@0: PAGE.apply 'CSS', sheet
Chris@0: end
Chris@0:
Chris@0: # Define a new wrapper. This is meta programming.
Chris@0: def wrapper *wrappers
Chris@0: wrappers.each do |wrapper|
Chris@0: define_method wrapper do |*args|
Chris@0: wrap wrapper, *args
Chris@0: end
Chris@0: define_method "#{wrapper}!".to_sym do |*args|
Chris@0: wrap! wrapper, *args
Chris@0: end
Chris@0: end
Chris@0: end
Chris@0:
Chris@0: end
Chris@0:
Chris@0: wrapper :div, :span, :page
Chris@0:
Chris@0: def wrapped_in? element
Chris@0: wrapped_in == element
Chris@0: end
Chris@0:
Chris@0: def wrapped_in
Chris@0: @wrapped_in ||= nil
Chris@0: end
Chris@0: attr_writer :wrapped_in
Chris@0:
Chris@0: def wrap_in template
Chris@0: clone.wrap_in! template
Chris@0: end
Chris@0:
Chris@0: def wrap_in! template
Chris@0: Template.wrap! self, template, 'CONTENT'
Chris@0: self
Chris@0: end
Chris@0:
Chris@0: def apply_title! title
Chris@0: self.sub!(/(
)(<\/title>)/) { $1 + title + $2 }
Chris@0: self
Chris@0: end
Chris@0:
Chris@0: def wrap! element, *args
Chris@0: return self if not element or element == wrapped_in
Chris@0: case element
Chris@0: when :div
Chris@0: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
Chris@0: wrap_in! DIV
Chris@0: when :span
Chris@0: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
Chris@0: wrap_in! SPAN
Chris@0: when :page
Chris@0: wrap! :div if wrapped_in? nil
Chris@0: raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div
Chris@0: wrap_in! Output.page_template_for_css(@css)
Chris@0: if args.first.is_a?(Hash) && title = args.first[:title]
Chris@0: apply_title! title
Chris@0: end
Chris@0: self
Chris@0: when nil
Chris@0: return self
Chris@0: else
Chris@0: raise "Unknown value %p for :wrap" % element
Chris@0: end
Chris@0: @wrapped_in = element
Chris@0: self
Chris@0: end
Chris@0:
Chris@0: def wrap *args
Chris@0: clone.wrap!(*args)
Chris@0: end
Chris@0:
Chris@0: def stylesheet in_tag = false
Chris@0: Output.make_stylesheet @css, in_tag
Chris@0: end
Chris@0:
Chris@0: class Template < String
Chris@0:
Chris@0: def self.wrap! str, template, target
Chris@0: target = Regexp.new(Regexp.escape("<%#{target}%>"))
Chris@0: if template =~ target
Chris@0: str[0,0] = $`
Chris@0: str << $'
Chris@0: else
Chris@0: raise "Template target <%%%p%%> not found" % target
Chris@0: end
Chris@0: end
Chris@0:
Chris@0: def apply target, replacement
Chris@0: target = Regexp.new(Regexp.escape("<%#{target}%>"))
Chris@0: if self =~ target
Chris@0: Template.new($` + replacement + $')
Chris@0: else
Chris@0: raise "Template target <%%%p%%> not found" % target
Chris@0: end
Chris@0: end
Chris@0:
Chris@0: module Simple
Chris@0: def ` str #` <-- for stupid editors
Chris@0: Template.new str
Chris@0: end
Chris@0: end
Chris@0: end
Chris@0:
Chris@0: extend Template::Simple
Chris@0:
Chris@0: #-- don't include the templates in docu
Chris@0:
Chris@0: SPAN = `<%CONTENT%>`
Chris@0:
Chris@0: DIV = <<-`DIV`
Chris@0:
Chris@0: DIV
Chris@0:
Chris@0: TABLE = <<-`TABLE`
Chris@0:
Chris@0: <%LINE_NUMBERS%> |
Chris@0: <%CONTENT%> |
Chris@0:
Chris@0: TABLE
Chris@0: # title="double click to expand"
Chris@0:
Chris@0: LIST = <<-`LIST`
Chris@0:
Chris@0: <%CONTENT%>
Chris@0:
Chris@0: LIST
Chris@0:
Chris@0: PAGE = <<-`PAGE`
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: <%CONTENT%>
Chris@0:
Chris@0:
Chris@0: PAGE
Chris@0:
Chris@0: end
Chris@0:
Chris@0: end
Chris@0:
Chris@0: end
Chris@0: end