diff --git a/coderay.gemspec b/coderay.gemspec index 50c195b5..f95afc5f 100644 --- a/coderay.gemspec +++ b/coderay.gemspec @@ -31,4 +31,6 @@ Gem::Specification.new do |s| s.rubyforge_project = s.name s.rdoc_options = '-SNw2', "-m#{readme_file}", '-t CodeRay Documentation' s.extra_rdoc_files = readme_file + + s.add_dependency 'escape_utils', '>= 1.0' end diff --git a/lib/coderay/encoders/html.rb b/lib/coderay/encoders/html.rb index 1b33e921..5d55b00f 100644 --- a/lib/coderay/encoders/html.rb +++ b/lib/coderay/encoders/html.rb @@ -1,4 +1,5 @@ require 'set' +require 'escape_utils' module CodeRay module Encoders @@ -127,22 +128,6 @@ class HTML < Encoder protected - def self.make_html_escape_hash - { - '&' => '&', - '"' => '"', - '>' => '>', - '<' => '<', - # "\t" => will be set to ' ' * options[:tab_width] during setup - }.tap do |hash| - # Escape ASCII control codes except \x9 == \t and \xA == \n. - (Array(0x00..0x8) + Array(0xB..0x1F)).each { |invalid| hash[invalid.chr] = ' ' } - end - end - - HTML_ESCAPE = make_html_escape_hash - HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1F]/ - TOKEN_KIND_TO_INFO = Hash.new do |h, kind| h[kind] = kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } end @@ -181,8 +166,6 @@ def setup options @break_lines = (options[:break_lines] == true) - @HTML_ESCAPE = HTML_ESCAPE.merge("\t" => options[:tab_width] ? ' ' * options[:tab_width] : "\t") - @opened = [] @last_opened = nil @css = CSS.new options[:style] @@ -198,7 +181,7 @@ def finish options @last_opened = nil end - if @out.respond_to? :to_str + if options[:wrap] || options[:line_numbers] @out.extend Output @out.css = @css if options[:line_numbers] @@ -221,7 +204,7 @@ def finish options def text_token text, kind style = @span_for_kinds[@last_opened ? [kind, *@opened] : kind] - text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } if text =~ /#{HTML_ESCAPE_PATTERN}/o + text = EscapeUtils.escape_html text, false text = break_lines(text, style) if @break_lines && (style || @opened.size > 0) && text.index("\n") if style diff --git a/lib/coderay/encoders/html/css.rb b/lib/coderay/encoders/html/css.rb index 164d7f85..e06c4869 100644 --- a/lib/coderay/encoders/html/css.rb +++ b/lib/coderay/encoders/html/css.rb @@ -3,25 +3,23 @@ module Encoders class HTML class CSS # :nodoc: + def initialize style_name = :default + @style_name = style_name + end - attr :stylesheet - - def CSS.load_stylesheet style = nil - CodeRay::Styles[style] + def style + @style ||= CodeRay::Styles[@style_name] end - def initialize style = :default - @styles = Hash.new - style = CSS.load_stylesheet style - @stylesheet = [ + def stylesheet + @css ||= [ style::CSS_MAIN_STYLES, style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') ].join("\n") - parse style::TOKEN_COLORS end def get_style_for_css_classes css_classes - cl = @styles[css_classes.first] + cl = styles[css_classes.first] return '' unless cl style = '' 1.upto css_classes.size do |offset| @@ -31,7 +29,7 @@ def get_style_for_css_classes css_classes return style end - private + private CSS_CLASS_PATTERN = / ( # $1 = selectors @@ -46,14 +44,16 @@ def get_style_for_css_classes css_classes | ( [^\n]+ ) # $3 = error /mx - def parse stylesheet - stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| - raise "CSS parse error: '#{error.inspect}' not recognized" if error - for selector in selectors.split(',') - classes = selector.scan(/[-\w]+/) - cl = classes.pop - @styles[cl] ||= Hash.new - @styles[cl][classes] = style.to_s.strip.delete(' ').chomp(';') + def styles + @styles ||= Hash.new.tap do |styles| + style::TOKEN_COLORS.scan CSS_CLASS_PATTERN do |selectors, style, error| + raise "CSS parse error: '#{error.inspect}' not recognized" if error + for selector in selectors.split(',') + classes = selector.scan(/[-\w]+/) + cl = classes.pop + styles[cl] ||= Hash.new + styles[cl][classes] = style.to_s.strip.delete(' ').chomp(';') + end end end end diff --git a/lib/coderay/helpers/plugin_host.rb b/lib/coderay/helpers/plugin_host.rb index e9bc17c1..12ee29de 100644 --- a/lib/coderay/helpers/plugin_host.rb +++ b/lib/coderay/helpers/plugin_host.rb @@ -47,11 +47,21 @@ def load_all # Example: # yaml_plugin = MyPluginHost[:yaml] def [] id, *args, &blk - plugin = validate_id(id) - begin - plugin = plugin_hash.[](plugin, *args, &blk) - end while plugin.is_a? String - plugin + if !args.empty? || blk + plugin = validate_id(id) + begin + plugin = plugin_hash.[](plugin, *args, &blk) + end while plugin.is_a? String + plugin + else + (@cache ||= Hash.new do |cache, key| + plugin = validate_id(key) + begin + plugin = plugin_hash.[](plugin) + end while plugin.is_a? String + cache[key] = plugin + end)[id] + end end alias load [] diff --git a/test/functional/basic.rb b/test/functional/basic.rb index 752d4ba0..8554a78f 100644 --- a/test/functional/basic.rb +++ b/test/functional/basic.rb @@ -7,6 +7,10 @@ class BasicTest < Test::Unit::TestCase + def normalize_html html + html.gsub(''', "'").gsub('"', '"') + end + def test_version assert_nothing_raised do assert_match(/\A\d\.\d\.\d?\z/, CodeRay::VERSION) @@ -46,11 +50,11 @@ def test_simple_scan end end - RUBY_TEST_HTML = 'puts "' + - 'Hello, World!"' + RUBY_TEST_HTML = 'puts "' + + 'Hello, World!"' def test_simple_highlight assert_nothing_raised do - assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html + assert_equal RUBY_TEST_HTML, normalize_html(CodeRay.scan(RUBY_TEST_CODE, :ruby).html) end end @@ -75,7 +79,8 @@ def test_highlight end def test_highlight_file - assert_match "require 'test/unit'\n", CodeRay.highlight_file(__FILE__) + assert_match "require 'test/unit'\n", + normalize_html(CodeRay.highlight_file(__FILE__)) end def test_duo diff --git a/test/functional/examples.rb b/test/functional/examples.rb index 985ef871..49337cb8 100644 --- a/test/functional/examples.rb +++ b/test/functional/examples.rb @@ -5,12 +5,16 @@ class ExamplesTest < Test::Unit::TestCase + def normalize_html html + html.gsub(''', "'").gsub('"', '"') + end + def test_examples # output as HTML div (using inline CSS styles) div = CodeRay.scan('puts "Hello, world!"', :ruby).div - assert_equal <<-DIV, div + assert_equal <<-DIV, normalize_html(div)
-
puts "Hello, world!"
+
puts "Hello, world!"
DIV @@ -20,7 +24,7 @@ def test_examples puts 'Hello, world!' end CODE - assert_equal <<-DIV, div + assert_equal <<-DIV, normalize_html(div)
1
 2
@@ -34,13 +38,13 @@ def test_examples
     
     # output as standalone HTML page (using CSS classes)
     page = CodeRay.scan('puts "Hello, world!"', :ruby).page
-    assert_match <<-PAGE, page
+    assert_match <<-PAGE, normalize_html(page)
 
 
 
-  
+  
1
 
puts "Hello, world!"
puts "Hello, world!"
@@ -90,9 +94,9 @@ def test_examples # produce a HTML div, but with CSS classes div = tokens.div(:css => :class) - assert_equal <<-DIV, div + assert_equal <<-DIV, normalize_html(div)
-
{ "just": "an", "example": 42 }
+
{ "just": "an", "example": 42 }
DIV @@ -119,9 +123,9 @@ def test_examples # re-using scanner and encoder ruby_highlighter = CodeRay::Duo[:ruby, :div] div = ruby_highlighter.encode('puts "Hello, world!"') - assert_equal <<-DIV, div + assert_equal <<-DIV, normalize_html(div)
-
puts "Hello, world!"
+
puts "Hello, world!"
DIV end diff --git a/test/functional/for_redcloth.rb b/test/functional/for_redcloth.rb index 9fd244ed..50fc50ca 100644 --- a/test/functional/for_redcloth.rb +++ b/test/functional/for_redcloth.rb @@ -14,16 +14,20 @@ class BasicTest < Test::Unit::TestCase + def normalize_html html + html.gsub(''', "'").gsub('"', '"') + end + def test_for_redcloth require 'coderay/for_redcloth' - assert_equal "

puts "Hello, World!"

", - RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + assert_equal "

puts \"Hello, World!\"

", + normalize_html(RedCloth.new('@[ruby]puts "Hello, World!"@').to_html) assert_equal <<-BLOCKCODE.chomp,
-
puts "Hello, World!"
+
puts "Hello, World!"
BLOCKCODE - RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html + normalize_html(RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html) end def test_for_redcloth_no_lang diff --git a/test/unit/html.rb b/test/unit/html.rb index 00726351..9175a4fc 100644 --- a/test/unit/html.rb +++ b/test/unit/html.rb @@ -3,6 +3,10 @@ class HtmlTest < Test::Unit::TestCase + def normalize_html html + html.gsub(''', "'").gsub('"', '"') + end + def test_break_lines_option snippets = {} @@ -60,7 +64,7 @@ def test_break_lines_option * used to test the */ public class Test { - public static final String MESSAGE = "My message To the world"; + public static final String MESSAGE = \"My message To the world\"; static void main() { /* @@ -80,7 +84,7 @@ def test_break_lines_option * used to test the */ public class Test { - public static final String MESSAGE = "My message To the world"; + public static final String MESSAGE = \"My message To the world\"; static void main() { /* @@ -95,9 +99,9 @@ def test_break_lines_option for lang, code in snippets tokens = CodeRay.scan code[:in], lang - assert_equal code[:expected_with_option_off], tokens.html - assert_equal code[:expected_with_option_off], tokens.html(:break_lines => false) - assert_equal code[:expected_with_option_on], tokens.html(:break_lines => true) + assert_equal code[:expected_with_option_off], normalize_html(tokens.html) + assert_equal code[:expected_with_option_off], normalize_html(tokens.html(:break_lines => false)) + assert_equal code[:expected_with_option_on], normalize_html(tokens.html(:break_lines => true)) end end end