Práctica: Servicio de Syntax Highlighting

Construya una aplicación que provee syntax higlighting para un código que se vuelca en un formulario. Use la gema syntaxi.

El siguiente ejemplo muestra como funciona la gema syntaxi:

[~/rubytesting/syntax_highlighting]$ cat ex_syntaxi.rb 
require 'syntaxi'
text = <<"EOF"
[code lang="ruby"]
  def foo
    puts 'bar'
  end
[/code]
EOF
formatted_text = Syntaxi.new(text).process
puts formatted_text
Ejecución:
[~/rubytesting/syntax_highlighting]$ ruby ex_syntaxi.rb 
<pre>
<code>
<span class="line_number">1</span> <span class="keyword">def </span><span class="method">foo</span>
<span class="line_number">2</span> <span class="ident">puts</span> 
<span class="punct">'</span><span class="string">bar</span><span class="punct">'</span>
<span class="line_number">3</span> <span class="keyword">end</span>
</code>
</pre>
La gema syntaxi usa la gema syntax:
[~/rubytesting/syntax_highlighting]$ gem which syntaxi/Users/casiano/.rvm/gems/ruby-1.9.2-head/gems/syntaxi-0.5.0/lib/syntaxi.rb
[~/rubytesting/syntax_highlighting]$ grep "require.*'" /Users/casiano/.rvm/gems/ruby-1.9.2-head/gems/syntaxi-0.5.0/lib/syntaxi.rb 
require 'syntax/convertors/html'
Es en esta gema que se definen las hojas de estilo:
[~/rubytesting/syntax_highlighting]$ gem which syntax
/Users/casiano/.rvm/gems/ruby-1.9.2-head/gems/syntax-1.0.0/lib/syntax.rb
[~/rubytesting/syntax_highlighting]$ tree /Users/casiano/.rvm/gems/ruby-1.9.2-head/gems/syntax-1.0.0/
/Users/casiano/.rvm/gems/ruby-1.9.2-head/gems/syntax-1.0.0/
|-- data
|   |-- ruby.css
|   |-- xml.css
|   `-- yaml.css
|-- lib
|   |-- syntax
|   |   |-- common.rb
|   |   |-- convertors
|   |   |   |-- abstract.rb
|   |   |   `-- html.rb
|   |   |-- lang
|   |   |   |-- ruby.rb
|   |   |   |-- xml.rb
|   |   |   `-- yaml.rb
|   |   `-- version.rb
|   `-- syntax.rb
`-- test
    |-- ALL-TESTS.rb
    |-- syntax
    |   |-- tc_ruby.rb
    |   |-- tc_xml.rb
    |   |-- tc_yaml.rb
    |   `-- tokenizer_testcase.rb
    `-- tc_syntax.rb

7 directories, 17 files

En el esquema incompleto que sigue se ha hecho para el lenguaje Ruby. Añada que se pueda elegir el lenguaje a colorear (xml, yaml).

$ tree -A
.
|-- Gemfile
|-- Gemfile.lock
|-- toopaste.rb
`-- views
    |-- layout.erb
    |-- new.erb
    `-- show.erb

$ cat Gemfile
source 'https://rubygems.org'

# Specify your gem's dependencies in my-gem.gemspec
# gemspec
# gem 'guard'
# gem 'guard-rspec'
# gem 'guard-bundler'
# gem 'rb-fsevent', '~> 0.9.1''

gem 'syntaxi'

Este es un fragmento de la aplicación:

[~/srcSTW/syntax_highlighting(withoutdm)]$ cat  toopaste.rb 
require 'sinatra'
require 'syntaxi'

class String
  def formatted_body
    source = "[code lang='ruby']
                #{self}
              [/code]"
    html = Syntaxi.new(source).process
    %Q{
      <div class="syntax syntax_ruby">
        #{html}
      </div>
    }
  end
end

get '/' do
  erb :new
end

post '/' do
  .....
end
Una versión simple de lo que puede ser new.erb:
[~/srcSTW/syntax_highlighting(withoutdm)]$ cat views/new.erb 
<div class="snippet">
  <form action="/" method="POST">
    <textarea name="body" id="body" rows="20"></textarea>
    <br/><input type="submit" value="Save"/>
  </form>
</div>

Véase la página HTML generada por el programa para la entrada a = 5:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Toopaste!</title>
  <style>
    html {
      background-color: #eee;
    }
    .snippet {
      margin: 5px;
    }
    .snippet textarea, .snippet .sbody {
      border: 5px dotted #eee;
      padding: 5px;
      width: 700px;
      color: #fff;
      background-color: #333;
    }
    .snippet textarea {
      padding: 20px;
    }
    .snippet input, .snippet .sdate {
      margin-top: 5px;
    }

    /* Syntax highlighting */
    #content .syntax_ruby .normal {}
    #content .syntax_ruby .comment { color: #CCC; font-style: italic; border: none; margin: none; }
    #content .syntax_ruby .keyword { color: #C60; font-weight: bold; }
    #content .syntax_ruby .method { color: #9FF; }
    #content .syntax_ruby .class { color: #074; }
    #content .syntax_ruby .module { color: #050; }
    #content .syntax_ruby .punct { color: #0D0; font-weight: bold; }
    #content .syntax_ruby .symbol { color: #099; }
    #content .syntax_ruby .string { color: #C03; }
    #content .syntax_ruby .char { color: #F07; }
    #content .syntax_ruby .ident { color: #0D0; }
    #content .syntax_ruby .constant { color: #07F; }
    #content .syntax_ruby .regex { color: #B66; }
    #content .syntax_ruby .number { color: #FF0; }
    #content .syntax_ruby .attribute { color: #7BB; }
    #content .syntax_ruby .global { color: #7FB; }
    #content .syntax_ruby .expr { color: #909; }
    #content .syntax_ruby .escape { color: #277; }
    #content .syntax {
      background-color: #333;
      padding: 2px;
      margin: 5px;
      margin-left: 1em;
      margin-bottom: 1em;
    }
    #content .syntax .line_number {
      text-align: right;
      font-family: monospace;
      padding-right: 1em;
      color: #999;
    }
  </style>
</head>
<body>
  <div class="snippet">
  <div class="snippet">
  <div class="sbody" id="content">
      <div class="syntax syntax_ruby">
        <pre>
           <code>
              <span class="line_number">1</span>  
              <span class="ident">a</span> 
              <span class="punct">=</span> 
              <span class="number">5</span>
            </code>
         </pre>
      </div>
  </div>
  <br/><a href="/">New Paste!</a>
</div>
</body>
</html>

La gema


Una versión resumida de layout.erb:
[~/srcSTW/syntax_highlighting(withoutdm)]$ cat views/layout.erb 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title><%= @title || 'Toopaste!' %></title>
  <style>
    ..............
  </style>
</head>
<body>
  <%= yield %>
</body>
</html>

Casiano Rodriguez León 2015-01-07