mirror of
https://github.com/sinatra/sinatra
synced 2023-03-27 23:18:01 -04:00
this is it
This commit is contained in:
commit
72be291da2
17 changed files with 477 additions and 0 deletions
20
examples/hello/test.rb
Normal file
20
examples/hello/test.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
$LOAD_PATH.unshift '../../lib/'
|
||||
require 'sinatra'
|
||||
|
||||
get '/' do
|
||||
body <<-HTML
|
||||
<form method="POST"><input type="text" name="name"/><input type="submit"></form>
|
||||
HTML
|
||||
end
|
||||
|
||||
post '/' do
|
||||
body "You entered #{params[:name]}"
|
||||
end
|
||||
|
||||
get '/erb' do
|
||||
erb :index
|
||||
end
|
||||
|
||||
get '/test' do
|
||||
erb "Hello <%= params[:name] %>"
|
||||
end
|
1
examples/hello/views/index.erb
Normal file
1
examples/hello/views/index.erb
Normal file
|
@ -0,0 +1 @@
|
|||
<%= 1 + 3 %>
|
1
files/default_index.erb
Normal file
1
files/default_index.erb
Normal file
|
@ -0,0 +1 @@
|
|||
Default Index!!!!!!!
|
52
files/not_found.erb
Normal file
52
files/not_found.erb
Normal file
|
@ -0,0 +1,52 @@
|
|||
<!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>Add this to your lyrics:</p>
|
||||
<pre><%= request.request_method.downcase %> '<%= request.path_info %>' do
|
||||
html "Replace this with your code."
|
||||
end</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
36
lib/sinatra.rb
Normal file
36
lib/sinatra.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
%w(rubygems rack).each do |library|
|
||||
begin
|
||||
require library
|
||||
rescue LoadError
|
||||
raise "== Sinatra cannot run without #{library} installed"
|
||||
end
|
||||
end
|
||||
|
||||
require File.dirname(__FILE__) + '/sinatra/core_ext/class'
|
||||
require File.dirname(__FILE__) + '/sinatra/core_ext/hash'
|
||||
|
||||
require File.dirname(__FILE__) + '/sinatra/logger'
|
||||
require File.dirname(__FILE__) + '/sinatra/event'
|
||||
require File.dirname(__FILE__) + '/sinatra/dispatcher'
|
||||
require File.dirname(__FILE__) + '/sinatra/server'
|
||||
require File.dirname(__FILE__) + '/sinatra/dsl'
|
||||
|
||||
SINATRA_LOGGER = Sinatra::Logger.new(STDOUT)
|
||||
|
||||
def set_logger(logger = SINATRA_LOGGER)
|
||||
[Sinatra::Server, Sinatra::EventContext, Sinatra::Event].each do |klass|
|
||||
klass.logger = logger
|
||||
end
|
||||
end
|
||||
|
||||
set_logger
|
||||
|
||||
SINATRA_ROOT = File.dirname(__FILE__) + '/..'
|
||||
|
||||
Dir.glob(SINATRA_ROOT + '/vendor/*/init.rb').each do |plugin|
|
||||
require plugin
|
||||
end
|
||||
|
||||
at_exit do
|
||||
Sinatra::Server.new.start unless Sinatra::Server.running
|
||||
end
|
48
lib/sinatra/core_ext/class.rb
Normal file
48
lib/sinatra/core_ext/class.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
# 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
|
7
lib/sinatra/core_ext/hash.rb
Normal file
7
lib/sinatra/core_ext/hash.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class Hash
|
||||
|
||||
def symbolize_keys
|
||||
self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
|
||||
end
|
||||
|
||||
end
|
42
lib/sinatra/dispatcher.rb
Normal file
42
lib/sinatra/dispatcher.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
module Sinatra
|
||||
|
||||
DEFAULT_HEADERS = { 'Content-Type' => 'text/html' }
|
||||
|
||||
class Dispatcher
|
||||
|
||||
def headers
|
||||
DEFAULT_HEADERS
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@request = Rack::Request.new(env)
|
||||
|
||||
event = EventManager.events.detect(lambda { not_found }) do |e|
|
||||
e.path == @request.path_info && e.verb == @request.request_method.downcase.intern
|
||||
end
|
||||
|
||||
result = event.attend(@request)
|
||||
|
||||
[result.status, headers.merge(result.headers), result.body]
|
||||
rescue => e
|
||||
puts "#{e.message}:\n\t#{e.backtrace.join("\n\t")}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def not_found
|
||||
Event.new(:get, nil) do
|
||||
status 404
|
||||
views_dir SINATRA_ROOT + '/files'
|
||||
|
||||
if request.path_info == '/'
|
||||
erb :default_index
|
||||
else
|
||||
erb :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
11
lib/sinatra/dsl.rb
Normal file
11
lib/sinatra/dsl.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Kernel
|
||||
|
||||
%w( get post put delete ).each do |verb|
|
||||
eval <<-end_eval
|
||||
def #{verb}(path, &block)
|
||||
Sinatra::Event.new(:#{verb}, path, &block)
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
|
||||
end
|
94
lib/sinatra/event.rb
Normal file
94
lib/sinatra/event.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
module Sinatra
|
||||
|
||||
module EventManager
|
||||
|
||||
extend self
|
||||
|
||||
def events
|
||||
@events || []
|
||||
end
|
||||
|
||||
def register_event(event)
|
||||
(@events ||= []) << event
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class EventContext
|
||||
|
||||
cattr_accessor :logger
|
||||
|
||||
attr_reader :request
|
||||
|
||||
def initialize(request)
|
||||
@request = request
|
||||
@headers = {}
|
||||
end
|
||||
|
||||
def status(value = nil)
|
||||
@status = value if value
|
||||
@status || 200
|
||||
end
|
||||
|
||||
def body(value = nil)
|
||||
@body = value if value
|
||||
@body || ''
|
||||
end
|
||||
|
||||
# This allows for:
|
||||
# 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)
|
||||
@headers.merge!(value) if value
|
||||
@headers
|
||||
end
|
||||
alias :header :headers
|
||||
|
||||
def params
|
||||
@params ||= @request.params.symbolize_keys
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Event
|
||||
|
||||
cattr_accessor :logger
|
||||
|
||||
attr_reader :path, :verb
|
||||
|
||||
def initialize(verb, path, &block)
|
||||
@verb = verb
|
||||
@path = path
|
||||
@block = block
|
||||
EventManager.register_event(self)
|
||||
end
|
||||
|
||||
def attend(request)
|
||||
begin
|
||||
context = EventContext.new(request)
|
||||
context.instance_eval(&@block) if @block
|
||||
log_event(request, context, nil)
|
||||
context
|
||||
rescue => e
|
||||
context.status 500
|
||||
log_event(request, context, e)
|
||||
context
|
||||
end
|
||||
end
|
||||
alias :call :attend
|
||||
|
||||
private
|
||||
|
||||
def log_event(request, context, e)
|
||||
logger.info "#{request.request_method} #{request.path_info} | Status: #{context.status} | Params: #{context.params.inspect}"
|
||||
logger.exception(e) if e
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
21
lib/sinatra/logger.rb
Normal file
21
lib/sinatra/logger.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
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
|
||||
end
|
||||
end
|
||||
|
||||
def exception(e)
|
||||
error "#{e.message}:\n\t#{e.backtrace.join("\n\t")}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
26
lib/sinatra/server.rb
Normal file
26
lib/sinatra/server.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module Sinatra
|
||||
|
||||
class Server
|
||||
|
||||
cattr_accessor :logger
|
||||
cattr_accessor :running
|
||||
|
||||
def start
|
||||
begin
|
||||
Rack::Handler::Mongrel.run(Sinatra::Dispatcher.new, :Port => 4567) do |server|
|
||||
logger.info "== Sinatra has taken the stage on port #{server.port}!"
|
||||
trap("INT") do
|
||||
server.stop
|
||||
self.class.running = false
|
||||
logger.info "\n== Sinatra has ended his set (crowd applauds)"
|
||||
end
|
||||
end
|
||||
self.class.running = true
|
||||
rescue => e
|
||||
logger.exception e
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
41
test/helper.rb
Normal file
41
test/helper.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
require File.dirname(__FILE__) + '/../lib/sinatra'
|
||||
|
||||
%w(mocha test/spec).each do |library|
|
||||
begin
|
||||
require library
|
||||
rescue
|
||||
STDERR.puts "== Sinatra's tests need #{library} to run."
|
||||
end
|
||||
end
|
||||
|
||||
Sinatra::Server.running = true
|
||||
|
||||
class Test::Unit::TestCase
|
||||
|
||||
def get_it(path)
|
||||
request = Rack::MockRequest.new(Sinatra::Dispatcher.new)
|
||||
@response = request.get path
|
||||
end
|
||||
|
||||
def post_it(path)
|
||||
request = Rack::MockRequest.new(Sinatra::Dispatcher.new)
|
||||
@response = request.post path
|
||||
end
|
||||
|
||||
def response
|
||||
@response
|
||||
end
|
||||
|
||||
def status
|
||||
@response.status
|
||||
end
|
||||
|
||||
def text
|
||||
@response.body
|
||||
end
|
||||
|
||||
def headers
|
||||
@response.headers
|
||||
end
|
||||
|
||||
end
|
30
test/sinatra/dispatcher_test.rb
Normal file
30
test/sinatra/dispatcher_test.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
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 "/test"
|
||||
|
||||
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
|
||||
|
||||
end
|
17
test/sinatra/event_test.rb
Normal file
17
test/sinatra/event_test.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../helper'
|
||||
|
||||
describe "Event" do
|
||||
|
||||
it "should return 500 if exception thrown" do
|
||||
set_logger stub_everything
|
||||
|
||||
event = Sinatra::Event.new(:get, nil) do
|
||||
raise 'whaaaa!'
|
||||
end
|
||||
|
||||
result = event.attend(stub_everything)
|
||||
|
||||
result.status.should.equal 500
|
||||
end
|
||||
|
||||
end
|
3
vendor/erb/init.rb
vendored
Normal file
3
vendor/erb/init.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
require File.dirname(__FILE__) + '/lib/erb'
|
||||
|
||||
Sinatra::EventContext.send(:include, Sinatra::Erb::InstanceMethods)
|
27
vendor/erb/lib/erb.rb
vendored
Normal file
27
vendor/erb/lib/erb.rb
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
require 'erb'
|
||||
|
||||
module Sinatra
|
||||
|
||||
module Erb
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def erb(content)
|
||||
s = if content.is_a?(Symbol)
|
||||
open("%s/%s.erb" % [views_dir, content]).read
|
||||
else
|
||||
content
|
||||
end
|
||||
body ERB.new(s).result(binding)
|
||||
end
|
||||
|
||||
def views_dir(value = nil)
|
||||
@views_dir = value if value
|
||||
@views_dir || File.dirname($0) + '/views'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue