1
0
Fork 0
mirror of https://github.com/sinatra/sinatra synced 2023-03-27 23:18:01 -04:00
This commit is contained in:
Blake Mizerany 2007-10-04 15:40:12 -07:00
parent 756b8e5de9
commit 85e1a4c944
15 changed files with 383 additions and 104 deletions

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
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.

View file

@ -1,7 +1,4 @@
CHANGELOG
RakeFile
README
x.rb
examples/hello/hello.rb
examples/hello/views/hello.erb
examples/todo/todo.rb
@ -9,8 +6,15 @@ files/default_index.erb
files/error.erb
files/logo.png
files/not_found.erb
lib/sinatra.rb
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
@ -19,29 +23,28 @@ lib/sinatra/irb.rb
lib/sinatra/loader.rb
lib/sinatra/logger.rb
lib/sinatra/options.rb
lib/sinatra/pretty_url.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/context/renderer.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.rb
LICENSE
RakeFile
README
sinatra.gemspec
site/index.htm
site/index.html
site/logo.png
test/helper.rb
test/sinatra/dispatcher_test.rb
test/sinatra/event_test.rb
test/sinatra/pretty_url_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
test/sinatra/static_files/foo.txt
vendor/erb/init.rb
vendor/erb/lib/erb.rb
vendor/haml/init.rb

74
README
View file

@ -1,43 +1,57 @@
Copyright (c) <year> <copyright holders>
Sinatra (C) 2007 By 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:
= Classy web-development dressed in a DSL
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
== Install!
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.
sudo gem install sinatra -y
== Use!
Using Sinatra is EASY!
I'm going to move quick. I'll let you drool at your own pace.
WARNING: Keep a fresh pair of underwear nearby. You may need them when you see this.
- Create a file called lyrics.rb (or any name you like)
Get running without a file!
- Add
require 'rubygems'
require 'sinatra'
ruby -e 'require "sinatra"' # HIT http://localhost:4567/ and BAM!
- Run (yes, with just ruby)
% ruby lyrics.rb
== Sinata has taken the stage on port 4567!
now create a file called test.rb (or whatever you fancy) and enter this:
- Take a moment and view the default page http://localhost:4567. Go ahead and bask in it's glory.
require 'sinatra'
* 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
get '/' do
body 'Hello World!'
end
- Modify lyrics.rb by adding:
now run 'ruby test.rb' and refresh your browser
get '/' do
'Hello World'
end
Oh yeah!
- Refresh (no need to restart Sinatra):
http://localhost:4567
- Modify again (then refresh):
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
- Homework:
Use the Sinatra::Erb::EventContext or Sinatra::Haml::EventContext to do the same. Do them inline and as template files.

View file

@ -20,6 +20,7 @@ begin
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')
end
rescue LoadError

View file

@ -9,22 +9,33 @@ module Sinatra
include Sinatra::Renderer
def initialize(request)
def initialize(request) #:nodoc:
@request = request
@headers = {}
end
# Sets or returns the status
def status(value = nil)
@status = value if value
@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)
@body = value if value
@body = block.call if block
@body
end
# Renders an exception to +body+ and sets status to 500
def error(value = nil)
if value
status 500
@ -34,12 +45,14 @@ module Sinatra
@error
end
# This allows for:
# header 'Content-Type' => 'text/html'
# header 'Foo' => 'Bar'
# Sets or returns response headers
#
# *Usage*
# header 'Content-Type' => 'text/html'
# header 'Foo' => 'Bar'
# or
# headers 'Content-Type' => 'text/html',
# 'Foo' => 'Bar'
# headers 'Content-Type' => 'text/html',
# 'Foo' => 'Bar'
#
# Whatever blows your hair back
def headers(value = nil)
@ -48,21 +61,24 @@ module Sinatra
end
alias :header :headers
# Returns a Hash of session data. Keys are symbolized
def session
request.env['rack.session']
end
# 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
def log_event #:nodoc:
logger.info "#{request.request_method} #{request.path_info} | Status: #{status} | Params: #{params.inspect}"
logger.exception(error) if error
end

View file

@ -1,7 +1,12 @@
Layouts = Hash.new
Layouts = Hash.new # :nodoc:
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
DEFAULT_OPTIONS = {
@ -9,6 +14,38 @@ module Sinatra
: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)

View file

@ -1,3 +1,6 @@
# 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

View file

@ -1,42 +1,163 @@
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
module Sinatra
def after_attend(filter_name = nil, &block)
Sinatra::Event.after_attend(filter_name, &block)
end
module Dsl
def helpers(&block)
Sinatra::EventContext.class_eval(&block)
end
def static(path, root)
Sinatra::StaticEvent.new(path, root)
end
%w(test development production).each do |env|
module_eval <<-end_eval
def #{env}
yield if Sinatra::Options.environment == :#{env}
end
end_eval
end
def layout(name = :layout, options = {})
Layouts[name] = unless block_given?
File.read("%s/%s" % [options[:views_directory] || 'views', name])
else
yield
# 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
# Example:
# after_attend do
# logger.debug "After event attend!"
# end
def after_attend(filter_name = nil, &block)
Sinatra::Event.after_attend(filter_name, &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 development mode (Used for configuration)
def development
yield if Sinatra::Options.environment == :development
end
# Execute block if in production mode (Used for configuration)
def production
yield if Sinatra::Options.environment == :production
end
# Execute block if in test mode (Used for configuration)
def test
yield if Sinatra::Options.environment == :test
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 = {})
Layouts[name] = unless block_given?
File.read("%s/%s" % [options[:views_directory] || 'views', name])
else
yield
end
end
# Turn sessions <tt>:on</tt> or <tt>:off</tt>
#
# NOTE: There is currently no way to turn it on or off per Event... patches anyone?)
def sessions(on_off)
Sinatra::Session::Cookie.use = on_off
end
end
def sessions(on_off)
Sinatra::Session::Cookie.use = on_off
end
end
include Sinatra::Dsl

View file

@ -1,6 +1,6 @@
module Sinatra
module EventManager
module EventManager # :nodoc:
extend self
def reset!
@ -39,7 +39,7 @@ module Sinatra
end
class Event
class Event # :nodoc:
cattr_accessor :logger
cattr_accessor :after_filters
@ -88,7 +88,7 @@ module Sinatra
end
class StaticEvent < Event
class StaticEvent < Event # :nodoc:
def initialize(path, root, register = true)
@root = root

View file

@ -1,17 +1,24 @@
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!
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|
@ -24,7 +31,7 @@ module Sinatra
end
alias :mate :show!
def result_info
def result_info #:nodoc:
info = <<-end_info
# Status: #{status}
# Headers: #{headers.inspect}

View file

@ -1,6 +1,6 @@
module Rack
module Rack #:nodoc:
class Request
class Request #:nodoc:
def request_method
if @env['REQUEST_METHOD'] == 'POST' && %w(PUT DELETE).include?(params['_method'])

View file

@ -2,8 +2,19 @@ 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 TestMethods
# 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 = {})

View file

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../helper'
class Sinatra::EventContext
class Sinatra::EventContext # :nodoc:
def render_foo(template)
require 'erb'

24
vendor/erb/lib/erb.rb vendored
View file

@ -1,14 +1,36 @@
module Sinatra
module Erb
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

View file

@ -1,14 +1,36 @@
module Sinatra
module Haml
module Haml # :nodoc:
module EventContext
def render_haml(content)
# 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)
require 'haml'
body ::Haml::Engine.new(content).render(self)
body ::Haml::Engine.new(template).render(self)
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