mirror of
https://github.com/sinatra/sinatra
synced 2023-03-27 23:18:01 -04:00
starting again
This commit is contained in:
parent
03626a1ec4
commit
e53fb2bcad
53 changed files with 60 additions and 2225 deletions
|
@ -1,8 +0,0 @@
|
||||||
v0.1.7 FIXES:
|
|
||||||
|
|
||||||
* test/development/production helpers changed to config_for. There was a problem with "test" fubar'ing libraries such as the new release of Sequel
|
|
||||||
* StaticEvent now makes sure the file it's looking for is really a file.
|
|
||||||
|
|
||||||
v0.1.6 Additions: require users vendor directory on load
|
|
||||||
v0.1.5 Mutex and before-filters
|
|
||||||
v0.1.0 Released!
|
|
22
LICENSE
22
LICENSE
|
@ -1,22 +0,0 @@
|
||||||
Copyright (c) 2007 Blake Mizerany
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use,
|
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
52
Manifest
52
Manifest
|
@ -1,52 +0,0 @@
|
||||||
CHANGELOG
|
|
||||||
examples/hello/hello.rb
|
|
||||||
examples/hello/views/hello.erb
|
|
||||||
examples/todo/todo.rb
|
|
||||||
files/default_index.erb
|
|
||||||
files/error.erb
|
|
||||||
files/logo.png
|
|
||||||
files/not_found.erb
|
|
||||||
lib/sinatra/context/renderer.rb
|
|
||||||
lib/sinatra/context.rb
|
|
||||||
lib/sinatra/core_ext/array.rb
|
|
||||||
lib/sinatra/core_ext/class.rb
|
|
||||||
lib/sinatra/core_ext/hash.rb
|
|
||||||
lib/sinatra/core_ext/kernel.rb
|
|
||||||
lib/sinatra/core_ext/metaid.rb
|
|
||||||
lib/sinatra/core_ext/module.rb
|
|
||||||
lib/sinatra/core_ext/symbol.rb
|
|
||||||
lib/sinatra/dispatcher.rb
|
|
||||||
lib/sinatra/dsl.rb
|
|
||||||
lib/sinatra/environment.rb
|
|
||||||
lib/sinatra/event.rb
|
|
||||||
lib/sinatra/irb.rb
|
|
||||||
lib/sinatra/loader.rb
|
|
||||||
lib/sinatra/logger.rb
|
|
||||||
lib/sinatra/options.rb
|
|
||||||
lib/sinatra/rack_ext/request.rb
|
|
||||||
lib/sinatra/route.rb
|
|
||||||
lib/sinatra/server.rb
|
|
||||||
lib/sinatra/sessions.rb
|
|
||||||
lib/sinatra/test_methods.rb
|
|
||||||
lib/sinatra.rb
|
|
||||||
LICENSE
|
|
||||||
Manifest
|
|
||||||
RakeFile
|
|
||||||
README
|
|
||||||
site/index.htm
|
|
||||||
site/index.html
|
|
||||||
site/logo.png
|
|
||||||
test/helper.rb
|
|
||||||
test/sinatra/dispatcher_test.rb
|
|
||||||
test/sinatra/event_test.rb
|
|
||||||
test/sinatra/renderer_test.rb
|
|
||||||
test/sinatra/request_test.rb
|
|
||||||
test/sinatra/route_test.rb
|
|
||||||
test/sinatra/static_files/foo.txt
|
|
||||||
test/sinatra/static_files_test.rb
|
|
||||||
test/sinatra/url_test.rb
|
|
||||||
vendor/erb/init.rb
|
|
||||||
vendor/erb/lib/erb.rb
|
|
||||||
vendor/haml/init.rb
|
|
||||||
vendor/haml/lib/haml.rb
|
|
||||||
Rakefile
|
|
119
README
119
README
|
@ -1,119 +0,0 @@
|
||||||
Sinatra (C) 2007 By Blake Mizerany
|
|
||||||
|
|
||||||
= Classy web-development dressed in a DSL
|
|
||||||
|
|
||||||
== Install!
|
|
||||||
|
|
||||||
sudo gem install sinatra -y
|
|
||||||
|
|
||||||
== Use!
|
|
||||||
|
|
||||||
I'm going to move quick. I'll let you drool at your own pace.
|
|
||||||
|
|
||||||
* Create a file called lyrics.rb (or any name you like)
|
|
||||||
|
|
||||||
* Add
|
|
||||||
require 'rubygems'
|
|
||||||
require 'sinatra'
|
|
||||||
|
|
||||||
* Run (yes, with just ruby)
|
|
||||||
% ruby lyrics.rb
|
|
||||||
== Sinata has taken the stage on port 4567!
|
|
||||||
|
|
||||||
* Take a moment and view the default page http://localhost:4567. Go ahead and bask in it's glory.
|
|
||||||
|
|
||||||
* Notice:
|
|
||||||
* It didn't create any page to show you that default page (just a cool thing to see, that's all)
|
|
||||||
* There was nothing generated other than a log file
|
|
||||||
* Sinatra is a really cool name for a web-framework that's a DSL
|
|
||||||
|
|
||||||
* Modify lyrics.rb by adding:
|
|
||||||
get '/' do
|
|
||||||
'Hello World'
|
|
||||||
end
|
|
||||||
|
|
||||||
* Refresh (no need to restart Sinatra):
|
|
||||||
http://localhost:4567
|
|
||||||
|
|
||||||
* Modify again (then refresh) -- And yes, this presentation logic can be quickly extracted to a template.. see below.
|
|
||||||
get '/' do
|
|
||||||
<<-HTML
|
|
||||||
<form action='/' method="POST">
|
|
||||||
<input type="text" name="name" />
|
|
||||||
<input type="submit" value="Say my name!" />
|
|
||||||
</form>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
post '/' do
|
|
||||||
"Hello #{params[:name] || 'World'}!"
|
|
||||||
end
|
|
||||||
|
|
||||||
* Test (lyrics_test.rb) -- We should be doing this first... for the purposes of this tutorial, we're doing it here
|
|
||||||
|
|
||||||
require 'sinatra/test/spec'
|
|
||||||
require 'lyrics'
|
|
||||||
|
|
||||||
context "My app" do
|
|
||||||
specify "should have a form" do
|
|
||||||
get_it '/'
|
|
||||||
response.should.be.ok
|
|
||||||
body.scan('form').size.should.equal 1
|
|
||||||
|
|
||||||
post_it '/', :name => 'Sinatra'
|
|
||||||
response.should.be.ok
|
|
||||||
body.should.equal 'Hello Sinatra!'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
For more test helpers see: Sinatra::Test::Methods and http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
|
|
||||||
|
|
||||||
* Now you try:
|
|
||||||
Use the Sinatra::Erb::EventContext or Sinatra::Haml::EventContext to do the same. Do them inline and as template files.
|
|
||||||
|
|
||||||
* Learn more cool stuff:
|
|
||||||
see Sinatra::Dsl
|
|
||||||
|
|
||||||
* Create your own plugins!
|
|
||||||
1. Create a 'vendor' directory in your app directory
|
|
||||||
2. Lay it out like:
|
|
||||||
|
|
||||||
myapp.rb : root
|
|
||||||
|- vendor
|
|
||||||
| - plugin_name
|
|
||||||
| - init.rb # load and hook here
|
|
||||||
| - lib
|
|
||||||
|- modules/classes here
|
|
||||||
|
|
||||||
3. Use it in your app!
|
|
||||||
|
|
||||||
see $SINATRA_GEM_ROOT/vendor/erb or $SINATRA_GEM_ROOT/vendor/erb for examples.
|
|
||||||
|
|
||||||
* Tell!
|
|
||||||
We would love to here what you're doing with Sinatra and any cool patches/features you would like. (blake { dot } mizerany [ at ] gmail)
|
|
||||||
|
|
||||||
* Talk!
|
|
||||||
IRC (irc.freenode.com #sinatra)
|
|
||||||
Mailing List (sinatrarb@googlegroups.com)
|
|
||||||
|
|
||||||
* Contribute
|
|
||||||
|
|
||||||
We're using git as our scm.. cuz.. it rocks. You can get the latest source from http://repo.or.cz/w/sinatra.git
|
|
||||||
|
|
||||||
NOTE: You can also get tar'd snapshots of each commit there too. So technically you don't need git to get the latest code.
|
|
||||||
|
|
||||||
It's probably going to happen.. you'll find a bug. Please help by:
|
|
||||||
|
|
||||||
* Sending a message to sintrarb@googlegroups.com with BUG: at the start of the subject (I'm working on a better tracking system)
|
|
||||||
* Please send patches or pull requests to (blake { dot } mizerany [ at ] gmail) don't forget the dot com. ;)
|
|
||||||
|
|
||||||
== Thanks!
|
|
||||||
|
|
||||||
- Ezra Zygmuntowicz (http://brainspl.at) for answering all those random questions over IM and all the poached code
|
|
||||||
- Ditto to Chris Wanstrath (errtheblog.com) and helping me keep things simple, and some cool tricks
|
|
||||||
- Ari Lerner over at CitrusByte for ideas, code, and enthusiasm
|
|
||||||
- Christian Neukirchen for Rack (http://rack.rubyforge.org/)
|
|
||||||
- Koshi (http://www.songbirdnest.com/jkoshi/blog) here at POTI, Inc. for the Sinatra mark
|
|
||||||
- Pete Golibersuch for the hat logo
|
|
||||||
- John Philip Green (http://www.linkedin.com/in/johngreen) for motivation and evangelism
|
|
||||||
- The team here at songbirdnest.com for cool ideas
|
|
35
RakeFile
35
RakeFile
|
@ -1,35 +0,0 @@
|
||||||
require 'rake/testtask'
|
|
||||||
require 'ftools'
|
|
||||||
|
|
||||||
Version = '0.1.0'
|
|
||||||
|
|
||||||
begin
|
|
||||||
require 'rubygems'
|
|
||||||
gem 'echoe'
|
|
||||||
ENV['RUBY_FLAGS'] = ""
|
|
||||||
require 'echoe'
|
|
||||||
|
|
||||||
Echoe.new('sinatra') do |p|
|
|
||||||
p.rubyforge_name = 'sinatra'
|
|
||||||
p.dependencies = ['mongrel >=1.0.1', 'rack >=0.2.0']
|
|
||||||
p.summary = "Sinatra is a classy web-framework dressed in a DSL"
|
|
||||||
p.description = "Sinatra is a classy web-framework dressed in a DSL"
|
|
||||||
p.url = "http://sinatra.rubyforge.org/"
|
|
||||||
p.author = 'Blake Mizerany'
|
|
||||||
p.email = "blake.mizerany@gmail.com"
|
|
||||||
p.test_pattern = 'test/**/*_test.rb'
|
|
||||||
p.include_rakefile = true
|
|
||||||
p.rdoc_pattern = ['README', 'LICENSE'] + Dir.glob('lib/**/*.rb') + Dir.glob('vendor/**/*.rb') + Dir.glob('lib/sinatra/test/*.rb')
|
|
||||||
p.docs_host = "bmizerany@rubyforge.org:/var/www/gforge-projects/"
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue LoadError
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'Clear all the log files from here down'
|
|
||||||
task :remove_logs do
|
|
||||||
Dir.glob(Dir.pwd + '/**/*.log') do |logfile|
|
|
||||||
FileUtils.rm(logfile)
|
|
||||||
puts 'Removed: %s' % logfile
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,26 +0,0 @@
|
||||||
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
|
|
||||||
require 'sinatra'
|
|
||||||
|
|
||||||
config_for(:production) do
|
|
||||||
|
|
||||||
get 404 do
|
|
||||||
"Not sure what you're looking for .. try something else."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/' do
|
|
||||||
"Hello World!"
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/erb.xml' do
|
|
||||||
header 'Content-Type' => 'application/xml'
|
|
||||||
'<this_is_xml/>'
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/erb' do
|
|
||||||
erb :hello
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/erb2' do
|
|
||||||
erb 'Hello <%= params[:name].capitalize || "World" %> 2!'
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
Hello <%= params[:name].capitalize || 'World' %>!
|
|
|
@ -1,42 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
|
||||||
<title>Sinatra has taken the stage!</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
body {
|
|
||||||
color: #333;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: center;
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content pre {
|
|
||||||
text-align: left;
|
|
||||||
background-color: #D8D8D8;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div id="content">
|
|
||||||
<div id="banner">
|
|
||||||
<img src="http://sinatra.rubyforge.org/logo.png">
|
|
||||||
</div>
|
|
||||||
<div id="content">
|
|
||||||
<h3>Sing this diddy to move on:</h3>
|
|
||||||
<pre>
|
|
||||||
get "/" do
|
|
||||||
... your code here ..
|
|
||||||
end</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<h2>Error!</h2>
|
|
||||||
|
|
||||||
<h3>
|
|
||||||
<%= @error.message %>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div id="backtrace">
|
|
||||||
<%= @error.backtrace.join('<br/>') %>
|
|
||||||
</div>
|
|
BIN
files/logo.png
BIN
files/logo.png
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
|
@ -1,52 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
|
||||||
<title>Not Found :: Sinatra</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body id="not_found">
|
|
||||||
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
body {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
font-size: 20px;
|
|
||||||
font-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
}
|
|
||||||
|
|
||||||
.message pre {
|
|
||||||
font-size: 15px;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
background-color: #ccc;
|
|
||||||
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="container">
|
|
||||||
<div id="content">
|
|
||||||
<div class='message'>
|
|
||||||
<h3>Sinatra doesn't know this diddy, but he's a quick study.</h3>
|
|
||||||
<p>Sing this one:</p>
|
|
||||||
<pre><%= request.request_method.downcase %> '<%= request.path_info %>' do
|
|
||||||
html "Replace this with your code."
|
|
||||||
end</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
105
lib/sinatra.rb
105
lib/sinatra.rb
|
@ -1,50 +1,65 @@
|
||||||
# Copyright (c) 2007 Blake Mizerany
|
require "rubygems"
|
||||||
#
|
require "rack"
|
||||||
# Permission is hereby granted, free of charge, to any person
|
|
||||||
# obtaining a copy of this software and associated documentation
|
|
||||||
# files (the "Software"), to deal in the Software without
|
|
||||||
# restriction, including without limitation the rights to use,
|
|
||||||
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the
|
|
||||||
# Software is furnished to do so, subject to the following
|
|
||||||
# conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be
|
|
||||||
# included in all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
%w(rubygems rack).each do |library|
|
class String
|
||||||
begin
|
def to_param
|
||||||
require library
|
URI.escape(self)
|
||||||
rescue LoadError
|
end
|
||||||
raise "== Sinatra cannot run without #{library} installed"
|
|
||||||
|
def from_param
|
||||||
|
URI.unescape(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
SINATRA_ROOT = File.dirname(__FILE__) + '/..'
|
class Symbol
|
||||||
|
def to_proc
|
||||||
require File.dirname(__FILE__) + '/sinatra/loader'
|
Proc.new { |*args| args.shift.__send__(self, *args) }
|
||||||
|
end
|
||||||
Sinatra::Loader.load_files Dir.glob(SINATRA_ROOT + '/lib/sinatra/core_ext/*.rb')
|
|
||||||
Sinatra::Loader.load_files Dir.glob(SINATRA_ROOT + '/lib/sinatra/rack_ext/*.rb')
|
|
||||||
Sinatra::Loader.load_files Dir.glob(SINATRA_ROOT + '/lib/sinatra/*.rb')
|
|
||||||
|
|
||||||
Sinatra::Environment.prepare
|
|
||||||
|
|
||||||
Sinatra::Loader.load_files Dir.glob(SINATRA_ROOT + '/vendor/*/init.rb')
|
|
||||||
Sinatra::Loader.load_files Dir.glob(File.dirname($0) + '/vendor/*/init.rb')
|
|
||||||
|
|
||||||
at_exit do
|
|
||||||
raise $! if $!
|
|
||||||
Sinatra::Environment.prepare_loggers unless Sinatra::Environment.test?
|
|
||||||
Sinatra::Irb.start! if Sinatra::Options.console
|
|
||||||
Sinatra::Server.new.start unless Sinatra::Server.running
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Array
|
||||||
|
def to_hash
|
||||||
|
self.inject({}) { |h, (k, v)| h[k] = v; h }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Sinatra
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def request_types
|
||||||
|
@request_types ||= %w(GET PUT POST DELETE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def events
|
||||||
|
@events ||= Hash.new do |hash, key|
|
||||||
|
hash[key] = [] if request_types.include?(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Route
|
||||||
|
|
||||||
|
URI_CHAR = '[^/?:,&#]'.freeze unless defined?(URI_CHAR)
|
||||||
|
PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
|
||||||
|
|
||||||
|
def initialize(path, &b)
|
||||||
|
@path, @block = path, b
|
||||||
|
@param_keys = []
|
||||||
|
regex = path.to_s.gsub(PARAM) do
|
||||||
|
@param_keys << $1.intern
|
||||||
|
"(#{URI_CHAR}+)"
|
||||||
|
end
|
||||||
|
@pattern = /^#{regex}$/
|
||||||
|
@struct = Struct.new(:block, :params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def match(path)
|
||||||
|
return nil unless path =~ @pattern
|
||||||
|
params = @param_keys.zip($~.captures.map(&:from_param)).to_hash
|
||||||
|
@struct.new(@block, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/context/renderer'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
class EventContext
|
|
||||||
|
|
||||||
cattr_accessor :logger
|
|
||||||
cattr_accessor :reraise_errors
|
|
||||||
attr_reader :request, :response
|
|
||||||
|
|
||||||
include Sinatra::Renderer
|
|
||||||
|
|
||||||
def initialize(request) #:nodoc:
|
|
||||||
@request = request
|
|
||||||
@response = Rack::Response.new
|
|
||||||
@response.body = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sets or returns the status
|
|
||||||
def status(value = nil)
|
|
||||||
@response.status = value if value
|
|
||||||
@response.status || 200
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sets or returns the body
|
|
||||||
# *Usage*
|
|
||||||
# body 'test'
|
|
||||||
# or
|
|
||||||
# body do
|
|
||||||
# 'test'
|
|
||||||
# end
|
|
||||||
# both are the same
|
|
||||||
#
|
|
||||||
def body(value = nil, &block)
|
|
||||||
@response.body = value if value
|
|
||||||
@response.body = block.call if block
|
|
||||||
@response.body
|
|
||||||
end
|
|
||||||
|
|
||||||
# Renders an exception to +body+ and sets status to 500
|
|
||||||
def error(value = nil)
|
|
||||||
raise value if value.kind_of?(Exception) && reraise_errors
|
|
||||||
if value
|
|
||||||
status 500
|
|
||||||
@error = value
|
|
||||||
erb :error, :views_directory => SINATRA_ROOT + '/files/'
|
|
||||||
end
|
|
||||||
@error
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_cookie(key, value)
|
|
||||||
@response.set_cookie(key, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_cookie(key, value)
|
|
||||||
@response.delete_cookie(key, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sets or returns response headers
|
|
||||||
#
|
|
||||||
# *Usage*
|
|
||||||
# header 'Content-Type' => 'text/html'
|
|
||||||
# header 'Foo' => 'Bar'
|
|
||||||
# or
|
|
||||||
# headers 'Content-Type' => 'text/html',
|
|
||||||
# 'Foo' => 'Bar'
|
|
||||||
#
|
|
||||||
# Whatever blows your hair back
|
|
||||||
def headers(value = nil)
|
|
||||||
@response.headers.merge!(value) if value
|
|
||||||
@response.headers
|
|
||||||
end
|
|
||||||
alias :header :headers
|
|
||||||
|
|
||||||
# Returns a Hash of params. Keys are symbolized
|
|
||||||
def params
|
|
||||||
@params ||= @request.params.symbolize_keys
|
|
||||||
end
|
|
||||||
|
|
||||||
# Redirect to a url
|
|
||||||
def redirect(path)
|
|
||||||
logger.info "Redirecting to: #{path}"
|
|
||||||
status 302
|
|
||||||
header 'Location' => path
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_event #:nodoc:
|
|
||||||
logger.info "#{request.request_method} #{request.path_info} | Status: #{status} | Params: #{params.inspect}"
|
|
||||||
logger.exception(error) if error
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,75 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
# The magic or rendering happens here. This is included in Sinatra::EventContext on load.
|
|
||||||
#
|
|
||||||
# These methods are the foundation for Sinatra::Erb and Sinatra::Haml and allow you to quickly
|
|
||||||
# create custom wrappers for your favorite rendering engines outside of erb and haml.
|
|
||||||
|
|
||||||
module Renderer
|
|
||||||
|
|
||||||
Layouts = Hash.new # :nodoc:
|
|
||||||
|
|
||||||
DEFAULT_OPTIONS = {
|
|
||||||
:views_directory => 'views',
|
|
||||||
:layout => :layout
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Renders templates from a string or file and handles their layouts:
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# module MyRenderer
|
|
||||||
# def my(template, options, &layout)
|
|
||||||
# render(template, :my, options, &layout)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# def render_my(template)
|
|
||||||
# template.capitalize # It capitalizes templates!!!!! WOW!
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# Sinatra::EventContext.send :include, MyRenderer
|
|
||||||
#
|
|
||||||
# get '/' do
|
|
||||||
# my "something"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# get_it '/' # => 'Something'
|
|
||||||
#
|
|
||||||
# The second method is named render_extname. render will call this dynamicly
|
|
||||||
#
|
|
||||||
# paramaters:
|
|
||||||
# * +template+ If String, renders the string. If Symbol, reads from file with the basename of the Symbol; uses +renderer+ for extension.
|
|
||||||
# * +renderer+ A symbol defining the render_ method to call and the extension append to +template+ when looking in the +views_directory+
|
|
||||||
# * +options+ An optional Hash of options (see next section)
|
|
||||||
#
|
|
||||||
# options:
|
|
||||||
# * +:views_directory+ Allows you to override the default 'views' directory an look for the template in another
|
|
||||||
# * +:layout+ Which layout to use (see Sinatra::Dsl). false to force a render with no layout. Defaults to :default layout
|
|
||||||
#
|
|
||||||
def render(template, renderer, options = {})
|
|
||||||
options = DEFAULT_OPTIONS.merge(options)
|
|
||||||
|
|
||||||
layout = block_given? ? yield : Layouts[options[:layout]]
|
|
||||||
|
|
||||||
result_method = 'render_%s' % renderer
|
|
||||||
|
|
||||||
if layout
|
|
||||||
send(result_method, layout) { send(result_method, determine_template(template, renderer, options)) }
|
|
||||||
else
|
|
||||||
send(result_method, determine_template(template, renderer, options))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def determine_template(template, ext, options)
|
|
||||||
if template.is_a?(Symbol)
|
|
||||||
File.read("%s/%s.%s" % [options[:views_directory], template, ext])
|
|
||||||
else
|
|
||||||
template
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,5 +0,0 @@
|
||||||
class Array
|
|
||||||
def to_hash
|
|
||||||
self.inject({}) { |h, (k, v)| h[k] = v; h }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,49 +0,0 @@
|
||||||
# Extends the class object with class and instance accessors for class attributes,
|
|
||||||
# just like the native attr* accessors for instance attributes.
|
|
||||||
class Class # :nodoc:
|
|
||||||
def cattr_reader(*syms)
|
|
||||||
syms.flatten.each do |sym|
|
|
||||||
next if sym.is_a?(Hash)
|
|
||||||
class_eval(<<-EOS, __FILE__, __LINE__)
|
|
||||||
unless defined? @@#{sym}
|
|
||||||
@@#{sym} = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.#{sym}
|
|
||||||
@@#{sym}
|
|
||||||
end
|
|
||||||
|
|
||||||
def #{sym}
|
|
||||||
@@#{sym}
|
|
||||||
end
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def cattr_writer(*syms)
|
|
||||||
options = syms.last.is_a?(Hash) ? syms.pop : {}
|
|
||||||
syms.flatten.each do |sym|
|
|
||||||
class_eval(<<-EOS, __FILE__, __LINE__)
|
|
||||||
unless defined? @@#{sym}
|
|
||||||
@@#{sym} = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.#{sym}=(obj)
|
|
||||||
@@#{sym} = obj
|
|
||||||
end
|
|
||||||
|
|
||||||
#{"
|
|
||||||
def #{sym}=(obj)
|
|
||||||
@@#{sym} = obj
|
|
||||||
end
|
|
||||||
" unless options[:instance_writer] == false }
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def cattr_accessor(*syms)
|
|
||||||
cattr_reader(*syms)
|
|
||||||
cattr_writer(*syms)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
class Hash
|
|
||||||
|
|
||||||
def symbolize_keys
|
|
||||||
self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,16 +0,0 @@
|
||||||
module Kernel
|
|
||||||
# (Taken from ActiveSupport)
|
|
||||||
# Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
|
|
||||||
#
|
|
||||||
# silence_warnings do
|
|
||||||
# value = noisy_call # no warning voiced
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# noisy_call # warning voiced
|
|
||||||
def silence_warnings
|
|
||||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
$VERBOSE = old_verbose
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Compliments to why for this:
|
|
||||||
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
|
||||||
|
|
||||||
class Object
|
|
||||||
# The hidden singleton lurks behind everyone
|
|
||||||
def metaclass; class << self; self; end; end
|
|
||||||
def meta_eval &blk; metaclass.instance_eval &blk; end
|
|
||||||
|
|
||||||
# Adds methods to a metaclass
|
|
||||||
def meta_def name, &blk
|
|
||||||
meta_eval { define_method name, &blk }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Defines an instance method within a class
|
|
||||||
def class_def name, &blk
|
|
||||||
class_eval { define_method name, &blk }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
class Module
|
|
||||||
def attr_with_default(sym, default)
|
|
||||||
define_method "#{sym}=" do |obj|
|
|
||||||
instance_variable_set("@#{sym}", obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
define_method sym do
|
|
||||||
instance_variable_get("@#{sym}") || default
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +0,0 @@
|
||||||
class Symbol
|
|
||||||
def to_proc
|
|
||||||
Proc.new { |*args| args.shift.__send__(self, *args) }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
class Dispatcher
|
|
||||||
|
|
||||||
cattr_accessor :logger
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
Loader.reload! if Options.environment == :development
|
|
||||||
|
|
||||||
@request = Rack::Request.new(env)
|
|
||||||
|
|
||||||
event = EventManager.determine_event(
|
|
||||||
@request.request_method.downcase.intern,
|
|
||||||
@request.path_info
|
|
||||||
)
|
|
||||||
|
|
||||||
result = event.attend(@request)
|
|
||||||
result.response.to_a
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,169 +0,0 @@
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
module Dsl
|
|
||||||
|
|
||||||
# Define an Event that responds to a +path+ on GET method
|
|
||||||
#
|
|
||||||
# The +path+ can be a template (i.e. '/:foo/bar/:baz'). When recognized, it will add <tt>:foo</tt> and <tt>:baz</tt> to +params+ with their values.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# # Going RESTful
|
|
||||||
#
|
|
||||||
# get '/' do
|
|
||||||
# .. show stuff ..
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# post '/' do
|
|
||||||
# .. add stuff ..
|
|
||||||
# redirect '/'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# put '/:id' do
|
|
||||||
# .. update params[:id] ..
|
|
||||||
# redirect '/'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# delete '/:id' do
|
|
||||||
# .. delete params[:id] ..
|
|
||||||
# redirect '/'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# BIG NOTE: PUT and DELETE are trigged when POSTing to their paths with a <tt>_method</tt> param whose value is PUT or DELETE
|
|
||||||
#
|
|
||||||
def get(path, &block)
|
|
||||||
Sinatra::Event.new(:get, path, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Same as get but responds to POST
|
|
||||||
def post(path, &block)
|
|
||||||
Sinatra::Event.new(:post, path, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Same as get but responds to PUT
|
|
||||||
#
|
|
||||||
# BIG NOTE: PUT and DELETE are trigged when POSTing to their paths with a <tt>_method</tt> param whose value is PUT or DELETE
|
|
||||||
def put(path, &block)
|
|
||||||
Sinatra::Event.new(:put, path, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Same as get but responds to DELETE
|
|
||||||
#
|
|
||||||
# BIG NOTE: PUT and DELETE are trigged when POSTing to their paths with a <tt>_method</tt> param whose value is PUT or DELETE
|
|
||||||
def delete(path, &block)
|
|
||||||
Sinatra::Event.new(:delete, path, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run given block after each Event's execution
|
|
||||||
# Usage:
|
|
||||||
# before_attend do
|
|
||||||
# logger.debug "After event attend!"
|
|
||||||
# end
|
|
||||||
# or
|
|
||||||
# before_attend :authorize # authorize is a helper method defined using helpers
|
|
||||||
#
|
|
||||||
# Stop execution using - throw :halt
|
|
||||||
# before_attend do
|
|
||||||
# throw :halt, 401 unless has_access?
|
|
||||||
# end
|
|
||||||
# Throw a Symbol to execute a helper method
|
|
||||||
# Throw a String to render it as the content
|
|
||||||
# Throw a Fixnum to set the status
|
|
||||||
#
|
|
||||||
def before_attend(filter_name = nil, options ={}, &block)
|
|
||||||
Sinatra::Event.before_attend(filter_name, options, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run given block after each Event's execution
|
|
||||||
# Example:
|
|
||||||
# after_attend do
|
|
||||||
# logger.debug "After event attend!"
|
|
||||||
# end
|
|
||||||
# or
|
|
||||||
# after_attend :clean_up # clean_up is a helper method defined using helpers
|
|
||||||
#
|
|
||||||
def after_attend(filter_name = nil, options ={}, &block)
|
|
||||||
Sinatra::Event.after_attend(filter_name, options, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add methods to each event for use during execution
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# helpers do
|
|
||||||
# def foo
|
|
||||||
# 'foo!'
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# get '/bar' do
|
|
||||||
# foo
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# get_it '/bar' # => 'foo!'
|
|
||||||
#
|
|
||||||
def helpers(&block)
|
|
||||||
Sinatra::EventContext.class_eval(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Maps a path to a physical directory containing static files
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# static '/p', 'public'
|
|
||||||
#
|
|
||||||
def static(path, root)
|
|
||||||
Sinatra::StaticEvent.new(path, root)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Execute block if in environment is equal to env (Used for configuration)
|
|
||||||
def config_for(env = :development)
|
|
||||||
yield if Sinatra::Options.environment == env.to_sym
|
|
||||||
end
|
|
||||||
|
|
||||||
# Define named layouts (default name is <tt>:layout</tt>)
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
# # Default layout in Erb
|
|
||||||
# layout do
|
|
||||||
# '-- <%= yield %> --'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # Named layout in Haml
|
|
||||||
# layout :for_haml do
|
|
||||||
# '== XXXX #{yield} XXXX'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # Loads layout named <tt>:"foo.erb"</tt> from file (default behaviour if block is omitted)
|
|
||||||
# layout 'foo.erb' # looks for foo.erb. This is odd an is being re-thought
|
|
||||||
#
|
|
||||||
# def layout(name = :layout, options = {})
|
|
||||||
# Layouts[name] = unless block_given?
|
|
||||||
# File.read("%s/%s" % [options[:views_directory] || 'views', name])
|
|
||||||
# else
|
|
||||||
# yield
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Cool trick:
|
|
||||||
#
|
|
||||||
# # Send a one-time layout to renderer method
|
|
||||||
# get '/cooltrick' do
|
|
||||||
# erb 'wicked' do
|
|
||||||
# 'Cool <%= yield %> Trick'
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# get_it '/cooltrick' # => 'Cool wicked Trick'
|
|
||||||
#
|
|
||||||
def layout(name = :layout, options = {})
|
|
||||||
Sinatra::Renderer::Layouts[name] = unless block_given?
|
|
||||||
File.read("%s/%s" % [options[:views_directory] || 'views', name])
|
|
||||||
else
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
include Sinatra::Dsl
|
|
|
@ -1,19 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
module Environment
|
|
||||||
extend self
|
|
||||||
|
|
||||||
def test?
|
|
||||||
Options.environment == :test
|
|
||||||
end
|
|
||||||
|
|
||||||
def prepare
|
|
||||||
Options.parse!(ARGV)
|
|
||||||
end
|
|
||||||
|
|
||||||
def prepare_loggers(logger = Logger.new(open(Options.log_file, 'w')))
|
|
||||||
[Server, EventContext, Event, Dispatcher].each do |klass|
|
|
||||||
klass.logger = logger
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,244 +0,0 @@
|
||||||
require 'thread'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
module EventManager # :nodoc:
|
|
||||||
extend self
|
|
||||||
|
|
||||||
def reset!
|
|
||||||
@events.clear if @events
|
|
||||||
end
|
|
||||||
|
|
||||||
def events
|
|
||||||
@events || []
|
|
||||||
end
|
|
||||||
|
|
||||||
def register_event(event)
|
|
||||||
(@events ||= []) << event
|
|
||||||
end
|
|
||||||
|
|
||||||
def determine_event(verb, path, if_nil = :present_error)
|
|
||||||
event = events.find(method(if_nil)) do |e|
|
|
||||||
e.verb == verb && e.recognize(path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def present_error
|
|
||||||
determine_event(:get, '404', :not_found)
|
|
||||||
end
|
|
||||||
|
|
||||||
def not_found
|
|
||||||
Event.new(:get, 'not_found', false) do
|
|
||||||
status 404
|
|
||||||
|
|
||||||
if request.path_info == '/' && request.request_method == 'GET'
|
|
||||||
erb :default_index, :views_directory => SINATRA_ROOT + '/files'
|
|
||||||
else
|
|
||||||
erb :not_found, :views_directory => SINATRA_ROOT + '/files'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class Event # :nodoc:
|
|
||||||
|
|
||||||
cattr_accessor :logger
|
|
||||||
cattr_accessor :after_filters
|
|
||||||
cattr_accessor :before_filters
|
|
||||||
|
|
||||||
@@mutex = Mutex.new
|
|
||||||
|
|
||||||
self.before_filters = []
|
|
||||||
self.after_filters = []
|
|
||||||
|
|
||||||
def self.reset!
|
|
||||||
self.before_filters.clear
|
|
||||||
self.after_filters.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.before_attend(method_name = nil, options ={}, &block)
|
|
||||||
setup_filter(:before_filters, method_name, options, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.after_attend(method_name = nil, options = {}, &block)
|
|
||||||
setup_filter(:after_filters, method_name, options, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.setup_filter(filter_set_name, method_name, options = {}, &block)
|
|
||||||
raise "Must specify method or block" if method_name.nil? and !block_given?
|
|
||||||
value = if block_given?
|
|
||||||
block
|
|
||||||
else
|
|
||||||
method_name
|
|
||||||
end
|
|
||||||
insert_index = options[:infront] == true ? 0 : -1
|
|
||||||
send(filter_set_name).insert(insert_index, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :path, :verb
|
|
||||||
|
|
||||||
def initialize(verb, path, register = true, &block)
|
|
||||||
@verb = verb
|
|
||||||
@path = path
|
|
||||||
@route = Route.new(path)
|
|
||||||
@block = block
|
|
||||||
EventManager.register_event(self) if register
|
|
||||||
end
|
|
||||||
|
|
||||||
def attend(request)
|
|
||||||
request.params.merge!(@route.params)
|
|
||||||
context = EventContext.new(request)
|
|
||||||
run_safely do
|
|
||||||
caught = catch(:halt) do
|
|
||||||
call_filters(before_filters, context)
|
|
||||||
end
|
|
||||||
body = case caught
|
|
||||||
when :filter_chain_completed
|
|
||||||
begin
|
|
||||||
context.instance_eval(&@block) if @block
|
|
||||||
rescue => e
|
|
||||||
context.error e
|
|
||||||
end
|
|
||||||
when Symbol
|
|
||||||
context.send(caught)
|
|
||||||
when String
|
|
||||||
caught
|
|
||||||
when Fixnum
|
|
||||||
context.status caught
|
|
||||||
end
|
|
||||||
context.body context.body || body || ''
|
|
||||||
call_filters(after_filters, context)
|
|
||||||
end
|
|
||||||
context.log_event
|
|
||||||
context
|
|
||||||
end
|
|
||||||
alias :call :attend
|
|
||||||
|
|
||||||
def recognize(path)
|
|
||||||
@route.recognize(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def run_safely
|
|
||||||
if Options.use_mutex?
|
|
||||||
@@mutex.synchronize do
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
else
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adapted from Merb
|
|
||||||
# calls a filter chain according to rules.
|
|
||||||
def call_filters(filter_set, context)
|
|
||||||
filter_set.each do |filter|
|
|
||||||
case filter
|
|
||||||
when Symbol, String
|
|
||||||
context.send(filter)
|
|
||||||
when Proc
|
|
||||||
context.instance_eval(&filter)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
:filter_chain_completed
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class StaticEvent < Event # :nodoc:
|
|
||||||
|
|
||||||
def initialize(path, root, register = true)
|
|
||||||
@root = root
|
|
||||||
super(:get, path, register)
|
|
||||||
end
|
|
||||||
|
|
||||||
def recognize(path)
|
|
||||||
filename = physical_path_for(path)
|
|
||||||
File.exists?(filename) && File.file?(filename)
|
|
||||||
end
|
|
||||||
|
|
||||||
def physical_path_for(path)
|
|
||||||
path.gsub(/^#{@path}/, @root)
|
|
||||||
end
|
|
||||||
|
|
||||||
def attend(request)
|
|
||||||
@filename = physical_path_for(request.path_info)
|
|
||||||
context = EventContext.new(request)
|
|
||||||
context.body self
|
|
||||||
context.header 'Content-Type' => MIME_TYPES[File.extname(@filename)[1..-1]]
|
|
||||||
context.header 'Content-Length' => File.size(@filename).to_s
|
|
||||||
context
|
|
||||||
end
|
|
||||||
|
|
||||||
def each
|
|
||||||
File.open(@filename, "rb") do |file|
|
|
||||||
while part = file.read(8192)
|
|
||||||
yield part
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# :stopdoc:
|
|
||||||
# From WEBrick.
|
|
||||||
MIME_TYPES = {
|
|
||||||
"ai" => "application/postscript",
|
|
||||||
"asc" => "text/plain",
|
|
||||||
"avi" => "video/x-msvideo",
|
|
||||||
"bin" => "application/octet-stream",
|
|
||||||
"bmp" => "image/bmp",
|
|
||||||
"class" => "application/octet-stream",
|
|
||||||
"cer" => "application/pkix-cert",
|
|
||||||
"crl" => "application/pkix-crl",
|
|
||||||
"crt" => "application/x-x509-ca-cert",
|
|
||||||
#"crl" => "application/x-pkcs7-crl",
|
|
||||||
"css" => "text/css",
|
|
||||||
"dms" => "application/octet-stream",
|
|
||||||
"doc" => "application/msword",
|
|
||||||
"dvi" => "application/x-dvi",
|
|
||||||
"eps" => "application/postscript",
|
|
||||||
"etx" => "text/x-setext",
|
|
||||||
"exe" => "application/octet-stream",
|
|
||||||
"gif" => "image/gif",
|
|
||||||
"htm" => "text/html",
|
|
||||||
"html" => "text/html",
|
|
||||||
"jpe" => "image/jpeg",
|
|
||||||
"jpeg" => "image/jpeg",
|
|
||||||
"jpg" => "image/jpeg",
|
|
||||||
"lha" => "application/octet-stream",
|
|
||||||
"lzh" => "application/octet-stream",
|
|
||||||
"mov" => "video/quicktime",
|
|
||||||
"mpe" => "video/mpeg",
|
|
||||||
"mpeg" => "video/mpeg",
|
|
||||||
"mpg" => "video/mpeg",
|
|
||||||
"pbm" => "image/x-portable-bitmap",
|
|
||||||
"pdf" => "application/pdf",
|
|
||||||
"pgm" => "image/x-portable-graymap",
|
|
||||||
"png" => "image/png",
|
|
||||||
"pnm" => "image/x-portable-anymap",
|
|
||||||
"ppm" => "image/x-portable-pixmap",
|
|
||||||
"ppt" => "application/vnd.ms-powerpoint",
|
|
||||||
"ps" => "application/postscript",
|
|
||||||
"qt" => "video/quicktime",
|
|
||||||
"ras" => "image/x-cmu-raster",
|
|
||||||
"rb" => "text/plain",
|
|
||||||
"rd" => "text/plain",
|
|
||||||
"rtf" => "application/rtf",
|
|
||||||
"sgm" => "text/sgml",
|
|
||||||
"sgml" => "text/sgml",
|
|
||||||
"tif" => "image/tiff",
|
|
||||||
"tiff" => "image/tiff",
|
|
||||||
"txt" => "text/plain",
|
|
||||||
"xbm" => "image/x-xbitmap",
|
|
||||||
"xls" => "application/vnd.ms-excel",
|
|
||||||
"xml" => "text/xml",
|
|
||||||
"xpm" => "image/x-xpixmap",
|
|
||||||
"xwd" => "image/x-xwindowdump",
|
|
||||||
"zip" => "application/zip",
|
|
||||||
}
|
|
||||||
# :startdoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,56 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
# Sinatra Irb is entered via <tt>ruby myapp.rb -c</tt> (replace myapp.rb with your app filename)
|
|
||||||
#
|
|
||||||
# Be sure to also check out Sinatra::TestMethods for more cool stuff when your in Irb
|
|
||||||
#
|
|
||||||
module Irb
|
|
||||||
extend self
|
|
||||||
|
|
||||||
# taken from merb
|
|
||||||
def start! #:nodoc:
|
|
||||||
|
|
||||||
Object.send(:include, TestMethods) # added to allow post_to in console
|
|
||||||
|
|
||||||
Object.class_eval do
|
|
||||||
# Reload all Sinatra and App specific files
|
|
||||||
def reload!
|
|
||||||
Loader.reload!
|
|
||||||
end
|
|
||||||
|
|
||||||
# Show the +body+ with result info in your text editor!!! Great Job!
|
|
||||||
def show!(editor = nil)
|
|
||||||
editor = editor || ENV['EDITOR']
|
|
||||||
IO.popen(editor, 'w') do |f|
|
|
||||||
f.puts "<!--"
|
|
||||||
f.puts result_info
|
|
||||||
f.puts "-->"
|
|
||||||
f.puts
|
|
||||||
f.puts body
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
alias :mate :show!
|
|
||||||
|
|
||||||
def result_info #:nodoc:
|
|
||||||
info = <<-end_info
|
|
||||||
# Status: #{status}
|
|
||||||
# Headers: #{headers.inspect}
|
|
||||||
end_info
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ARGV.clear # Avoid passing args to IRB
|
|
||||||
require 'irb'
|
|
||||||
require 'irb/completion'
|
|
||||||
def exit
|
|
||||||
exit!
|
|
||||||
end
|
|
||||||
if File.exists? ".irbrc"
|
|
||||||
ENV['IRBRC'] = ".irbrc"
|
|
||||||
end
|
|
||||||
IRB.start
|
|
||||||
exit!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,31 +0,0 @@
|
||||||
require 'set'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
module Loader
|
|
||||||
extend self
|
|
||||||
|
|
||||||
def reload!
|
|
||||||
silence_warnings do
|
|
||||||
EventManager.reset!
|
|
||||||
load_files loaded_files
|
|
||||||
load $0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_files(*files)
|
|
||||||
files = files.flatten
|
|
||||||
files = files.first if files.first.is_a? Set
|
|
||||||
|
|
||||||
files.each do |file|
|
|
||||||
file = File.expand_path(file)
|
|
||||||
load file
|
|
||||||
loaded_files << file
|
|
||||||
end
|
|
||||||
end
|
|
||||||
alias_method :load_file, :load_files
|
|
||||||
|
|
||||||
def loaded_files
|
|
||||||
@loaded_files ||= Set.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
class Logger
|
|
||||||
|
|
||||||
def initialize(steam)
|
|
||||||
@stream = steam
|
|
||||||
end
|
|
||||||
|
|
||||||
%w(info debug error warn).each do |n|
|
|
||||||
define_method n do |message|
|
|
||||||
@stream.puts message
|
|
||||||
@stream.flush
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def exception(e)
|
|
||||||
error "#{e.message}:\n\t#{e.backtrace.join("\n\t")}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,49 +0,0 @@
|
||||||
require 'optparse'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
module Options
|
|
||||||
extend self
|
|
||||||
|
|
||||||
attr_with_default :port, 4567
|
|
||||||
attr_with_default :environment, :development
|
|
||||||
attr_with_default :console, nil
|
|
||||||
attr_with_default :use_mutex, false
|
|
||||||
|
|
||||||
alias :use_mutex? :use_mutex
|
|
||||||
|
|
||||||
def parse!(args)
|
|
||||||
return if @environment == :test
|
|
||||||
OptionParser.new do |opts|
|
|
||||||
opts.on '-p port', '--port port', 'Set the port (default is 4567)' do |port|
|
|
||||||
@port = port
|
|
||||||
end
|
|
||||||
opts.on '-e environment', 'Set the environment (default if development)' do |env|
|
|
||||||
@environment = env.intern
|
|
||||||
end
|
|
||||||
opts.on '-c', '--console', 'Run in console mode' do
|
|
||||||
@console = true
|
|
||||||
end
|
|
||||||
opts.on '-h', '--help', '-?', 'Show this message' do
|
|
||||||
puts opts
|
|
||||||
exit!
|
|
||||||
end
|
|
||||||
opts.on '-X', '--mutex', 'Use mutex lock when attending events' do
|
|
||||||
@use_mutex = true
|
|
||||||
end
|
|
||||||
end.parse!(ARGV)
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_file
|
|
||||||
# TODO find a better way that this
|
|
||||||
if File.basename($0, '.rb') == 'rake_test_loader' # hack to satisfy rake
|
|
||||||
'%s.log' % environment
|
|
||||||
else
|
|
||||||
File.dirname($0) + ('/%s.log' % environment)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_environment(env)
|
|
||||||
@environment = env
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,15 +0,0 @@
|
||||||
module Rack #:nodoc:
|
|
||||||
|
|
||||||
class Request #:nodoc:
|
|
||||||
|
|
||||||
def request_method
|
|
||||||
if @env['REQUEST_METHOD'] == 'POST' && %w(PUT DELETE).include?(params['_method'])
|
|
||||||
params['_method'].upcase
|
|
||||||
else
|
|
||||||
@env['REQUEST_METHOD']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,65 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
class Route
|
|
||||||
|
|
||||||
SYMBOL_FIND = /:[a-z_]+/.freeze
|
|
||||||
PARENTHETICAL_SEGMENT_STRING = "([^\/.,;?]+)".freeze
|
|
||||||
|
|
||||||
attr_reader :regex, :params
|
|
||||||
|
|
||||||
def initialize(template)
|
|
||||||
@template = template.to_s.strip
|
|
||||||
@default_params = { :format => 'html' }
|
|
||||||
@params = {}
|
|
||||||
extract_keys
|
|
||||||
genereate_route
|
|
||||||
end
|
|
||||||
|
|
||||||
def recognize(path)
|
|
||||||
@params.clear
|
|
||||||
|
|
||||||
param_values = path.match(@regex).captures.compact rescue nil
|
|
||||||
|
|
||||||
if param_values
|
|
||||||
keys = @keys.size < param_values.size ? @keys.concat([:format]) : @keys
|
|
||||||
@params = @default_params.merge(@keys.zip(param_values).to_hash)
|
|
||||||
true
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def extract_keys
|
|
||||||
@keys = @template.scan(SYMBOL_FIND).map { |raw| eval(raw) }
|
|
||||||
@keys
|
|
||||||
end
|
|
||||||
|
|
||||||
def genereate_route_without_format
|
|
||||||
template = @template.dup
|
|
||||||
template.gsub!(/\.:format$/, '')
|
|
||||||
to_regex_route(template)
|
|
||||||
end
|
|
||||||
|
|
||||||
def genereate_route_with_format
|
|
||||||
template = @template.dup
|
|
||||||
if template =~ /\.:format$|\.([\w\d]+)$/
|
|
||||||
@default_params[:format] = $1 if $1
|
|
||||||
else
|
|
||||||
template << '.:format'
|
|
||||||
end
|
|
||||||
to_regex_route(template)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_regex_route(template)
|
|
||||||
/^#{template.gsub(/\./, '\.').gsub(SYMBOL_FIND, PARENTHETICAL_SEGMENT_STRING)}$/
|
|
||||||
end
|
|
||||||
|
|
||||||
def genereate_route
|
|
||||||
@regex = Regexp.union(genereate_route_without_format, genereate_route_with_format)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,57 +0,0 @@
|
||||||
require 'fileutils'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
class Server
|
|
||||||
|
|
||||||
cattr_accessor :logger
|
|
||||||
cattr_accessor :running
|
|
||||||
|
|
||||||
def start
|
|
||||||
begin
|
|
||||||
tail_thread = tail(Options.log_file)
|
|
||||||
Rack::Handler::Mongrel.run(Dispatcher.new, :Port => Options.port) do |server|
|
|
||||||
puts "== Sinatra has taken the stage on port #{server.port}!"
|
|
||||||
trap("INT") do
|
|
||||||
server.stop
|
|
||||||
self.class.running = false
|
|
||||||
puts "\n== Sinatra has ended his set (crowd applauds)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.class.running = true
|
|
||||||
rescue Errno::EADDRINUSE => e
|
|
||||||
puts "== Someone is already performing on port #{Options.port}!"
|
|
||||||
logger.exception e
|
|
||||||
rescue => e
|
|
||||||
logger.exception e
|
|
||||||
ensure
|
|
||||||
tail_thread.kill if tail_thread
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def tail(log_file)
|
|
||||||
FileUtils.touch(log_file)
|
|
||||||
cursor = File.size(log_file)
|
|
||||||
last_checked = Time.now
|
|
||||||
tail_thread = Thread.new do
|
|
||||||
File.open(log_file, 'r') do |f|
|
|
||||||
loop do
|
|
||||||
f.seek cursor
|
|
||||||
if f.mtime > last_checked
|
|
||||||
last_checked = f.mtime
|
|
||||||
contents = f.read
|
|
||||||
cursor += contents.length
|
|
||||||
print contents
|
|
||||||
end
|
|
||||||
sleep 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
tail_thread
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,62 +0,0 @@
|
||||||
require 'uri'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
# These methods are for integration testing without an internet connection. They are available in Test::Unit::TestCase and when in Irb.
|
|
||||||
module Test
|
|
||||||
|
|
||||||
module Methods
|
|
||||||
|
|
||||||
# get_it, post_it, put_it, delete_it
|
|
||||||
# Executes the method and returns the result of the body
|
|
||||||
#
|
|
||||||
# options:
|
|
||||||
# +:params+ a hash of name parameters
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# get_it '/', :name => 'Blake' # => 'Hello Blake!'
|
|
||||||
#
|
|
||||||
%w(get post put delete).each do |verb|
|
|
||||||
module_eval <<-end_eval
|
|
||||||
def #{verb}_it(path, params = {})
|
|
||||||
request = Rack::MockRequest.new(Sinatra::Dispatcher.new)
|
|
||||||
@response = request.#{verb} path, :input => generate_input(params)
|
|
||||||
body
|
|
||||||
end
|
|
||||||
end_eval
|
|
||||||
end
|
|
||||||
|
|
||||||
# The response returned by the Event
|
|
||||||
def response
|
|
||||||
@response || Rack::MockResponse.new(404, {}, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
# The status returned by the event
|
|
||||||
def status
|
|
||||||
response.status
|
|
||||||
end
|
|
||||||
|
|
||||||
# The text returned by the event
|
|
||||||
def text
|
|
||||||
response.body
|
|
||||||
end
|
|
||||||
alias :xml :text
|
|
||||||
alias :html :text
|
|
||||||
alias :body :text
|
|
||||||
|
|
||||||
# The headers returned by the event
|
|
||||||
def headers
|
|
||||||
response.headers
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def generate_input(params)
|
|
||||||
params.map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,39 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/methods'
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
module Test
|
|
||||||
module Spec
|
|
||||||
def self.included(base)
|
|
||||||
silence_warnings do
|
|
||||||
require File.dirname(__FILE__) + '/../../sinatra'
|
|
||||||
require 'test/spec'
|
|
||||||
end
|
|
||||||
Server.running = true
|
|
||||||
Options.set_environment :test
|
|
||||||
Environment.prepare_loggers
|
|
||||||
EventContext.reraise_errors = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
include Sinatra::Test::Spec
|
|
||||||
|
|
||||||
class Test::Spec::TestCase
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
include Sinatra::Test::Methods
|
|
||||||
end
|
|
||||||
|
|
||||||
alias :initialize_orig :initialize
|
|
||||||
|
|
||||||
def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
|
|
||||||
initialize_orig(name, parent, superclass)
|
|
||||||
|
|
||||||
@testcase.setup do
|
|
||||||
Sinatra::EventManager.reset!
|
|
||||||
Sinatra::Event.reset!
|
|
||||||
Sinatra::Renderer::Layouts.clear
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,65 +0,0 @@
|
||||||
require "rubygems"
|
|
||||||
require "rack"
|
|
||||||
|
|
||||||
class String
|
|
||||||
def to_param
|
|
||||||
URI.escape(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_param
|
|
||||||
URI.unescape(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Symbol
|
|
||||||
def to_proc
|
|
||||||
Proc.new { |*args| args.shift.__send__(self, *args) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Array
|
|
||||||
def to_hash
|
|
||||||
self.inject({}) { |h, (k, v)| h[k] = v; h }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Sinatra
|
|
||||||
extend self
|
|
||||||
|
|
||||||
def request_types
|
|
||||||
@request_types ||= %w(GET PUT POST DELETE)
|
|
||||||
end
|
|
||||||
|
|
||||||
def events
|
|
||||||
@events ||= Hash.new do |hash, key|
|
|
||||||
hash[key] = [] if request_types.include?(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Route
|
|
||||||
|
|
||||||
URI_CHAR = '[^/?:,&#]'.freeze unless defined?(URI_CHAR)
|
|
||||||
PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
|
|
||||||
|
|
||||||
def initialize(path, &b)
|
|
||||||
@path, @block = path, b
|
|
||||||
@param_keys = []
|
|
||||||
regex = path.to_s.gsub(PARAM) do
|
|
||||||
@param_keys << $1.intern
|
|
||||||
"(#{URI_CHAR}+)"
|
|
||||||
end
|
|
||||||
@pattern = /^#{regex}$/
|
|
||||||
@struct = Struct.new(:block, :params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def match(path)
|
|
||||||
return nil unless path =~ @pattern
|
|
||||||
params = @param_keys.zip($~.captures.map(&:from_param)).to_hash
|
|
||||||
@struct.new(@block, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
104
site/index.htm
104
site/index.htm
|
@ -1,104 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
|
||||||
<title>Sinatra : Classy web-development dressed in a DSL</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
body {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
font-size: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container {
|
|
||||||
width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container pre {
|
|
||||||
font-size: .8em;
|
|
||||||
background-color: #F5F6C9;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container note {
|
|
||||||
font-size: .7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner {
|
|
||||||
width: 600px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="container">
|
|
||||||
<div id="banner">
|
|
||||||
<img src='logo.png' />
|
|
||||||
<h2><em>Classy web-development dressed in a DSL</em></h2>
|
|
||||||
</div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<strong>Install!</strong><br/>
|
|
||||||
<pre>gem install sinatra -y</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Require!</strong> (any filename you wish)<br/>
|
|
||||||
<pre>
|
|
||||||
# lyrics.rb
|
|
||||||
require 'rubygems'
|
|
||||||
require 'sinatra'</pre>
|
|
||||||
<note>yup.. that's it for a sec</note><br />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Run!</strong><br />
|
|
||||||
<pre>ruby lyrics.rb</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Bask!</strong><br />
|
|
||||||
<pre>http://localhost:4567</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Write!</strong>
|
|
||||||
<pre>
|
|
||||||
get '/' do
|
|
||||||
"Now that's a fine looking dame!"
|
|
||||||
end</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Examples!</strong><br />
|
|
||||||
<pre><a href="http://repo.or.cz/w/sinatra.git?a=tree;f=examples;h=fd7513e49762738ad945adbb2e15bb31528b4207;hb=HEAD">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Docs!</strong><br />
|
|
||||||
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Can you <a href="http://digg.com/programming/Sinatra_Classy_web_development_dressed_in_a_DSL">digg</a> it cats?</strong><br />
|
|
||||||
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Contribute!</strong><br />
|
|
||||||
<pre><a href="http://repo.or.cz/w/sinatra.git">using git</a></pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
104
site/index.html
104
site/index.html
|
@ -1,104 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
|
||||||
<title>Sinatra : Classy web-development dressed in a DSL</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
body {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
font-size: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container {
|
|
||||||
width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container pre {
|
|
||||||
font-size: .8em;
|
|
||||||
background-color: #F5F6C9;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container note {
|
|
||||||
font-size: .7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner {
|
|
||||||
width: 600px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="container">
|
|
||||||
<div id="banner">
|
|
||||||
<img src='logo.png' />
|
|
||||||
<h2><em>Classy web-development dressed in a DSL</em></h2>
|
|
||||||
</div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<strong>Install!</strong><br/>
|
|
||||||
<pre>gem install sinatra -y</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Require!</strong> (any filename you wish)<br/>
|
|
||||||
<pre>
|
|
||||||
# lyrics.rb
|
|
||||||
require 'rubygems'
|
|
||||||
require 'sinatra'</pre>
|
|
||||||
<note>yup.. that's it for a sec</note><br />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Run!</strong><br />
|
|
||||||
<pre>ruby lyrics.rb</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Bask!</strong><br />
|
|
||||||
<pre>http://localhost:4567</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Write!</strong>
|
|
||||||
<pre>
|
|
||||||
get '/' do
|
|
||||||
"Now that's a fine looking dame!"
|
|
||||||
end</pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Examples!</strong><br />
|
|
||||||
<pre><a href="http://repo.or.cz/w/sinatra.git?a=tree;f=examples;h=fd7513e49762738ad945adbb2e15bb31528b4207;hb=HEAD">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Docs!</strong><br />
|
|
||||||
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Can you <a href="http://digg.com/programming/Sinatra_Classy_web_development_dressed_in_a_DSL">digg</a> it cats?</strong><br />
|
|
||||||
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Contribute!</strong><br />
|
|
||||||
<pre><a href="http://repo.or.cz/w/sinatra.git">using git</a></pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
BIN
site/logo.png
BIN
site/logo.png
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
|
@ -1,2 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../lib/sinatra/test/spec'
|
|
||||||
require 'mocha'
|
|
|
@ -1,87 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
describe "When a dispatcher receives a request" do
|
|
||||||
|
|
||||||
it "should attend to the event" do
|
|
||||||
|
|
||||||
Sinatra::Event.new(:get, '/') do
|
|
||||||
body 'this is the index as a get'
|
|
||||||
end
|
|
||||||
|
|
||||||
get_it "/"
|
|
||||||
|
|
||||||
status.should.equal 200
|
|
||||||
text.should.equal 'this is the index as a get'
|
|
||||||
headers['Content-Type'].should.equal 'text/html'
|
|
||||||
|
|
||||||
post_it "/"
|
|
||||||
|
|
||||||
status.should.equal 404
|
|
||||||
text.scan("Not Found :: Sinatra").size.should.equal 1
|
|
||||||
headers['Content-Type'].should.equal 'text/html'
|
|
||||||
|
|
||||||
get_it '/foo'
|
|
||||||
|
|
||||||
status.should.equal 404
|
|
||||||
text.scan("Not Found :: Sinatra").size.should.equal 1
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should use custom error pages if present" do
|
|
||||||
Sinatra::Event.new(:get, 404) do
|
|
||||||
body 'custom 404'
|
|
||||||
end
|
|
||||||
|
|
||||||
get_it('/laksdjf').should.equal 'custom 404'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should reload app files unless in production" do
|
|
||||||
Sinatra::Event.new(:get, '/') {}
|
|
||||||
|
|
||||||
Sinatra::Options.expects(:environment).returns(:production)
|
|
||||||
Sinatra::Loader.expects(:reload!).never
|
|
||||||
get_it '/'
|
|
||||||
|
|
||||||
Sinatra::Options.expects(:environment).returns(:development)
|
|
||||||
Sinatra::Loader.expects(:reload!)
|
|
||||||
get_it '/'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not register not_found (otherwise we'll have a newone in the array for every error)" do
|
|
||||||
Sinatra::EventManager.events.size.should.equal 0
|
|
||||||
get_it '/blake'
|
|
||||||
Sinatra::EventManager.events.size.should.equal 0
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return blocks result if body not called" do
|
|
||||||
event = Sinatra::Event.new(:get, '/return_block') do
|
|
||||||
'no body called'
|
|
||||||
end
|
|
||||||
|
|
||||||
get_it '/return_block'
|
|
||||||
|
|
||||||
status.should.equal 200
|
|
||||||
html.should.equal 'no body called'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should recognize pretty urls" do
|
|
||||||
Sinatra::Event.new(:get, '/test/:name') do
|
|
||||||
params[:name]
|
|
||||||
end
|
|
||||||
|
|
||||||
get_it '/test/blake'
|
|
||||||
body.should.equal 'blake'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should respond to DELETE and PUT" do
|
|
||||||
Sinatra::Event.new(:delete, '/') do
|
|
||||||
request.request_method
|
|
||||||
end
|
|
||||||
|
|
||||||
# Browser only know GET and POST. DELETE and PUT are signaled by passing in a _method paramater
|
|
||||||
post_it '/', :_method => 'DELETE'
|
|
||||||
status.should.equal 200
|
|
||||||
text.should.equal 'DELETE'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,44 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
describe "Event" do
|
|
||||||
|
|
||||||
it "should return 500 if exception thrown" do
|
|
||||||
Sinatra::Environment.prepare_loggers stub_everything
|
|
||||||
|
|
||||||
Sinatra::EventContext.any_instance.expects(:reraise_errors).returns(false)
|
|
||||||
|
|
||||||
event = Sinatra::Event.new(:get, '/') do
|
|
||||||
raise 'whaaaa!'
|
|
||||||
end
|
|
||||||
|
|
||||||
result = event.attend(stub_everything(:params => {}, :path_info => '/'))
|
|
||||||
|
|
||||||
result.status.should.equal 500
|
|
||||||
end
|
|
||||||
|
|
||||||
it "custom error if present" do
|
|
||||||
Sinatra::Environment.prepare_loggers stub_everything
|
|
||||||
|
|
||||||
event = Sinatra::Event.new(:get, '404') do
|
|
||||||
body 'custom 404'
|
|
||||||
end
|
|
||||||
|
|
||||||
Sinatra::EventManager.expects(:not_found).never
|
|
||||||
Sinatra::EventManager.determine_event(:get, '/sdf')
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should show default 404 if custom not present" do
|
|
||||||
Sinatra::EventManager.expects(:not_found)
|
|
||||||
Sinatra::EventManager.determine_event(:get, '/asdfsasd')
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not execute event if halted" do
|
|
||||||
Sinatra::Event.before_filters << lambda { throw :halt, 'whoa!' }
|
|
||||||
event = Sinatra::Event.new(:get, '/') do
|
|
||||||
foo
|
|
||||||
end
|
|
||||||
event.expects(:foo).never
|
|
||||||
get_it('/').should.equal 'whoa!'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
context "Filter" do
|
|
||||||
|
|
||||||
specify "befores can be in front" do
|
|
||||||
before_attend :bar
|
|
||||||
before_attend :foo, :infront => true
|
|
||||||
|
|
||||||
Sinatra::Event.before_filters.should.equal [:foo, :bar]
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "afters can be in front" do
|
|
||||||
after_attend :bar
|
|
||||||
after_attend :foo, :infront => true
|
|
||||||
|
|
||||||
Sinatra::Event.after_filters.should.equal [:foo, :bar]
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
|
|
||||||
context "Haml" do
|
|
||||||
|
|
||||||
specify "does layouts" do
|
|
||||||
layout do
|
|
||||||
'%h1== Hello #{yield}'
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/" do
|
|
||||||
haml 'Ben'
|
|
||||||
end
|
|
||||||
|
|
||||||
get_it '/'
|
|
||||||
|
|
||||||
body.should.equal "<h1>Hello Ben</h1>\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
class Sinatra::EventContext # :nodoc:
|
|
||||||
|
|
||||||
def render_foo(template)
|
|
||||||
require 'erb'
|
|
||||||
ERB.new(template).result(binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Renderer" do
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@context = Sinatra::EventContext.new(stub())
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should render render a tempalate" do
|
|
||||||
@context.render('foo', :foo).should.equal 'foo'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should render with a layout if given" do
|
|
||||||
result = @context.render('content', :foo) do
|
|
||||||
'X <%= yield %> X'
|
|
||||||
end
|
|
||||||
|
|
||||||
result.should.equal 'X content X'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should render default layout if it exists and layout if no layout name given" do
|
|
||||||
Sinatra::Renderer::Layouts[:layout] = 'X <%= yield %> Y'
|
|
||||||
@context.render('foo', :foo).should.equal 'X foo Y'
|
|
||||||
|
|
||||||
Sinatra::Renderer::Layouts[:foo] = 'Foo <%= yield %> Layout'
|
|
||||||
@context.render('bar', :foo, :layout => :foo).should.equal 'Foo bar Layout'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should read template from a file if exists" do
|
|
||||||
File.expects(:read).with('views/bar.foo').returns('foo content')
|
|
||||||
@context.render(:bar, :foo).should.equal 'foo content'
|
|
||||||
|
|
||||||
File.expects(:read).with('views2/bar.foo').returns('foo content')
|
|
||||||
@context.render(:bar, :foo, :views_directory => 'views2').should.equal 'foo content'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
describe "Rack::Request" do
|
|
||||||
it "should return PUT and DELETE based on _method param" do
|
|
||||||
env = {'REQUEST_METHOD' => 'POST', 'rack.input' => StringIO.new('_method=DELETE')}
|
|
||||||
Rack::Request.new(env).request_method.should.equal 'DELETE'
|
|
||||||
|
|
||||||
env = {'REQUEST_METHOD' => 'POST', 'rack.input' => StringIO.new('_method=PUT')}
|
|
||||||
Rack::Request.new(env).request_method.should.equal 'PUT'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow faking" do
|
|
||||||
env = {'REQUEST_METHOD' => 'POST', 'rack.input' => StringIO.new('_method=GET')}
|
|
||||||
Rack::Request.new(env).request_method.should.equal 'POST'
|
|
||||||
|
|
||||||
env = {'REQUEST_METHOD' => 'GET', 'rack.input' => StringIO.new('_method=POST')}
|
|
||||||
Rack::Request.new(env).request_method.should.equal 'GET'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
describe "Route" do
|
|
||||||
it "gives :format for free" do
|
|
||||||
route = Sinatra::Route.new('/foo/:test/:blake')
|
|
||||||
|
|
||||||
route.recognize('/foo/bar/baz').should.equal true
|
|
||||||
route.params.should.equal :test => 'bar', :blake => 'baz', :format => 'html'
|
|
||||||
|
|
||||||
route.recognize('/foo/bar/baz.xml').should.equal true
|
|
||||||
route.params.should.equal :test => 'bar', :blake => 'baz', :format => 'xml'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't auto add :format for routes with explicit formats" do
|
|
||||||
route = Sinatra::Route.new('/foo/:test.xml')
|
|
||||||
route.recognize('/foo/bar').should.equal false
|
|
||||||
route.recognize('/foo/bar.xml').should.equal true
|
|
||||||
route.params.should.equal :test => 'bar', :format => 'xml'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
You found foo!
|
|
|
@ -1,44 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
context "StaticEvent" do
|
|
||||||
|
|
||||||
specify "recognizes paths prefixed with it's path" do
|
|
||||||
File.expects(:exists?).with('/x/bar/test.jpg').returns(true)
|
|
||||||
File.expects(:file?).with('/x/bar/test.jpg').returns(true)
|
|
||||||
Sinatra::StaticEvent.new('/foo', '/x/bar').recognize('/foo/test.jpg').should.equal true
|
|
||||||
|
|
||||||
File.expects(:exists?).with('/x/bar/test.jpg').returns(false)
|
|
||||||
Sinatra::StaticEvent.new('/foo', '/x/bar').recognize('/foo/test.jpg').should.equal false
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "sets headers for file type" do
|
|
||||||
File.expects(:open).with('/x/bar/test.jpg', 'rb').returns(StringIO.new)
|
|
||||||
File.expects(:size).with('/x/bar/test.jpg').returns(255)
|
|
||||||
result = Sinatra::StaticEvent.new('/foo', '/x/bar').attend(stub(:path_info => '/foo/test.jpg'))
|
|
||||||
result.headers.should.equal 'Content-Type' => 'image/jpeg', 'Content-Length' => '255'
|
|
||||||
result.body.each { }
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "makes sure it is a file and not a directory" do
|
|
||||||
File.expects(:exists?).with('/x/bar').returns(true)
|
|
||||||
File.expects(:file?).with('/x/bar').returns(false)
|
|
||||||
Sinatra::StaticEvent.new('/foo', '/x').recognize('/foo/bar').should.equal false
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
context "StaticEvent (In full context)" do
|
|
||||||
|
|
||||||
specify "should serve a static file" do
|
|
||||||
e = static '/x', root = File.dirname(__FILE__) + '/static_files'
|
|
||||||
|
|
||||||
File.read(e.physical_path_for('/x/foo.txt')).should.equal 'You found foo!'
|
|
||||||
|
|
||||||
get_it '/x/foo.txt'
|
|
||||||
|
|
||||||
status.should.equal 200
|
|
||||||
body.should.equal 'You found foo!'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,16 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../helper'
|
|
||||||
|
|
||||||
describe "Route" do
|
|
||||||
|
|
||||||
it "should recognize params in urls" do
|
|
||||||
route = Sinatra::Route.new('/foo/:test/:blake')
|
|
||||||
|
|
||||||
route.recognize('/foo/bar/baz').should.equal true
|
|
||||||
route.params.should.equal :test => 'bar', :blake => 'baz', :format => 'html'
|
|
||||||
|
|
||||||
route.recognize('/foo/bar/baz.xml').should.equal true
|
|
||||||
route.params.should.equal :test => 'bar', :blake => 'baz', :format => 'xml'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
3
vendor/erb/init.rb
vendored
3
vendor/erb/init.rb
vendored
|
@ -1,3 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/lib/erb'
|
|
||||||
|
|
||||||
Sinatra::EventContext.send(:include, Sinatra::Erb::EventContext)
|
|
41
vendor/erb/lib/erb.rb
vendored
41
vendor/erb/lib/erb.rb
vendored
|
@ -1,41 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
module Erb # :nodoc:
|
|
||||||
|
|
||||||
module EventContext
|
|
||||||
|
|
||||||
# Renders raw erb in within the events context.
|
|
||||||
#
|
|
||||||
# This can be use to if you already have the template on hand and don't
|
|
||||||
# need a layout. This is speedier than using erb
|
|
||||||
#
|
|
||||||
def render_erb(content)
|
|
||||||
require 'erb'
|
|
||||||
body ERB.new(content).result(binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Renders erb within an event.
|
|
||||||
#
|
|
||||||
# Inline example:
|
|
||||||
#
|
|
||||||
# get '/foo' do
|
|
||||||
# erb 'The time is <%= Time.now %>'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Template example:
|
|
||||||
#
|
|
||||||
# get '/foo' do
|
|
||||||
# erb :foo #=> reads and renders view/foo.erb
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# For options, see Sinatra::Renderer
|
|
||||||
#
|
|
||||||
# See also: Sinatra::Renderer
|
|
||||||
def erb(template, options = {}, &layout)
|
|
||||||
render(template, :erb, options, &layout)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
3
vendor/haml/init.rb
vendored
3
vendor/haml/init.rb
vendored
|
@ -1,3 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/lib/haml'
|
|
||||||
|
|
||||||
Sinatra::EventContext.send(:include, Sinatra::Haml::EventContext)
|
|
41
vendor/haml/lib/haml.rb
vendored
41
vendor/haml/lib/haml.rb
vendored
|
@ -1,41 +0,0 @@
|
||||||
module Sinatra
|
|
||||||
|
|
||||||
module Haml # :nodoc:
|
|
||||||
|
|
||||||
module EventContext
|
|
||||||
|
|
||||||
# Renders raw haml in within the events context.
|
|
||||||
#
|
|
||||||
# This can be use to if you already have the template on hand and don't
|
|
||||||
# need a layout. This is speedier than using haml
|
|
||||||
#
|
|
||||||
def render_haml(template, &block)
|
|
||||||
require 'haml'
|
|
||||||
body ::Haml::Engine.new(template).render(self, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Renders Haml within an event.
|
|
||||||
#
|
|
||||||
# Inline example:
|
|
||||||
#
|
|
||||||
# get '/foo' do
|
|
||||||
# haml '== The time is #{Time.now}'
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Template example:
|
|
||||||
#
|
|
||||||
# get '/foo' do
|
|
||||||
# haml :foo #=> reads and renders view/foo.haml
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# For options, see Sinatra::Renderer
|
|
||||||
#
|
|
||||||
# See also: Sinatra::Renderer
|
|
||||||
def haml(template, options = {}, &layout)
|
|
||||||
render(template, :haml, options, &layout)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
Loading…
Reference in a new issue