From 84b8431608174e74a4c0d2394eb330a6621bc74b Mon Sep 17 00:00:00 2001 From: no author Date: Mon, 26 Sep 2005 02:58:54 +0000 Subject: New Repository, initial import --- lib/coderay/encoders/helpers/html_output.rb | 240 ++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 lib/coderay/encoders/helpers/html_output.rb (limited to 'lib/coderay/encoders/helpers/html_output.rb') diff --git a/lib/coderay/encoders/helpers/html_output.rb b/lib/coderay/encoders/helpers/html_output.rb new file mode 100644 index 0000000..e2b26e7 --- /dev/null +++ b/lib/coderay/encoders/helpers/html_output.rb @@ -0,0 +1,240 @@ +module CodeRay + module Encoders + + class HTML + + # This module is included in the output String from thew HTML Encoder. + # + # It provides methods like wrap, div, page etc. + # + # Remember to use #clone instead of #dup to keep the modules the object was + # extended with. + # + # TODO: more doc. + module Output + + class << self + + # This makes Output look like a class. + # + # Example: + # + # a = Output.new 'Code' + # a.wrap! :page + def new string, element = nil + output = string.clone.extend self + output.wrapped_in = element + output + end + + # Raises an exception if an object that doesn't respond to to_str is extended by Output, + # to prevent users from misuse. Use Module#remove_method to disable. + def extended o + warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str + end + + def page_template_for_css css = :default + css = CSS::DEFAULT_STYLESHEET if css == :default + PAGE.apply 'CSS', css + end + + # Define a new wrapper. This is meta programming. + def wrapper *wrappers + wrappers.each do |wrapper| + define_method wrapper do |*args| + wrap wrapper, *args + end + define_method(:"#{wrapper}!") do |*args| + wrap! wrapper, *args + end + end + end + end + + wrapper :div, :span, :page + + def wrapped_in + @wrapped_in || nil + end + attr_writer :wrapped_in + + def wrapped_in? element + wrapped_in == element + end + + def wrap_in template + clone.wrap_in! template + end + + def wrap_in! template + Template.wrap! self, template, 'CONTENT' + self + end + + def wrap! element, *args + return self if not element or element == wrapped_in + case element + when :div + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! DIV + when :span + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! SPAN + when :page + wrap! :div if wrapped_in? nil + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div + wrap_in! Output.page_template_for_css + when nil + return self + else + raise "Unknown value %p for :wrap" % element + end + @wrapped_in = element + self + end + + def wrap *args + clone.wrap!(*args) + end + + def numerize! mode = :table, options = {} + return self unless mode + + offset = options.fetch :line_numbers_offset, DEFAULT_OPTIONS[:line_numbers_offset] + unless offset.is_a? Integer + raise ArgumentError, "Invalid value %p for :offset; Integer expected." % offset + end + + unless NUMERIZABLE_WRAPPINGS.include? options[:wrap] + raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]] + end + + bold_every = options.fetch :bold_every, DEFAULT_OPTIONS[:bold_every] + bolding = + if bold_every == :no_bolding or bold_every == 0 + proc { |line| line.to_s } + elsif bold_every.is_a? Integer + proc do |line| + if line % bold_every == 0 + "#{line}" # every bold_every-th number in bold + else + line.to_s + end + end + else + raise ArgumentError, "Invalid value %p for :bolding; :no_bolding or Integer expected." % bolding + end + + line_count = count("\n") + line_count += 1 if self[-1] != ?\n + + case mode + when :inline + max_width = line_count.to_s.size + line = offset - 1 + gsub!(/^/) do + line += 1 + line_number = bolding.call line + "#{ line_number.rjust(max_width) } " + end + wrap! :div + + when :table + # This is really ugly. + # Because even monospace fonts seem to have different heights when bold, + # I make the newline bold, both in the code and the line numbers. + # FIXME Still not working perfect for Mr. Internet Exploder + line_numbers = (offset ... offset + line_count).to_a.map(&bolding).join("\n") + line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ + line_numbers.gsub!(/\n/) { "\n" } + + line_numbers_tpl = DIV_TABLE.apply('LINE_NUMBERS', line_numbers) + gsub!(/\n/) { "\n" } + wrap_in! line_numbers_tpl + @wrapped_in = :div + + else + raise ArgumentError, "Unknown value %p for mode: :inline or :table expected" % mode + end + + self + end + + def numerize *args + clone.numerize!(*args) + end + + class Template < String + + def self.wrap! str, template, target + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if template =~ target + str[0,0] = $` + str << $' + else + raise "Template target <%%%p%%> not found" % target + end + end + + def apply target, replacement + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if self =~ target + Template.new($` + replacement + $') + else + raise "Template target <%%%p%%> not found" % target + end + end + + module Simple + def ` str #` + Template.new str + end + end + end + + extend Template::Simple + +#-- don't include the templates in docu + + SPAN = `<%CONTENT%>` + + DIV, DIV_TABLE, PAGE = + <<-`DIV`, <<-`DIV_TABLE`, <<-`PAGE` + +
+
<%CONTENT%>
+
+ DIV + +
+ + + + + +
<%LINE_NUMBERS%>
<%CONTENT%>
+
+ DIV_TABLE + + + + + + CodeRay HTML Encoder Example + + + +<%CONTENT%> + + + PAGE + + end + + end + +end +end -- cgit v1.2.1