From 0b60a93641a5bfafb2b07f81a8e9c7da03ef3c86 Mon Sep 17 00:00:00 2001 From: murphy Date: Sat, 5 Nov 2005 02:28:36 +0000 Subject: New helper module scheme, step 3 --- lib/coderay/encoders/html.rb | 6 +- lib/coderay/encoders/html/classes.rb | 69 +++++++++ lib/coderay/encoders/html/css.rb | 155 ++++++++++++++++++++ lib/coderay/encoders/html/html_css.rb | 155 -------------------- lib/coderay/encoders/html/html_helper.rb | 69 --------- lib/coderay/encoders/html/html_numerization.rb | 112 --------------- lib/coderay/encoders/html/html_output.rb | 188 ------------------------- lib/coderay/encoders/html/numerization.rb | 112 +++++++++++++++ lib/coderay/encoders/html/output.rb | 188 +++++++++++++++++++++++++ 9 files changed, 527 insertions(+), 527 deletions(-) create mode 100644 lib/coderay/encoders/html/classes.rb create mode 100644 lib/coderay/encoders/html/css.rb delete mode 100644 lib/coderay/encoders/html/html_css.rb delete mode 100644 lib/coderay/encoders/html/html_helper.rb delete mode 100644 lib/coderay/encoders/html/html_numerization.rb delete mode 100644 lib/coderay/encoders/html/html_output.rb create mode 100644 lib/coderay/encoders/html/numerization.rb create mode 100644 lib/coderay/encoders/html/output.rb (limited to 'lib/coderay/encoders') diff --git a/lib/coderay/encoders/html.rb b/lib/coderay/encoders/html.rb index 22738d8..986bf00 100644 --- a/lib/coderay/encoders/html.rb +++ b/lib/coderay/encoders/html.rb @@ -80,9 +80,9 @@ module Encoders :hint => false, } - require 'coderay/encoders/helpers/html_helper' - require 'coderay/encoders/helpers/html_output' - require 'coderay/encoders/helpers/html_css' + require 'coderay/encoders/html/classes' + require 'coderay/encoders/html/output' + require 'coderay/encoders/html/css' def initialize(*) super diff --git a/lib/coderay/encoders/html/classes.rb b/lib/coderay/encoders/html/classes.rb new file mode 100644 index 0000000..6a2938e --- /dev/null +++ b/lib/coderay/encoders/html/classes.rb @@ -0,0 +1,69 @@ +module CodeRay module Encoders + + class HTML + + ClassOfKind = { + :attribute_name => 'an', + :attribute_name_fat => 'af', + :attribute_value => 'av', + :attribute_value_fat => 'aw', + :bin => 'bi', + :char => 'ch', + :class => 'cl', + :class_variable => 'cv', + :color => 'cr', + :comment => 'c', + :constant => 'co', + :content => 'k', + :definition => 'df', + :delimiter => 'dl', + :directive => 'di', + :doc => 'do', + :doc_string => 'ds', + :error => 'er', + :escape => 'e', + :exception => 'ex', + :float => 'fl', + :function => 'fu', + :global_variable => 'gv', + :hex => 'hx', + :include => 'ic', + :inline => 'il', + :instance_variable => 'iv', + :integer => 'i', + :interpreted => 'in', + :label => 'la', + :local_variable => 'lv', + :modifier => 'mod', + :oct => 'oc', + :operator_name => 'on', + :pre_constant => 'pc', + :pre_type => 'pt', + :predefined => 'pd', + :preprocessor => 'pp', + :regexp => 'rx', + :reserved => 'r', + :shell => 'sh', + :string => 's', + :symbol => 'sy', + :tag => 'ta', + :tag_fat => 'tf', + :tag_special => 'ts', + :type => 'ty', + :variable => 'v', + :xml_text => 'xt', + + :ident => :NO_HIGHLIGHT, # 'id' + :operator => :NO_HIGHLIGHT, # 'op' + :space => :NO_HIGHLIGHT, # 'sp' + :plain => :NO_HIGHLIGHT, + } + ClassOfKind[:procedure] = ClassOfKind[:method] = ClassOfKind[:function] + ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter] + ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter] + ClassOfKind[:escape] = ClassOfKind[:delimiter] + ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!' + + end + +end end diff --git a/lib/coderay/encoders/html/css.rb b/lib/coderay/encoders/html/css.rb new file mode 100644 index 0000000..80ccab4 --- /dev/null +++ b/lib/coderay/encoders/html/css.rb @@ -0,0 +1,155 @@ +module CodeRay module Encoders + + class HTML + class CSS + + def initialize stylesheet = TOKENS + @classes = Hash.new + parse stylesheet + end + + def [] *styles + cl = @classes[styles.first] + return '' unless cl + style = false + 1.upto(styles.size) do |offset| + break if style = cl[styles[offset .. -1]] + end + return style + end + + private + + CSS_CLASS_PATTERN = / + ( (?: # $1 = classes + \s* \. [-\w]+ + )+ ) + \s* \{ + ( [^\}]* ) # $2 = style + \} \s* + | + ( . ) # $3 = error + /mx + def parse stylesheet + stylesheet.scan CSS_CLASS_PATTERN do |classes, style, error| + raise "CSS parse error: '#{error.inspect}' not recognized" if error + styles = classes.scan(/[-\w]+/) + cl = styles.pop + @classes[cl] ||= Hash.new + @classes[cl][styles] = style.strip + end + end + + MAIN = <<-'MAIN' +.CodeRay { + background-color: #f8f8f8; + border: 1px solid silver; + font-family: 'Courier New', 'Terminal', monospace; + color: black; +} +.CodeRay pre { margin: 0px; } + +div.CodeRay { } + +span.CodeRay { white-space: pre; border: 0px; padding: 2px; } + +table.CodeRay { border-collapse: collapse; width: 100%; padding: 2px; } +table.CodeRay td { padding: 2px 4px; vertical-align: top; } + +.CodeRay .line_numbers, .CodeRay .no { + background-color: #def; + color: gray; + text-align: right; +} +.CodeRay .line_numbers tt { font-weight: bold; } +.CodeRay .no { padding: 0px 4px; } +.CodeRay .code { width: 100%; } + +ol.CodeRay { font-size: 10pt; } +ol.CodeRay li { white-space: pre; } + +.CodeRay .code pre { overflow: auto; } + MAIN + + TOKENS = <<-'TOKENS' +.af { color:#00C; } +.an { color:#007; } +.av { color:#700; } +.aw { color:#C00; } +.bi { color:#509; font-weight:bold; } +.c { color:#888; } + +.ch { color:#04D; } +.ch .k { color:#04D; } +.ch .dl { color:#039; } + +.cl { color:#B06; font-weight:bold; } +.co { color:#036; font-weight:bold; } +.cr { color:#0A0; } +.cv { color:#369; } +.df { color:#099; font-weight:bold; } +.di { color:#088; font-weight:bold; } +.dl { color:black; } +.do { color:#970; } +.ds { color:#D42; font-weight:bold; } +.e { color:#666; font-weight:bold; } +.er { color:#F00; background-color:#FAA; } +.ex { color:#F00; font-weight:bold; } +.fl { color:#60E; font-weight:bold; } +.fu { color:#06B; font-weight:bold; } +.gv { color:#d70; font-weight:bold; } +.hx { color:#058; font-weight:bold; } +.i { color:#00D; font-weight:bold; } +.ic { color:#B44; font-weight:bold; } +.il { } +.in { color:#B2B; font-weight:bold; } +.iv { color:#33B; } +.la { color:#970; font-weight:bold; } +.lv { color:#963; } +.oc { color:#40E; font-weight:bold; } +.on { color:#000; font-weight:bold; } +.pc { color:#038; font-weight:bold; } +.pd { color:#369; font-weight:bold; } +.pp { color:#579; } +.pt { color:#339; font-weight:bold; } +.r { color:#080; font-weight:bold; } + +.rx { background-color:#fff0ff; } +.rx .k { color:#808; } +.rx .dl { color:#404; } +.rx .mod { color:#C2C; } +.rx .fu { color:#404; font-weight: bold; } + +.s { background-color:#fff0f0; } +.s .s { background-color:#ffe0e0; } +.s .s .s { background-color:#ffd0d0; } +.s .k { color:#D20; } +.s .dl { color:#710; } + +.sh { background-color:#f0fff0; } +.sh .k { color:#2B2; } +.sh .dl { color:#161; } + +.sy { color:#A60; } +.sy .k { color:#A60; } +.sy .dl { color:#630; } + +.ta { color:#070; } +.tf { color:#070; font-weight:bold; } +.ts { color:#D70; font-weight:bold; } +.ty { color:#339; font-weight:bold; } +.v { color:#036; } +.xt { color:#444; } + TOKENS + + DEFAULT_STYLESHEET = MAIN + TOKENS.gsub(/^(?!$)/, '.CodeRay ') + + end + end + +end end + +if $0 == __FILE__ + require 'pp' + pp CodeRay::Encoders::HTML::CSS.new +end diff --git a/lib/coderay/encoders/html/html_css.rb b/lib/coderay/encoders/html/html_css.rb deleted file mode 100644 index 80ccab4..0000000 --- a/lib/coderay/encoders/html/html_css.rb +++ /dev/null @@ -1,155 +0,0 @@ -module CodeRay module Encoders - - class HTML - class CSS - - def initialize stylesheet = TOKENS - @classes = Hash.new - parse stylesheet - end - - def [] *styles - cl = @classes[styles.first] - return '' unless cl - style = false - 1.upto(styles.size) do |offset| - break if style = cl[styles[offset .. -1]] - end - return style - end - - private - - CSS_CLASS_PATTERN = / - ( (?: # $1 = classes - \s* \. [-\w]+ - )+ ) - \s* \{ - ( [^\}]* ) # $2 = style - \} \s* - | - ( . ) # $3 = error - /mx - def parse stylesheet - stylesheet.scan CSS_CLASS_PATTERN do |classes, style, error| - raise "CSS parse error: '#{error.inspect}' not recognized" if error - styles = classes.scan(/[-\w]+/) - cl = styles.pop - @classes[cl] ||= Hash.new - @classes[cl][styles] = style.strip - end - end - - MAIN = <<-'MAIN' -.CodeRay { - background-color: #f8f8f8; - border: 1px solid silver; - font-family: 'Courier New', 'Terminal', monospace; - color: black; -} -.CodeRay pre { margin: 0px; } - -div.CodeRay { } - -span.CodeRay { white-space: pre; border: 0px; padding: 2px; } - -table.CodeRay { border-collapse: collapse; width: 100%; padding: 2px; } -table.CodeRay td { padding: 2px 4px; vertical-align: top; } - -.CodeRay .line_numbers, .CodeRay .no { - background-color: #def; - color: gray; - text-align: right; -} -.CodeRay .line_numbers tt { font-weight: bold; } -.CodeRay .no { padding: 0px 4px; } -.CodeRay .code { width: 100%; } - -ol.CodeRay { font-size: 10pt; } -ol.CodeRay li { white-space: pre; } - -.CodeRay .code pre { overflow: auto; } - MAIN - - TOKENS = <<-'TOKENS' -.af { color:#00C; } -.an { color:#007; } -.av { color:#700; } -.aw { color:#C00; } -.bi { color:#509; font-weight:bold; } -.c { color:#888; } - -.ch { color:#04D; } -.ch .k { color:#04D; } -.ch .dl { color:#039; } - -.cl { color:#B06; font-weight:bold; } -.co { color:#036; font-weight:bold; } -.cr { color:#0A0; } -.cv { color:#369; } -.df { color:#099; font-weight:bold; } -.di { color:#088; font-weight:bold; } -.dl { color:black; } -.do { color:#970; } -.ds { color:#D42; font-weight:bold; } -.e { color:#666; font-weight:bold; } -.er { color:#F00; background-color:#FAA; } -.ex { color:#F00; font-weight:bold; } -.fl { color:#60E; font-weight:bold; } -.fu { color:#06B; font-weight:bold; } -.gv { color:#d70; font-weight:bold; } -.hx { color:#058; font-weight:bold; } -.i { color:#00D; font-weight:bold; } -.ic { color:#B44; font-weight:bold; } -.il { } -.in { color:#B2B; font-weight:bold; } -.iv { color:#33B; } -.la { color:#970; font-weight:bold; } -.lv { color:#963; } -.oc { color:#40E; font-weight:bold; } -.on { color:#000; font-weight:bold; } -.pc { color:#038; font-weight:bold; } -.pd { color:#369; font-weight:bold; } -.pp { color:#579; } -.pt { color:#339; font-weight:bold; } -.r { color:#080; font-weight:bold; } - -.rx { background-color:#fff0ff; } -.rx .k { color:#808; } -.rx .dl { color:#404; } -.rx .mod { color:#C2C; } -.rx .fu { color:#404; font-weight: bold; } - -.s { background-color:#fff0f0; } -.s .s { background-color:#ffe0e0; } -.s .s .s { background-color:#ffd0d0; } -.s .k { color:#D20; } -.s .dl { color:#710; } - -.sh { background-color:#f0fff0; } -.sh .k { color:#2B2; } -.sh .dl { color:#161; } - -.sy { color:#A60; } -.sy .k { color:#A60; } -.sy .dl { color:#630; } - -.ta { color:#070; } -.tf { color:#070; font-weight:bold; } -.ts { color:#D70; font-weight:bold; } -.ty { color:#339; font-weight:bold; } -.v { color:#036; } -.xt { color:#444; } - TOKENS - - DEFAULT_STYLESHEET = MAIN + TOKENS.gsub(/^(?!$)/, '.CodeRay ') - - end - end - -end end - -if $0 == __FILE__ - require 'pp' - pp CodeRay::Encoders::HTML::CSS.new -end diff --git a/lib/coderay/encoders/html/html_helper.rb b/lib/coderay/encoders/html/html_helper.rb deleted file mode 100644 index 6a2938e..0000000 --- a/lib/coderay/encoders/html/html_helper.rb +++ /dev/null @@ -1,69 +0,0 @@ -module CodeRay module Encoders - - class HTML - - ClassOfKind = { - :attribute_name => 'an', - :attribute_name_fat => 'af', - :attribute_value => 'av', - :attribute_value_fat => 'aw', - :bin => 'bi', - :char => 'ch', - :class => 'cl', - :class_variable => 'cv', - :color => 'cr', - :comment => 'c', - :constant => 'co', - :content => 'k', - :definition => 'df', - :delimiter => 'dl', - :directive => 'di', - :doc => 'do', - :doc_string => 'ds', - :error => 'er', - :escape => 'e', - :exception => 'ex', - :float => 'fl', - :function => 'fu', - :global_variable => 'gv', - :hex => 'hx', - :include => 'ic', - :inline => 'il', - :instance_variable => 'iv', - :integer => 'i', - :interpreted => 'in', - :label => 'la', - :local_variable => 'lv', - :modifier => 'mod', - :oct => 'oc', - :operator_name => 'on', - :pre_constant => 'pc', - :pre_type => 'pt', - :predefined => 'pd', - :preprocessor => 'pp', - :regexp => 'rx', - :reserved => 'r', - :shell => 'sh', - :string => 's', - :symbol => 'sy', - :tag => 'ta', - :tag_fat => 'tf', - :tag_special => 'ts', - :type => 'ty', - :variable => 'v', - :xml_text => 'xt', - - :ident => :NO_HIGHLIGHT, # 'id' - :operator => :NO_HIGHLIGHT, # 'op' - :space => :NO_HIGHLIGHT, # 'sp' - :plain => :NO_HIGHLIGHT, - } - ClassOfKind[:procedure] = ClassOfKind[:method] = ClassOfKind[:function] - ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter] - ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter] - ClassOfKind[:escape] = ClassOfKind[:delimiter] - ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!' - - end - -end end diff --git a/lib/coderay/encoders/html/html_numerization.rb b/lib/coderay/encoders/html/html_numerization.rb deleted file mode 100644 index f51b5d3..0000000 --- a/lib/coderay/encoders/html/html_numerization.rb +++ /dev/null @@ -1,112 +0,0 @@ -module CodeRay - module Encoders - - class HTML - - module Output - - def numerize *args - clone.numerize!(*args) - end - - NUMERIZABLE_WRAPPINGS = { - :table => [:div, :page], - :inline => :all, - :list => [:div, :page], - nil => :all - } - - def numerize! mode = :table, options = {} - return self unless mode - - options = DEFAULT_OPTIONS.merge options - - start = options[:line_number_start] - unless start.is_a? Integer - raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start - end - - allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode] - unless allowed_wrappings == :all or allowed_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[: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 = (start + line_count).to_s.size - line = start - gsub!(/^/) do - line_number = bolding.call line - line += 1 - "#{ 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 - # FIXME Firefox struggles with very long codes (> 200 lines) - line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n") - line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ - line_numbers.gsub!(/\n/) { "\n" } - - line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers) - gsub!(/\n/) { "\n" } - wrap_in! line_numbers_table_tpl - @wrapped_in = :div - - when :list - opened_tags = [] - gsub!(/^.*$\n?/) do |line| - line.chomp! - - open = opened_tags.join - line.scan(%r!<(/)?span[^>]*>?!) do |close,| - if close - opened_tags.pop - else - opened_tags << $& - end - end - close = '' * opened_tags.size - - "
  • #{open}#{line}#{close}
  • " - end - wrap_in! LIST - @wrapped_in = :div - - else - raise ArgumentError, "Unknown value %p for mode: expected one of %p" % - [mode, NUMERIZABLE_WRAPPINGS.keys - [:all]] - end - - self - end - - end - - end - -end -end diff --git a/lib/coderay/encoders/html/html_output.rb b/lib/coderay/encoders/html/html_output.rb deleted file mode 100644 index f17965d..0000000 --- a/lib/coderay/encoders/html/html_output.rb +++ /dev/null @@ -1,188 +0,0 @@ -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 - - require 'coderay/encoders/helpers/html_numerization.rb' - - attr_accessor :wrapped_in - - 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 stylesheet in_tag = false - ss = CSS::DEFAULT_STYLESHEET - ss = <<-CSS if in_tag - - CSS - ss - end - - def page_template_for_css css = :default - css = 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}!".to_sym do |*args| - wrap! wrapper, *args - end - end - end - end - - wrapper :div, :span, :page - - 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 stylesheet in_tag = false - Output.stylesheet in_tag - 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` -
    -
    <%CONTENT%>
    -
    - DIV - - TABLE = <<-`TABLE` - - - -
    <%LINE_NUMBERS%>
    <%CONTENT%>
    - TABLE - # title="double click to expand" - - LIST = <<-`LIST` -
      <%CONTENT%>
    - LIST - - PAGE = <<-`PAGE` - - - - - CodeRay HTML Encoder Example - - - - -<%CONTENT%> - - - PAGE - - end - - end - -end -end diff --git a/lib/coderay/encoders/html/numerization.rb b/lib/coderay/encoders/html/numerization.rb new file mode 100644 index 0000000..f51b5d3 --- /dev/null +++ b/lib/coderay/encoders/html/numerization.rb @@ -0,0 +1,112 @@ +module CodeRay + module Encoders + + class HTML + + module Output + + def numerize *args + clone.numerize!(*args) + end + + NUMERIZABLE_WRAPPINGS = { + :table => [:div, :page], + :inline => :all, + :list => [:div, :page], + nil => :all + } + + def numerize! mode = :table, options = {} + return self unless mode + + options = DEFAULT_OPTIONS.merge options + + start = options[:line_number_start] + unless start.is_a? Integer + raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start + end + + allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode] + unless allowed_wrappings == :all or allowed_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[: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 = (start + line_count).to_s.size + line = start + gsub!(/^/) do + line_number = bolding.call line + line += 1 + "#{ 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 + # FIXME Firefox struggles with very long codes (> 200 lines) + line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n") + line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ + line_numbers.gsub!(/\n/) { "\n" } + + line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers) + gsub!(/\n/) { "\n" } + wrap_in! line_numbers_table_tpl + @wrapped_in = :div + + when :list + opened_tags = [] + gsub!(/^.*$\n?/) do |line| + line.chomp! + + open = opened_tags.join + line.scan(%r!<(/)?span[^>]*>?!) do |close,| + if close + opened_tags.pop + else + opened_tags << $& + end + end + close = '' * opened_tags.size + + "
  • #{open}#{line}#{close}
  • " + end + wrap_in! LIST + @wrapped_in = :div + + else + raise ArgumentError, "Unknown value %p for mode: expected one of %p" % + [mode, NUMERIZABLE_WRAPPINGS.keys - [:all]] + end + + self + end + + end + + end + +end +end diff --git a/lib/coderay/encoders/html/output.rb b/lib/coderay/encoders/html/output.rb new file mode 100644 index 0000000..c8985da --- /dev/null +++ b/lib/coderay/encoders/html/output.rb @@ -0,0 +1,188 @@ +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 + + require 'coderay/encoders/html/numerization.rb' + + attr_accessor :wrapped_in + + 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 stylesheet in_tag = false + ss = CSS::DEFAULT_STYLESHEET + ss = <<-CSS if in_tag + + CSS + ss + end + + def page_template_for_css css = :default + css = 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}!".to_sym do |*args| + wrap! wrapper, *args + end + end + end + end + + wrapper :div, :span, :page + + 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 stylesheet in_tag = false + Output.stylesheet in_tag + 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` +
    +
    <%CONTENT%>
    +
    + DIV + + TABLE = <<-`TABLE` + + + +
    <%LINE_NUMBERS%>
    <%CONTENT%>
    + TABLE + # title="double click to expand" + + LIST = <<-`LIST` +
      <%CONTENT%>
    + LIST + + PAGE = <<-`PAGE` + + + + + CodeRay HTML Encoder Example + + + + +<%CONTENT%> + + + PAGE + + end + + end + +end +end -- cgit v1.2.1