Brian Kelly
Brian Kelly

Reputation: 5664

How can I get Sinatra to deliver Markdown as HTML as well as the source code as plain text?

I'm building a simple "notes" site using Sinatra and Heroku. I write my notes up using Markdown and use the rdiscount gem to convert them to HTML in Sinatra. So a request for /foo would serve up the template /views/foo.md, converted to HTML

What I'd also like to be able to do is serve up the Markdown source as a plain text file. So /foo/source (or something similar) would server up /views/foo.md as plain text.

I've tried using ERB but it just ends up wanting to serve /views/foo.erb.

Here is my current app:

require 'sinatra'
require 'rdiscount'

set :markdown, :layout_engine => :erb

get '/' do
  markdown :index
end

get '/:topic' do
  markdown params[:topic].to_sym
end

Upvotes: 2

Views: 3050

Answers (3)

AlexChaffee
AlexChaffee

Reputation: 8252

Short answer: use File.read to suck in the file's contents, then do what you want with it:

get '/topic/:topic'
    markdown File.read(params[:topic] + ".md")
end

Long answer: Sinatra can get kind of goofy with dots and colons and file types, so you may have to wrest control of the parameter. The following (working!) Sinatra app may help demonstrate.

require 'rubygems'
require 'sinatra'

get '/' do  
  markdown <<-MARKDOWN
# Markdown in Sinatra
* [markdown](/notes)
* [plain text](/notes.txt)
* [pre html](/notes.html)
  MARKDOWN
end

def source
  parts = params[:base].split('.')
  name = parts.first
  ext = parts.last
  filename = name  + ".md"
  source = File.read(filename)
  puts "filename=" + filename.inspect
  puts "source=" + source.inspect
  source
end

get '/:base.txt' do
  source
end

get '/:base.html' do
  "<pre>#{source}</pre>"
end

get '/:base' do
  markdown source
end

Upvotes: 4

Brian Kelly
Brian Kelly

Reputation: 5664

With a little more searching I managed to get it working using send_file:

get '/:topic/source' do
  send_file File.dirname(__FILE__) + "/views/#{params[:topic]}.md", :type => :text
end

But I'd like to believe there's a more elegant solution out there, so leaving the question open for now.

Upvotes: 0

kikito
kikito

Reputation: 52688

You can try using the str template:

get '/:topic/source' do
  str params[:topic].to_sym
end

The only thing to take into account is that it'll try to interpolate the values like it would do with a string - in other words, it'll try to replace #{foo} with foo.to_s. This might or might not be desirable.

Disclaimer: I'm not sure it'll work, I had to deduce this functionality by looking at the source code of Tilt, and I haven't tested it.

Edit: I'm afraid that doesn't work. It's possible to define the str method like this:

helpers do
  def str(*args) render(:str, *args) end
end

The Tilt engine tries to find a view called 'foo.str' instead of using 'foo.md'. I also tried registering 'md' as a valid extension of StringTemplate, but it didn't work (I either got the markdown rendered as a string, or I had the same error as before.

Sorry.

Upvotes: -1

Related Questions