sinatra-contrib-1.4.7/ 0000755 0000041 0000041 00000000000 12706205017 014652 5 ustar www-data www-data sinatra-contrib-1.4.7/Rakefile 0000644 0000041 0000041 00000004022 12706205017 016315 0 ustar www-data www-data $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
require 'open-uri'
require 'yaml'
require 'sinatra/contrib/version'
desc "run specs"
task(:spec) { ruby '-S rspec spec -cw' }
task(:test => :spec)
task(:default => :spec)
namespace :doc do
task :readmes do
Dir.glob 'lib/sinatra/*.rb' do |file|
excluded_files = %w[lib/sinatra/contrib.rb lib/sinatra/capture.rb lib/sinatra/engine_tracking.rb]
next if excluded_files.include?(file)
doc = File.read(file)[/^module Sinatra(\n)+( #[^\n]*\n)*/m].scan(/^ *#(?!#) ?(.*)\n/).join("\n")
file = "doc/#{file[4..-4].tr("/_", "-")}.rdoc"
Dir.mkdir "doc" unless File.directory? "doc"
puts "writing #{file}"
File.open(file, "w") { |f| f << doc }
end
end
task :all => [:readmes]
end
desc "generate documentation"
task :doc => 'doc:all'
desc "generate gemspec"
task 'sinatra-contrib.gemspec' do
content = File.read 'sinatra-contrib.gemspec'
fields = {
:authors => `git shortlog -sn`.scan(/[^\d\s].*/),
:email => `git shortlog -sne`.scan(/[^<]+@[^>]+/),
:files => `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ }
}
fields.each do |field, values|
updated = " s.#{field} = ["
updated << values.map { |v| "\n %p" % v }.join(',')
updated << "\n ]"
content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated)
end
File.open('sinatra-contrib.gemspec', 'w') { |f| f << content }
end
task :gemspec => 'sinatra-contrib.gemspec'
task :release => :gemspec do
sh <<-SH
rm -Rf sinatra-contrib*.gem &&
gem build sinatra-contrib.gemspec &&
gem install sinatra-contrib*.gem --local &&
gem push sinatra-contrib*.gem &&
git commit --allow-empty -a -m '#{Sinatra::Contrib::VERSION} release' &&
git tag -s v#{Sinatra::Contrib::VERSION} -m '#{Sinatra::Contrib::VERSION} release' &&
git tag -s #{Sinatra::Contrib::VERSION} -m '#{Sinatra::Contrib::VERSION} release' &&
git push && (git push origin master || true) &&
git push --tags && (git push origin --tags || true)
SH
end
sinatra-contrib-1.4.7/ideas.md 0000644 0000041 0000041 00000001750 12706205017 016264 0 ustar www-data www-data * Extension that does something like this:
def build(*)
if settings.memcached?
use Rack::Cache, :backend => :memcached
use Rack::Session::Memcached
# ...
end
super
end
* `sinatra-smart-cache`: update cache header only if arguments are more
restrictive than curent value, set caching headers that way for most helper
methods (i.e. `sass` or `send_file`)
* Some verbose logging extension: Log what filters, routes, error handlers,
templates, and so on is used.
* Form helpers, with forms as first class objects that accepts hashes or
something, so the form meta data can also be used to expose a JSON API or
similar, possibly defining routes (like "Sinatra's Hat"), strictly using
the ActiveModel API.
* Extend `sinatra-content-for` to support Liquid, Radius, Markaby, Nokogiri and
Builder. At least the first two probably involve patching Tilt.
* Rewrite of `sinatra-compass`?
* Helpers for HTML escaping and such. sinatra-contrib-1.4.7/spec/ 0000755 0000041 0000041 00000000000 12706205017 015604 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/decompile_spec.rb 0000644 0000041 0000041 00000002403 12706205017 021103 0 ustar www-data www-data require 'spec_helper'
RSpec::Matchers.define :decompile do |path|
match do |app|
@compiled, @keys = app.send :compile, path
@decompiled = app.decompile(@compiled, @keys)
@decompiled.should == path
end
failure_message_for_should do |app|
values = [app, @compiled, @keys, path, @decompiled].map(&:inspect)
"expected %s to decompile %s with %s to %s, but was %s" % values
end
end
describe Sinatra::Decompile do
subject { Sinatra::Application }
it { should decompile("") }
it { should decompile("/") }
it { should decompile("/?") }
it { should decompile("/foo") }
it { should decompile("/:name") }
it { should decompile("/:name?") }
it { should decompile("/:foo/:bar") }
it { should decompile("/page/:id/edit") }
it { should decompile("/hello/*") }
it { should decompile("/*/foo/*") }
it { should decompile("*") }
it { should decompile(":name.:format") }
it { should decompile("a b") }
it { should decompile("a+b") }
it { should decompile(/./) }
it { should decompile(/f(oo)/) }
it { should decompile(/ba+r/) }
it 'just returns strings' do
subject.decompile('/foo').should == '/foo'
end
it 'just decompile simple regexps without keys' do
subject.decompile(%r{/foo}).should == '/foo'
end
end
sinatra-contrib-1.4.7/spec/link_header_spec.rb 0000644 0000041 0000041 00000004401 12706205017 021407 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::LinkHeader do
before do
mock_app do
helpers Sinatra::LinkHeader
before('/') { link 'something', :rel => 'from-filter', :foo => :bar }
get '/' do
link :something, 'booyah'
end
get '/style' do
stylesheet '/style.css'
end
get '/prefetch' do
prefetch '/foo'
end
get '/link_headers' do
response['Link'] = " ;bar=\"baz\""
stylesheet '/style.css'
prefetch '/foo'
link_headers
end
end
end
describe :link do
it "sets link headers" do
get '/'
headers['Link'].lines.should include('; rel="something"')
end
it "returns link html tags" do
get '/'
body.should == ''
end
it "takes an options hash" do
get '/'
elements = ["", "foo=\"bar\"", "rel=\"from-filter\""]
headers['Link'].lines.first.strip.split('; ').sort.should == elements
end
end
describe :stylesheet do
it 'sets link headers' do
get '/style'
headers['Link'].should match(%r{^;})
end
it 'sets type to text/css' do
get '/style'
headers['Link'].should include('type="text/css"')
end
it 'sets rel to stylesheet' do
get '/style'
headers['Link'].should include('rel="stylesheet"')
end
it 'returns html tag' do
get '/style'
body.should match(%r{^;})
end
it 'sets rel to prefetch' do
get '/prefetch'
headers['Link'].should include('rel="prefetch"')
end
it 'returns html tag' do
get '/prefetch'
body.should == ''
end
end
describe :link_headers do
it 'generates html for all link headers' do
get '/link_headers'
body.should include('')
body.should include('')
end
end
end
sinatra-contrib-1.4.7/spec/spec_helper.rb 0000644 0000041 0000041 00000000226 12706205017 020422 0 ustar www-data www-data ENV['RACK_ENV'] = 'test'
require 'sinatra/contrib'
RSpec.configure do |config|
config.expect_with :rspec
config.include Sinatra::TestHelpers
end
sinatra-contrib-1.4.7/spec/namespace/ 0000755 0000041 0000041 00000000000 12706205017 017540 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/namespace/nested/ 0000755 0000041 0000041 00000000000 12706205017 021022 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/namespace/nested/foo.erb 0000644 0000041 0000041 00000000003 12706205017 022270 0 ustar www-data www-data ho
sinatra-contrib-1.4.7/spec/namespace/foo.erb 0000644 0000041 0000041 00000000003 12706205017 021006 0 ustar www-data www-data hi
sinatra-contrib-1.4.7/spec/multi_route_spec.rb 0000644 0000041 0000041 00000002310 12706205017 021507 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::MultiRoute do
it 'does not break normal routing' do
mock_app do
register Sinatra::MultiRoute
get('/') { 'normal' }
end
get('/').should be_ok
body.should be == 'normal'
end
it 'supports multiple routes' do
mock_app do
register Sinatra::MultiRoute
get('/foo', '/bar') { 'paths' }
end
get('/foo').should be_ok
body.should be == 'paths'
get('/bar').should be_ok
body.should be == 'paths'
end
it 'triggers conditions' do
count = 0
mock_app do
register Sinatra::MultiRoute
set(:some_condition) { |_| count += 1 }
get('/foo', '/bar', :some_condition => true) { 'paths' }
end
count.should be == 4
end
it 'supports multiple verbs' do
mock_app do
register Sinatra::MultiRoute
route('PUT', 'POST', '/') { 'verb' }
end
post('/').should be_ok
body.should be == 'verb'
put('/').should be_ok
body.should be == 'verb'
end
it 'takes symbols as verbs' do
mock_app do
register Sinatra::MultiRoute
route(:get, '/baz') { 'symbol as verb' }
end
get('/baz').should be_ok
body.should be == 'symbol as verb'
end
end
sinatra-contrib-1.4.7/spec/config_file_spec.rb 0000644 0000041 0000041 00000003475 12706205017 021420 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::ConfigFile do
def config_file(*args, &block)
mock_app do
register Sinatra::ConfigFile
set :root, File.expand_path('../config_file', __FILE__)
instance_eval(&block) if block
config_file(*args)
end
end
it 'should set options from a simple config_file' do
config_file 'key_value.yml'
settings.foo.should == 'bar'
settings.something.should == 42
end
it 'should create indifferent hashes' do
config_file 'key_value.yml'
settings.nested['a'].should == 1
settings.nested[:a].should == 1
end
it 'should render options in ERB tags' do
config_file 'key_value.yml.erb'
settings.foo.should == "bar"
settings.something.should == 42
settings.nested['a'].should == 1
settings.nested[:a].should == 1
settings.nested['b'].should == 2
settings.nested[:b].should == 2
end
it 'should recognize env specific settings per file' do
config_file 'with_envs.yml'
settings.foo.should == 'test'
end
it 'should recognize env specific settings per setting' do
config_file 'with_nested_envs.yml'
settings.database[:adapter].should == 'sqlite'
end
it 'should not set present values to nil if the current env is missing' do
# first let's check the test is actually working properly
config_file('missing_env.yml') { set :foo => 42, :environment => :production }
settings.foo.should == 10
# now test it
config_file('missing_env.yml') { set :foo => 42, :environment => :test }
settings.foo.should == 42
end
it 'should prioritize settings in latter files' do
# first let's check the test is actually working properly
config_file 'key_value.yml'
settings.foo.should == 'bar'
# now test it
config_file 'key_value_override.yml'
settings.foo.should == 'foo'
end
end
sinatra-contrib-1.4.7/spec/streaming_spec.rb 0000644 0000041 0000041 00000022121 12706205017 021132 0 ustar www-data www-data require 'backports'
require 'spec_helper'
describe Sinatra::Streaming do
def stream(&block)
rack_middleware = @use
out = nil
mock_app do
rack_middleware.each { |args| use(*args) }
helpers Sinatra::Streaming
get('/') { out = stream(&block) }
end
get('/')
out
end
def use(*args)
@use << args
end
before do
@use = []
end
context 'stream test helper' do
it 'runs the given block' do
ran = false
stream { ran = true }
ran.should be true
end
it 'returns the stream object' do
out = stream { }
out.should be_a(Sinatra::Helpers::Stream)
end
it 'fires a request against that stream' do
stream { |out| out << "Hello World!" }
last_response.should be_ok
body.should be == "Hello World!"
end
it 'passes the stream object to the block' do
passed = nil
returned = stream { |out| passed = out }
passed.should be == returned
end
end
context Sinatra::Streaming::Stream do
it 'should extend the stream object' do
out = stream { }
out.should be_a(Sinatra::Streaming::Stream)
end
it 'should not extend stream objects of other apps' do
out = nil
mock_app { get('/') { out = stream { }}}
get('/')
out.should be_a(Sinatra::Helpers::Stream)
out.should_not be_a(Sinatra::Streaming::Stream)
end
end
context 'app' do
it 'is the app instance the stream was created from' do
out = stream { }
out.app.should be_a(Sinatra::Base)
end
end
context 'lineno' do
it 'defaults to 0' do
stream { }.lineno.should be == 0
end
it 'does not increase on write' do
stream do |out|
out << "many\nlines\n"
out.lineno.should be == 0
end
end
it 'is writable' do
out = stream { }
out.lineno = 10
out.lineno.should be == 10
end
end
context 'pos' do
it 'defaults to 0' do
stream { }.pos.should be == 0
end
it 'increases when writing data' do
stream do |out|
out.pos.should be == 0
out << 'hi'
out.pos.should be == 2
end
end
it 'is writable' do
out = stream { }
out.pos = 10
out.pos.should be == 10
end
it 'aliased to #tell' do
out = stream { }
out.tell.should be == 0
out.pos = 10
out.tell.should be == 10
end
end
context 'closed' do
it 'returns false while streaming' do
stream { |out| out.should_not be_closed }
end
it 'returns true after streaming' do
stream {}.should be_closed
end
end
context 'map!' do
it 'applies transformations later' do
stream do |out|
out.map! { |s| s.upcase }
out << 'ok'
end
body.should be == "OK"
end
it 'is chainable' do
stream do |out|
out.map! { |s| s.upcase }
out.map! { |s| s.reverse }
out << 'ok'
end
body.should be == "KO"
end
it 'works with middleware' do
middleware = Class.new do
def initialize(app) @app = app end
def call(env)
status, headers, body = @app.call(env)
body.map! { |s| s.upcase }
[status, headers, body]
end
end
use middleware
stream { |out| out << "ok" }
body.should be == "OK"
end
it 'modifies each value separately' do
stream do |out|
out.map! { |s| s.reverse }
out << "ab" << "cd"
end
body.should be == "badc"
end
end
context 'map' do
it 'works with middleware' do
middleware = Class.new do
def initialize(app) @app = app end
def call(env)
status, headers, body = @app.call(env)
[status, headers, body.map(&:upcase)]
end
end
use middleware
stream { |out| out << "ok" }
body.should be == "OK"
end
it 'is chainable' do
middleware = Class.new do
def initialize(app) @app = app end
def call(env)
status, headers, body = @app.call(env)
[status, headers, body.map(&:upcase).map(&:reverse)]
end
end
use middleware
stream { |out| out << "ok" }
body.should be == "KO"
end
it 'can be written as each.map' do
middleware = Class.new do
def initialize(app) @app = app end
def call(env)
status, headers, body = @app.call(env)
[status, headers, body.each.map(&:upcase)]
end
end
use middleware
stream { |out| out << "ok" }
body.should be == "OK"
end
it 'does not modify the original body' do
stream do |out|
out.map { |s| s.reverse }
out << 'ok'
end
body.should be == 'ok'
end
end
context 'write' do
it 'writes to the stream' do
stream { |out| out.write 'hi' }
body.should be == 'hi'
end
it 'returns the number of bytes' do
stream do |out|
out.write('hi').should be == 2
out.write('hello').should be == 5
end
end
it 'accepts non-string objects' do
stream do |out|
out.write(12).should be == 2
end
end
it 'should be aliased to syswrite' do
stream { |out| out.syswrite('hi').should be == 2 }
body.should be == 'hi'
end
it 'should be aliased to write_nonblock' do
stream { |out| out.write_nonblock('hi').should be == 2 }
body.should be == 'hi'
end
end
context 'print' do
it 'writes to the stream' do
stream { |out| out.print('hi') }
body.should be == 'hi'
end
it 'accepts multiple arguments' do
stream { |out| out.print(1, 2, 3, 4) }
body.should be == '1234'
end
it 'returns nil' do
stream { |out| out.print('hi').should be_nil }
end
end
context 'printf' do
it 'writes to the stream' do
stream { |out| out.printf('hi') }
body.should be == 'hi'
end
it 'interpolates the format string' do
stream { |out| out.printf("%s: %d", "answer", 42) }
body.should be == 'answer: 42'
end
it 'returns nil' do
stream { |out| out.printf('hi').should be_nil }
end
end
context 'putc' do
it 'writes the first character of a string' do
stream { |out| out.putc('hi') }
body.should be == 'h'
end
it 'writes the character corresponding to an integer' do
stream { |out| out.putc(42) }
body.should be == '*'
end
it 'returns nil' do
stream { |out| out.putc('hi').should be_nil }
end
end
context 'puts' do
it 'writes to the stream' do
stream { |out| out.puts('hi') }
body.should be == "hi\n"
end
it 'accepts multiple arguments' do
stream { |out| out.puts(1, 2, 3, 4) }
body.should be == "1\n2\n3\n4\n"
end
it 'returns nil' do
stream { |out| out.puts('hi').should be_nil }
end
end
context 'close' do
it 'sets #closed? to true' do
stream do |out|
out.close
out.should be_closed
end
end
it 'sets #closed_write? to true' do
stream do |out|
out.should_not be_closed_write
out.close
out.should be_closed_write
end
end
it 'fires callbacks' do
stream do |out|
fired = false
out.callback { fired = true }
out.close
fired.should be true
end
end
it 'prevents from further writing' do
stream do |out|
out.close
expect { out << 'hi' }.to raise_error(IOError, 'not opened for writing')
end
end
end
context 'close_read' do
it 'raises the appropriate exception' do
expect { stream { |out| out.close_read }}.
to raise_error(IOError, "closing non-duplex IO for reading")
end
end
context 'closed_read?' do
it('returns true') { stream { |out| out.should be_closed_read }}
end
context 'rewind' do
it 'resets pos' do
stream do |out|
out << 'hi'
out.rewind
out.pos.should be == 0
end
end
it 'resets lineno' do
stream do |out|
out.lineno = 10
out.rewind
out.lineno.should be == 0
end
end
end
raises = %w[
bytes eof? eof getbyte getc gets read read_nonblock readbyte readchar
readline readlines readpartial sysread ungetbyte ungetc
]
enum = %w[chars each_line each_byte each_char lines]
dummies = %w[flush fsync internal_encoding pid]
raises.each do |method|
context method do
it 'raises the appropriate exception' do
expect { stream { |out| out.public_send(method) }}.
to raise_error(IOError, "not opened for reading")
end
end
end
enum.each do |method|
context method do
it 'creates an Enumerator' do
stream { |out| out.public_send(method).should be_a(Enumerator) }
end
it 'calling each raises the appropriate exception' do
expect { stream { |out| out.public_send(method).each { }}}.
to raise_error(IOError, "not opened for reading")
end
end
end
dummies.each do |method|
context method do
it 'returns nil' do
stream { |out| out.public_send(method).should be_nil }
end
end
end
end
sinatra-contrib-1.4.7/spec/respond_with/ 0000755 0000041 0000041 00000000000 12706205017 020311 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/respond_with/bar.json.erb 0000644 0000041 0000041 00000000005 12706205017 022512 0 ustar www-data www-data json! sinatra-contrib-1.4.7/spec/respond_with/not_html.sass 0000644 0000041 0000041 00000000022 12706205017 023022 0 ustar www-data www-data body
color: red
sinatra-contrib-1.4.7/spec/respond_with/bar.erb 0000644 0000041 0000041 00000000012 12706205017 021540 0 ustar www-data www-data guten Tag! sinatra-contrib-1.4.7/spec/respond_with/baz.yajl 0000644 0000041 0000041 00000000017 12706205017 021744 0 ustar www-data www-data json = "yajl!"
sinatra-contrib-1.4.7/spec/respond_with/foo.html.erb 0000644 0000041 0000041 00000000022 12706205017 022523 0 ustar www-data www-data Hello <%= name %>! sinatra-contrib-1.4.7/spec/reloader_spec.rb 0000644 0000041 0000041 00000032201 12706205017 020736 0 ustar www-data www-data require 'spec_helper'
require 'fileutils'
describe Sinatra::Reloader do
# Returns the temporary directory.
def tmp_dir
File.expand_path('../../tmp', __FILE__)
end
# Returns the path of the Sinatra application file created by
# +setup_example_app+.
def app_file_path
File.join(tmp_dir, "example_app_#{$example_app_counter}.rb")
end
# Returns the name of the Sinatra application created by
# +setup_example_app+: 'ExampleApp1' for the first application,
# 'ExampleApp2' fo the second one, and so on...
def app_name
"ExampleApp#{$example_app_counter}"
end
# Returns the (constant of the) Sinatra application created by
# +setup_example_app+.
def app_const
Module.const_get(app_name)
end
# Writes a file with a Sinatra application using the template
# located at specs/reloader/app.rb.erb. It expects an
# +options+ hash, with an array of strings containing the
# application's routes (+:routes+ key), a hash with the inline
# template's names as keys and the bodys as values
# (+:inline_templates+ key) and an optional application name
# (+:name+) otherwise +app_name+ is used.
#
# It ensures to change the written file's mtime when it already
# exists.
def write_app_file(options={})
options[:routes] ||= ['get("/foo") { erb :foo }']
options[:inline_templates] ||= nil
options[:extensions] ||= []
options[:middlewares] ||= []
options[:filters] ||= []
options[:errors] ||= {}
options[:name] ||= app_name
options[:enable_reloader] = true unless options[:enable_reloader] === false
options[:parent] ||= 'Sinatra::Base'
update_file(app_file_path) do |f|
template_path = File.expand_path('../reloader/app.rb.erb', __FILE__)
template = Tilt.new(template_path, nil, :trim => '<>')
f.write template.render(Object.new, options)
end
end
alias update_app_file write_app_file
# It calls File.open(path, 'w', &block) all the times
# needed to change the file's mtime.
def update_file(path, &block)
original_mtime = File.exist?(path) ? File.mtime(path) : Time.at(0)
new_time = original_mtime + 1
File.open(path, 'w', &block)
File.utime(new_time, new_time, path)
end
# Writes a Sinatra application to a file, requires the file, sets
# the new application as the one being tested and enables the
# reloader.
def setup_example_app(options={})
$example_app_counter ||= 0
$example_app_counter += 1
FileUtils.mkdir_p(tmp_dir)
write_app_file(options)
$LOADED_FEATURES.delete app_file_path
require app_file_path
self.app = app_const
app_const.enable :reloader
end
after(:all) { FileUtils.rm_rf(tmp_dir) }
describe "default route reloading mechanism" do
before(:each) do
setup_example_app(:routes => ['get("/foo") { "foo" }'])
end
it "doesn't mess up the application" do
get('/foo').body.should == 'foo'
end
it "knows when a route has been modified" do
update_app_file(:routes => ['get("/foo") { "bar" }'])
get('/foo').body.should == 'bar'
end
it "knows when a route has been added" do
update_app_file(
:routes => ['get("/foo") { "foo" }', 'get("/bar") { "bar" }']
)
get('/foo').body.should == 'foo'
get('/bar').body.should == 'bar'
end
it "knows when a route has been removed" do
update_app_file(:routes => ['get("/bar") { "bar" }'])
get('/foo').status.should == 404
end
it "doesn't try to reload a removed file" do
update_app_file(:routes => ['get("/foo") { "i shall not be reloaded" }'])
FileUtils.rm app_file_path
get('/foo').body.strip.should == 'foo'
end
end
describe "default inline templates reloading mechanism" do
before(:each) do
setup_example_app(
:routes => ['get("/foo") { erb :foo }'],
:inline_templates => { :foo => 'foo' }
)
end
it "doesn't mess up the application" do
get('/foo').body.strip.should == 'foo'
end
it "reloads inline templates in the app file" do
update_app_file(
:routes => ['get("/foo") { erb :foo }'],
:inline_templates => { :foo => 'bar' }
)
get('/foo').body.strip.should == 'bar'
end
it "reloads inline templates in other file" do
setup_example_app(:routes => ['get("/foo") { erb :foo }'])
template_file_path = File.join(tmp_dir, 'templates.rb')
File.open(template_file_path, 'w') do |f|
f.write "__END__\n\n@@foo\nfoo"
end
require template_file_path
app_const.inline_templates= template_file_path
get('/foo').body.strip.should == 'foo'
update_file(template_file_path) do |f|
f.write "__END__\n\n@@foo\nbar"
end
get('/foo').body.strip.should == 'bar'
end
end
describe "default middleware reloading mechanism" do
it "knows when a middleware has been added" do
setup_example_app(:routes => ['get("/foo") { "foo" }'])
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:middlewares => [Rack::Head]
)
get('/foo') # ...to perform the reload
app_const.middleware.should_not be_empty
end
it "knows when a middleware has been removed" do
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:middlewares => [Rack::Head]
)
update_app_file(:routes => ['get("/foo") { "foo" }'])
get('/foo') # ...to perform the reload
app_const.middleware.should be_empty
end
end
describe "default filter reloading mechanism" do
it "knows when a before filter has been added" do
setup_example_app(:routes => ['get("/foo") { "foo" }'])
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:filters => ['before { @hi = "hi" }']
)
get('/foo') # ...to perform the reload
}.to change { app_const.filters[:before].size }.by(1)
end
it "knows when an after filter has been added" do
setup_example_app(:routes => ['get("/foo") { "foo" }'])
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:filters => ['after { @bye = "bye" }']
)
get('/foo') # ...to perform the reload
}.to change { app_const.filters[:after].size }.by(1)
end
it "knows when a before filter has been removed" do
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:filters => ['before { @hi = "hi" }']
)
expect {
update_app_file(:routes => ['get("/foo") { "foo" }'])
get('/foo') # ...to perform the reload
}.to change { app_const.filters[:before].size }.by(-1)
end
it "knows when an after filter has been removed" do
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:filters => ['after { @bye = "bye" }']
)
expect {
update_app_file(:routes => ['get("/foo") { "foo" }'])
get('/foo') # ...to perform the reload
}.to change { app_const.filters[:after].size }.by(-1)
end
end
describe "error reloading" do
before do
setup_example_app(
:routes => ['get("/secret") { 403 }'],
:errors => { 403 => "'Access forbiden'" }
)
end
it "doesn't mess up the application" do
get('/secret').should be_client_error
get('/secret').body.strip.should == 'Access forbiden'
end
it "knows when a error has been added" do
update_app_file(:errors => { 404 => "'Nowhere'" })
get('/nowhere').should be_not_found
get('/nowhere').body.should == 'Nowhere'
end
it "knows when a error has been removed" do
update_app_file(:routes => ['get("/secret") { 403 }'])
get('/secret').should be_client_error
get('/secret').body.should_not == 'Access forbiden'
end
it "knows when a error has been modified" do
update_app_file(
:routes => ['get("/secret") { 403 }'],
:errors => { 403 => "'What are you doing here?'" }
)
get('/secret').should be_client_error
get('/secret').body.should == 'What are you doing here?'
end
end
describe "extension reloading" do
it "doesn't duplicate routes with every reload" do
module ::RouteExtension
def self.registered(klass)
klass.get('/bar') { 'bar' }
end
end
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['RouteExtension']
)
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['RouteExtension']
)
get('/foo') # ...to perform the reload
}.to_not change { app_const.routes['GET'].size }
end
it "doesn't duplicate middleware with every reload" do
module ::MiddlewareExtension
def self.registered(klass)
klass.use Rack::Head
end
end
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['MiddlewareExtension']
)
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['MiddlewareExtension']
)
get('/foo') # ...to perform the reload
}.to_not change { app_const.middleware.size }
end
it "doesn't duplicate before filters with every reload" do
module ::BeforeFilterExtension
def self.registered(klass)
klass.before { @hi = 'hi' }
end
end
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['BeforeFilterExtension']
)
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['BeforeFilterExtension']
)
get('/foo') # ...to perform the reload
}.to_not change { app_const.filters[:before].size }
end
it "doesn't duplicate after filters with every reload" do
module ::AfterFilterExtension
def self.registered(klass)
klass.after { @bye = 'bye' }
end
end
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['AfterFilterExtension']
)
expect {
update_app_file(
:routes => ['get("/foo") { "foo" }'],
:extensions => ['AfterFilterExtension']
)
get('/foo') # ...to perform the reload
}.to_not change { app_const.filters[:after].size }
end
end
describe ".dont_reload" do
before(:each) do
setup_example_app(
:routes => ['get("/foo") { erb :foo }'],
:inline_templates => { :foo => 'foo' }
)
end
it "allows to specify a file to stop from being reloaded" do
app_const.dont_reload app_file_path
update_app_file(:routes => ['get("/foo") { "bar" }'])
get('/foo').body.strip.should == 'foo'
end
it "allows to specify a glob to stop matching files from being reloaded" do
app_const.dont_reload '**/*.rb'
update_app_file(:routes => ['get("/foo") { "bar" }'])
get('/foo').body.strip.should == 'foo'
end
it "doesn't interfere with other application's reloading policy" do
app_const.dont_reload '**/*.rb'
setup_example_app(:routes => ['get("/foo") { "foo" }'])
update_app_file(:routes => ['get("/foo") { "bar" }'])
get('/foo').body.strip.should == 'bar'
end
end
describe ".also_reload" do
before(:each) do
setup_example_app(:routes => ['get("/foo") { Foo.foo }'])
@foo_path = File.join(tmp_dir, 'foo.rb')
update_file(@foo_path) do |f|
f.write 'class Foo; def self.foo() "foo" end end'
end
$LOADED_FEATURES.delete @foo_path
require @foo_path
app_const.also_reload @foo_path
end
it "allows to specify a file to be reloaded" do
get('/foo').body.strip.should == 'foo'
update_file(@foo_path) do |f|
f.write 'class Foo; def self.foo() "bar" end end'
end
get('/foo').body.strip.should == 'bar'
end
it "allows to specify glob to reaload matching files" do
get('/foo').body.strip.should == 'foo'
update_file(@foo_path) do |f|
f.write 'class Foo; def self.foo() "bar" end end'
end
get('/foo').body.strip.should == 'bar'
end
it "doesn't try to reload a removed file" do
update_file(@foo_path) do |f|
f.write 'class Foo; def self.foo() "bar" end end'
end
FileUtils.rm @foo_path
get('/foo').body.strip.should == 'foo'
end
it "doesn't interfere with other application's reloading policy" do
app_const.also_reload '**/*.rb'
setup_example_app(:routes => ['get("/foo") { Foo.foo }'])
get('/foo').body.strip.should == 'foo'
update_file(@foo_path) do |f|
f.write 'class Foo; def self.foo() "bar" end end'
end
get('/foo').body.strip.should == 'foo'
end
end
it "automatically registers the reloader in the subclasses" do
class ::Parent < Sinatra::Base
register Sinatra::Reloader
enable :reloader
end
setup_example_app(
:routes => ['get("/foo") { "foo" }'],
:enable_reloader => false,
:parent => 'Parent'
)
update_app_file(
:routes => ['get("/foo") { "bar" }'],
:enable_reloader => false,
:parent => 'Parent'
)
get('/foo').body.should == 'bar'
end
end
sinatra-contrib-1.4.7/spec/capture_spec.rb 0000644 0000041 0000041 00000003676 12706205017 020622 0 ustar www-data www-data # -*- coding: utf-8 -*-
require 'slim'
require 'spec_helper'
describe Sinatra::Capture do
subject do
Sinatra.new do
enable :inline_templates
helpers Sinatra::Capture
end.new!
end
Tilt.prefer Tilt::ERBTemplate
extend Forwardable
def_delegators :subject, :capture, :capture_later
def render(engine, template)
subject.send(:render, engine, template.to_sym).strip.gsub(/\s+/, ' ')
end
shared_examples_for "a template language" do |engine|
lang = engine == :erubis ? :erb : engine
require "#{engine}"
it "captures content" do
render(engine, "simple_#{lang}").should == "Say Hello World!"
end
it "allows nested captures" do
render(engine, "nested_#{lang}").should == "Say Hello World!"
end
end
describe('haml') { it_behaves_like "a template language", :haml }
describe('slim') { it_behaves_like "a template language", :slim }
describe('erubis') { it_behaves_like "a template language", :erubis }
describe 'erb' do
it_behaves_like "a template language", :erb
it "handles utf-8 encoding" do
render(:erb, "utf_8").should == "UTF-8 –"
end
it "handles ISO-8859-1 encoding" do
render(:erb, "iso_8859_1").should == "ISO-8859-1 -"
end if RUBY_VERSION >= '1.9'
end
end
__END__
@@ simple_erb
Say
<% a = capture do %>World<% end %>
Hello <%= a %>!
@@ nested_erb
Say
<% a = capture do %>
<% b = capture do %>World<% end %>
<%= b %>!
<% end %>
Hello <%= a.strip %>
@@ simple_slim
| Say
- a = capture do
| World
| Hello #{a.strip}!
@@ nested_slim
| Say
- a = capture do
- b = capture do
| World
| #{b.strip}!
| Hello #{a.strip}
@@ simple_haml
Say
- a = capture do
World
Hello #{a.strip}!
@@ nested_haml
Say
- a = capture do
- b = capture do
World
#{b.strip}!
Hello #{a.strip}
@@ utf_8
<% a = capture do %>–<% end %>
UTF-8 <%= a %>
@@ iso_8859_1
<% a = capture do %>-<% end %>
ISO-8859-1 <%= a.force_encoding("iso-8859-1") %>
sinatra-contrib-1.4.7/spec/okjson.rb 0000644 0000041 0000041 00000032634 12706205017 017444 0 ustar www-data www-data # Copyright 2011 Keith Rarick
#
# 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.
# See https://github.com/kr/okjson for updates.
require 'stringio'
# Some parts adapted from
# http://golang.org/src/pkg/json/decode.go and
# http://golang.org/src/pkg/utf8/utf8.go
module OkJson
extend self
# Decodes a json document in string s and
# returns the corresponding ruby value.
# String s must be valid UTF-8. If you have
# a string in some other encoding, convert
# it first.
#
# String values in the resulting structure
# will be UTF-8.
def decode(s)
ts = lex(s)
v, ts = textparse(ts)
if ts.length > 0
raise Error, 'trailing garbage'
end
v
end
# Parses a "json text" in the sense of RFC 4627.
# Returns the parsed value and any trailing tokens.
# Note: this is almost the same as valparse,
# except that it does not accept atomic values.
def textparse(ts)
if ts.length < 0
raise Error, 'empty'
end
typ, _, val = ts[0]
case typ
when '{' then objparse(ts)
when '[' then arrparse(ts)
else
raise Error, "unexpected #{val.inspect}"
end
end
# Parses a "value" in the sense of RFC 4627.
# Returns the parsed value and any trailing tokens.
def valparse(ts)
if ts.length < 0
raise Error, 'empty'
end
typ, _, val = ts[0]
case typ
when '{' then objparse(ts)
when '[' then arrparse(ts)
when :val,:str then [val, ts[1..-1]]
else
raise Error, "unexpected #{val.inspect}"
end
end
# Parses an "object" in the sense of RFC 4627.
# Returns the parsed value and any trailing tokens.
def objparse(ts)
ts = eat('{', ts)
obj = {}
if ts[0][0] == '}'
return obj, ts[1..-1]
end
k, v, ts = pairparse(ts)
obj[k] = v
if ts[0][0] == '}'
return obj, ts[1..-1]
end
loop do
ts = eat(',', ts)
k, v, ts = pairparse(ts)
obj[k] = v
if ts[0][0] == '}'
return obj, ts[1..-1]
end
end
end
# Parses a "member" in the sense of RFC 4627.
# Returns the parsed values and any trailing tokens.
def pairparse(ts)
(typ, _, k), ts = ts[0], ts[1..-1]
if typ != :str
raise Error, "unexpected #{k.inspect}"
end
ts = eat(':', ts)
v, ts = valparse(ts)
[k, v, ts]
end
# Parses an "array" in the sense of RFC 4627.
# Returns the parsed value and any trailing tokens.
def arrparse(ts)
ts = eat('[', ts)
arr = []
if ts[0][0] == ']'
return arr, ts[1..-1]
end
v, ts = valparse(ts)
arr << v
if ts[0][0] == ']'
return arr, ts[1..-1]
end
loop do
ts = eat(',', ts)
v, ts = valparse(ts)
arr << v
if ts[0][0] == ']'
return arr, ts[1..-1]
end
end
end
def eat(typ, ts)
if ts[0][0] != typ
raise Error, "expected #{typ} (got #{ts[0].inspect})"
end
ts[1..-1]
end
# Sans s and returns a list of json tokens,
# excluding white space (as defined in RFC 4627).
def lex(s)
ts = []
while s.length > 0
typ, lexeme, val = tok(s)
if typ == nil
raise Error, "invalid character at #{s[0,10].inspect}"
end
if typ != :space
ts << [typ, lexeme, val]
end
s = s[lexeme.length..-1]
end
ts
end
# Scans the first token in s and
# returns a 3-element list, or nil
# if no such token exists.
#
# The first list element is one of
# '{', '}', ':', ',', '[', ']',
# :val, :str, and :space.
#
# The second element is the lexeme.
#
# The third element is the value of the
# token for :val and :str, otherwise
# it is the lexeme.
def tok(s)
case s[0]
when ?{ then ['{', s[0,1], s[0,1]]
when ?} then ['}', s[0,1], s[0,1]]
when ?: then [':', s[0,1], s[0,1]]
when ?, then [',', s[0,1], s[0,1]]
when ?[ then ['[', s[0,1], s[0,1]]
when ?] then [']', s[0,1], s[0,1]]
when ?n then nulltok(s)
when ?t then truetok(s)
when ?f then falsetok(s)
when ?" then strtok(s)
when Spc then [:space, s[0,1], s[0,1]]
when ?\t then [:space, s[0,1], s[0,1]]
when ?\n then [:space, s[0,1], s[0,1]]
when ?\r then [:space, s[0,1], s[0,1]]
else numtok(s)
end
end
def nulltok(s); s[0,4] == 'null' && [:val, 'null', nil] end
def truetok(s); s[0,4] == 'true' && [:val, 'true', true] end
def falsetok(s); s[0,5] == 'false' && [:val, 'false', false] end
def numtok(s)
m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
if m && m.begin(0) == 0
if m[3] && !m[2]
[:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
elsif m[2]
[:val, m[0], Float(m[0])]
else
[:val, m[0], Integer(m[0])]
end
end
end
def strtok(s)
m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
if ! m
raise Error, "invalid string literal at #{abbrev(s)}"
end
[:str, m[0], unquote(m[0])]
end
def abbrev(s)
t = s[0,10]
p = t['`']
t = t[0,p] if p
t = t + '...' if t.length < s.length
'`' + t + '`'
end
# Converts a quoted json string literal q into a UTF-8-encoded string.
# The rules are different than for Ruby, so we cannot use eval.
# Unquote will raise an error if q contains control characters.
def unquote(q)
q = q[1...-1]
a = q.dup # allocate a big enough string
r, w = 0, 0
while r < q.length
c = q[r]
case true
when c == ?\\
r += 1
if r >= q.length
raise Error, "string literal ends with a \"\\\": \"#{q}\""
end
case q[r]
when ?",?\\,?/,?'
a[w] = q[r]
r += 1
w += 1
when ?b,?f,?n,?r,?t
a[w] = Unesc[q[r]]
r += 1
w += 1
when ?u
r += 1
uchar = begin
hexdec4(q[r,4])
rescue RuntimeError => e
raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
end
r += 4
if surrogate? uchar
if q.length >= r+6
uchar1 = hexdec4(q[r+2,4])
uchar = subst(uchar, uchar1)
if uchar != Ucharerr
# A valid pair; consume.
r += 6
end
end
end
w += ucharenc(a, w, uchar)
else
raise Error, "invalid escape char #{q[r]} in \"#{q}\""
end
when c == ?", c < Spc
raise Error, "invalid character in string literal \"#{q}\""
else
# Copy anything else byte-for-byte.
# Valid UTF-8 will remain valid UTF-8.
# Invalid UTF-8 will remain invalid UTF-8.
a[w] = c
r += 1
w += 1
end
end
a[0,w]
end
# Encodes unicode character u as UTF-8
# bytes in string a at position i.
# Returns the number of bytes written.
def ucharenc(a, i, u)
case true
when u <= Uchar1max
a[i] = (u & 0xff).chr
1
when u <= Uchar2max
a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
a[i+1] = (Utagx | (u&Umaskx)).chr
2
when u <= Uchar3max
a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
a[i+2] = (Utagx | (u&Umaskx)).chr
3
else
a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
a[i+3] = (Utagx | (u&Umaskx)).chr
4
end
end
def hexdec4(s)
if s.length != 4
raise Error, 'short'
end
(nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
end
def subst(u1, u2)
if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
end
return Ucharerr
end
def unsubst(u)
if u < Usurrself || u > Umax || surrogate?(u)
return Ucharerr, Ucharerr
end
u -= Usurrself
[Usurr1 + ((u>>10)&0x3ff), Usurr2 + (u&0x3ff)]
end
def surrogate?(u)
Usurr1 <= u && u < Usurr3
end
def nibble(c)
case true
when ?0 <= c && c <= ?9 then c.ord - ?0.ord
when ?a <= c && c <= ?z then c.ord - ?a.ord + 10
when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
else
raise Error, "invalid hex code #{c}"
end
end
# Encodes x into a json text. It may contain only
# Array, Hash, String, Numeric, true, false, nil.
# (Note, this list excludes Symbol.)
# X itself must be an Array or a Hash.
# No other value can be encoded, and an error will
# be raised if x contains any other value, such as
# Nan, Infinity, Symbol, and Proc, or if a Hash key
# is not a String.
# Strings contained in x must be valid UTF-8.
def encode(x)
case x
when Hash then objenc(x)
when Array then arrenc(x)
else
raise Error, 'root value must be an Array or a Hash'
end
end
def valenc(x)
case x
when Hash then objenc(x)
when Array then arrenc(x)
when String then strenc(x)
when Numeric then numenc(x)
when true then "true"
when false then "false"
when nil then "null"
else
raise Error, "cannot encode #{x.class}: #{x.inspect}"
end
end
def objenc(x)
'{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
end
def arrenc(a)
'[' + a.map{|x| valenc(x)}.join(',') + ']'
end
def keyenc(k)
case k
when String then strenc(k)
else
raise Error, "Hash key is not a string: #{k.inspect}"
end
end
def strenc(s)
t = StringIO.new
t.putc(?")
r = 0
while r < s.length
case s[r]
when ?" then t.print('\\"')
when ?\\ then t.print('\\\\')
when ?\b then t.print('\\b')
when ?\f then t.print('\\f')
when ?\n then t.print('\\n')
when ?\r then t.print('\\r')
when ?\t then t.print('\\t')
else
c = s[r]
case true
when Spc <= c && c <= ?~
t.putc(c)
when true
u, size = uchardec(s, r)
r += size - 1 # we add one more at the bottom of the loop
if u < 0x10000
t.print('\\u')
hexenc4(t, u)
else
u1, u2 = unsubst(u)
t.print('\\u')
hexenc4(t, u1)
t.print('\\u')
hexenc4(t, u2)
end
else
# invalid byte; skip it
end
end
r += 1
end
t.putc(?")
t.string
end
def hexenc4(t, u)
t.putc(Hex[(u>>12)&0xf])
t.putc(Hex[(u>>8)&0xf])
t.putc(Hex[(u>>4)&0xf])
t.putc(Hex[u&0xf])
end
def numenc(x)
if x.nan? || x.infinite?
return 'null'
end rescue nil
"#{x}"
end
# Decodes unicode character u from UTF-8
# bytes in string s at position i.
# Returns u and the number of bytes read.
def uchardec(s, i)
n = s.length - i
return [Ucharerr, 1] if n < 1
c0 = s[i].ord
# 1-byte, 7-bit sequence?
if c0 < Utagx
return [c0, 1]
end
# unexpected continuation byte?
return [Ucharerr, 1] if c0 < Utag2
# need continuation byte
return [Ucharerr, 1] if n < 2
c1 = s[i+1].ord
return [Ucharerr, 1] if c1 < Utagx || Utag2 <= c1
# 2-byte, 11-bit sequence?
if c0 < Utag3
u = (c0&Umask2)<<6 | (c1&Umaskx)
return [Ucharerr, 1] if u <= Uchar1max
return [u, 2]
end
# need second continuation byte
return [Ucharerr, 1] if n < 3
c2 = s[i+2].ord
return [Ucharerr, 1] if c2 < Utagx || Utag2 <= c2
# 3-byte, 16-bit sequence?
if c0 < Utag4
u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
return [Ucharerr, 1] if u <= Uchar2max
return [u, 3]
end
# need third continuation byte
return [Ucharerr, 1] if n < 4
c3 = s[i+3].ord
return [Ucharerr, 1] if c3 < Utagx || Utag2 <= c3
# 4-byte, 21-bit sequence?
if c0 < Utag5
u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
return [Ucharerr, 1] if u <= Uchar3max
return [u, 4]
end
return [Ucharerr, 1]
end
class Error < ::StandardError
end
Utagx = 0x80 # 1000 0000
Utag2 = 0xc0 # 1100 0000
Utag3 = 0xe0 # 1110 0000
Utag4 = 0xf0 # 1111 0000
Utag5 = 0xF8 # 1111 1000
Umaskx = 0x3f # 0011 1111
Umask2 = 0x1f # 0001 1111
Umask3 = 0x0f # 0000 1111
Umask4 = 0x07 # 0000 0111
Uchar1max = (1<<7) - 1
Uchar2max = (1<<11) - 1
Uchar3max = (1<<16) - 1
Ucharerr = 0xFFFD # unicode "replacement char"
Usurrself = 0x10000
Usurr1 = 0xd800
Usurr2 = 0xdc00
Usurr3 = 0xe000
Umax = 0x10ffff
Spc = ' '[0]
Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
Hex = '0123456789abcdef'
end
sinatra-contrib-1.4.7/spec/extension_spec.rb 0000644 0000041 0000041 00000001214 12706205017 021155 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::Extension do
module ExampleExtension
extend Sinatra::Extension
set :foo, :bar
settings.set :bar, :blah
configure :test, :production do
set :reload_stuff, false
end
configure :development do
set :reload_stuff, true
end
get '/' do
"from extension, yay"
end
end
before { mock_app { register ExampleExtension }}
it('allows using set') { settings.foo.should == :bar }
it('implements configure') { settings.reload_stuff.should be false }
it 'allows defing routes' do
get('/').should be_ok
body.should == "from extension, yay"
end
end
sinatra-contrib-1.4.7/spec/reloader/ 0000755 0000041 0000041 00000000000 12706205017 017401 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/reloader/app.rb.erb 0000644 0000041 0000041 00000001270 12706205017 021255 0 ustar www-data www-data class <%= name %> < <%= parent %>
<% if enable_reloader %>
register Sinatra::Reloader
enable :reloader
<% end %>
<% unless inline_templates.nil? %>
enable :inline_templates
<% end %>
<% extensions.each do |extension| %>
register <%= extension %>
<% end %>
<% middlewares.each do |middleware| %>
use <%= middleware %>
<% end %>
<% filters.each do |filter| %>
<%= filter %>
<% end %>
<% errors.each do |number, code| %>
error <%= number %> do
<%= code %>
end
<% end %>
<% routes.each do |route| %>
<%= route %>
<% end %>
end
<% unless inline_templates.nil? %>
__END__
<% inline_templates.each_pair do |name, content| %>
@@<%= name %>
<%= content %>
<% end %>
<% end %>
sinatra-contrib-1.4.7/spec/content_for/ 0000755 0000041 0000041 00000000000 12706205017 020124 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/content_for/takes_values.erubis 0000644 0000041 0000041 00000000101 12706205017 024015 0 ustar www-data www-data <% content_for :foo do |a, b| %><%= a %> <%= b %><% end %> sinatra-contrib-1.4.7/spec/content_for/same_key.erb 0000644 0000041 0000041 00000000046 12706205017 022413 0 ustar www-data www-data <% content_for :foo do %>foo<% end %>
sinatra-contrib-1.4.7/spec/content_for/passes_values.haml 0000644 0000041 0000041 00000000033 12706205017 023640 0 ustar www-data www-data = yield_content :foo, 1, 2
sinatra-contrib-1.4.7/spec/content_for/footer.haml 0000644 0000041 0000041 00000000054 12706205017 022264 0 ustar www-data www-data - if content_for? :foo
= yield_content :foo sinatra-contrib-1.4.7/spec/content_for/layout.haml 0000644 0000041 0000041 00000000025 12706205017 022301 0 ustar www-data www-data = yield_content :foo
sinatra-contrib-1.4.7/spec/content_for/different_key.erb 0000644 0000041 0000041 00000000046 12706205017 023434 0 ustar www-data www-data <% content_for :bar do %>bar<% end %>
sinatra-contrib-1.4.7/spec/content_for/passes_values.slim 0000644 0000041 0000041 00000000034 12706205017 023664 0 ustar www-data www-data == yield_content :foo, 1, 2
sinatra-contrib-1.4.7/spec/content_for/multiple_yields.slim 0000644 0000041 0000041 00000000077 12706205017 024222 0 ustar www-data www-data = yield_content :foo
= yield_content :foo
= yield_content :foo
sinatra-contrib-1.4.7/spec/content_for/different_key.slim 0000644 0000041 0000041 00000000036 12706205017 023627 0 ustar www-data www-data - content_for :bar do
| bar
sinatra-contrib-1.4.7/spec/content_for/same_key.erubis 0000644 0000041 0000041 00000000046 12706205017 023134 0 ustar www-data www-data <% content_for :foo do %>foo<% end %>
sinatra-contrib-1.4.7/spec/content_for/multiple_blocks.haml 0000644 0000041 0000041 00000000174 12706205017 024161 0 ustar www-data www-data - content_for :foo do
foo
- content_for :foo do
bar
- content_for :baz do
WON'T RENDER ME
- content_for :foo do
baz
sinatra-contrib-1.4.7/spec/content_for/footer.slim 0000644 0000041 0000041 00000000054 12706205017 022307 0 ustar www-data www-data - if content_for? :foo
= yield_content :foo sinatra-contrib-1.4.7/spec/content_for/takes_values.slim 0000644 0000041 0000041 00000000052 12706205017 023475 0 ustar www-data www-data - content_for :foo do |a, b|
i= a
= b
sinatra-contrib-1.4.7/spec/content_for/layout.slim 0000644 0000041 0000041 00000000025 12706205017 022324 0 ustar www-data www-data = yield_content :foo
sinatra-contrib-1.4.7/spec/content_for/footer.erb 0000644 0000041 0000041 00000000100 12706205017 022103 0 ustar www-data www-data <% if content_for? :foo %>
<%= yield_content :foo %>
<% end %> sinatra-contrib-1.4.7/spec/content_for/same_key.haml 0000644 0000041 0000041 00000000034 12706205017 022561 0 ustar www-data www-data - content_for :foo do
foo
sinatra-contrib-1.4.7/spec/content_for/takes_values.haml 0000644 0000041 0000041 00000000052 12706205017 023452 0 ustar www-data www-data - content_for :foo do |a, b|
%i= a
=b
sinatra-contrib-1.4.7/spec/content_for/multiple_blocks.erb 0000644 0000041 0000041 00000000244 12706205017 024006 0 ustar www-data www-data <% content_for :foo do %>foo<% end %>
<% content_for :foo do %>bar<% end %>
<% content_for :baz do %>WON'T RENDER ME<% end %>
<% content_for :foo do %>baz<% end %>
sinatra-contrib-1.4.7/spec/content_for/multiple_yields.erubis 0000644 0000041 0000041 00000000116 12706205017 024541 0 ustar www-data www-data <%= yield_content :foo %>
<%= yield_content :foo %>
<%= yield_content :foo %>
sinatra-contrib-1.4.7/spec/content_for/multiple_blocks.slim 0000644 0000041 0000041 00000000204 12706205017 024176 0 ustar www-data www-data - content_for :foo do
| foo
- content_for :foo do
| bar
- content_for :baz do
| WON'T RENDER ME
- content_for :foo do
| baz
sinatra-contrib-1.4.7/spec/content_for/layout.erb 0000644 0000041 0000041 00000000031 12706205017 022125 0 ustar www-data www-data <%= yield_content :foo %> sinatra-contrib-1.4.7/spec/content_for/layout.erubis 0000644 0000041 0000041 00000000031 12706205017 022646 0 ustar www-data www-data <%= yield_content :foo %> sinatra-contrib-1.4.7/spec/content_for/passes_values.erb 0000644 0000041 0000041 00000000037 12706205017 023473 0 ustar www-data www-data <%= yield_content :foo, 1, 2 %> sinatra-contrib-1.4.7/spec/content_for/same_key.slim 0000644 0000041 0000041 00000000036 12706205017 022606 0 ustar www-data www-data - content_for :foo do
| foo
sinatra-contrib-1.4.7/spec/content_for/multiple_yields.haml 0000644 0000041 0000041 00000000077 12706205017 024177 0 ustar www-data www-data = yield_content :foo
= yield_content :foo
= yield_content :foo
sinatra-contrib-1.4.7/spec/content_for/footer.erubis 0000644 0000041 0000041 00000000100 12706205017 022624 0 ustar www-data www-data <% if content_for? :foo %>
<%= yield_content :foo %>
<% end %> sinatra-contrib-1.4.7/spec/content_for/multiple_yields.erb 0000644 0000041 0000041 00000000116 12706205017 024020 0 ustar www-data www-data <%= yield_content :foo %>
<%= yield_content :foo %>
<%= yield_content :foo %>
sinatra-contrib-1.4.7/spec/content_for/different_key.erubis 0000644 0000041 0000041 00000000046 12706205017 024155 0 ustar www-data www-data <% content_for :bar do %>bar<% end %>
sinatra-contrib-1.4.7/spec/content_for/takes_values.erb 0000644 0000041 0000041 00000000101 12706205017 023274 0 ustar www-data www-data <% content_for :foo do |a, b| %><%= a %> <%= b %><% end %> sinatra-contrib-1.4.7/spec/content_for/passes_values.erubis 0000644 0000041 0000041 00000000037 12706205017 024214 0 ustar www-data www-data <%= yield_content :foo, 1, 2 %> sinatra-contrib-1.4.7/spec/content_for/different_key.haml 0000644 0000041 0000041 00000000034 12706205017 023602 0 ustar www-data www-data - content_for :bar do
bar
sinatra-contrib-1.4.7/spec/content_for/multiple_blocks.erubis 0000644 0000041 0000041 00000000244 12706205017 024527 0 ustar www-data www-data <% content_for :foo do %>foo<% end %>
<% content_for :foo do %>bar<% end %>
<% content_for :baz do %>WON'T RENDER ME<% end %>
<% content_for :foo do %>baz<% end %>
sinatra-contrib-1.4.7/spec/config_file/ 0000755 0000041 0000041 00000000000 12706205017 020050 5 ustar www-data www-data sinatra-contrib-1.4.7/spec/config_file/with_nested_envs.yml 0000644 0000041 0000041 00000000310 12706205017 024135 0 ustar www-data www-data ---
database:
production:
adapter: postgresql
database: foo_production
development:
adapter: sqlite
database: db/development.db
test:
adapter: sqlite
database: db/test.db sinatra-contrib-1.4.7/spec/config_file/key_value.yml.erb 0000644 0000041 0000041 00000000117 12706205017 023325 0 ustar www-data www-data ---
foo: <%= "bar" %>
something: <%= 42 %>
nested:
a: <%= 1 %>
b: <%= 2 %>
sinatra-contrib-1.4.7/spec/config_file/key_value.yml 0000644 0000041 0000041 00000000061 12706205017 022554 0 ustar www-data www-data ---
foo: bar
something: 42
nested:
a: 1
b: 2
sinatra-contrib-1.4.7/spec/config_file/missing_env.yml 0000644 0000041 0000041 00000000053 12706205017 023112 0 ustar www-data www-data ---
foo:
production: 10
development: 20 sinatra-contrib-1.4.7/spec/config_file/with_envs.yml 0000644 0000041 0000041 00000000124 12706205017 022576 0 ustar www-data www-data ---
development:
foo: development
production:
foo: production
test:
foo: test
sinatra-contrib-1.4.7/spec/config_file/key_value_override.yml 0000644 0000041 0000041 00000000015 12706205017 024452 0 ustar www-data www-data ---
foo: foo
sinatra-contrib-1.4.7/spec/respond_with_spec.rb 0000644 0000041 0000041 00000020273 12706205017 021654 0 ustar www-data www-data require 'multi_json'
require 'spec_helper'
require 'okjson'
describe Sinatra::RespondWith do
def provides(*args)
@provides = args
end
def respond_app(&block)
types = @provides
mock_app do
set :app_file, __FILE__
set :views, root + '/respond_with'
register Sinatra::RespondWith
respond_to(*types) if types
class_eval(&block)
end
end
def respond_to(*args, &block)
respond_app { get('/') { respond_to(*args, &block) } }
end
def respond_with(*args, &block)
respond_app { get('/') { respond_with(*args, &block) } }
end
def req(*types)
p = types.shift if types.first.is_a? String and types.first.start_with? '/'
accept = types.map { |t| Sinatra::Base.mime_type(t).to_s }.join ','
get (p || '/'), {}, 'HTTP_ACCEPT' => accept
end
describe "Helpers#respond_to" do
it 'allows defining handlers by file extensions' do
respond_to do |format|
format.html { "html!" }
format.json { "json!" }
end
req(:html).body.should == "html!"
req(:json).body.should == "json!"
end
it 'respects quality' do
respond_to do |format|
format.html { "html!" }
format.json { "json!" }
end
req("text/html;q=0.7, application/json;q=0.3").body.should == "html!"
req("text/html;q=0.3, application/json;q=0.7").body.should == "json!"
end
it 'allows using mime types' do
respond_to do |format|
format.on('text/html') { "html!" }
format.json { "json!" }
end
req(:html).body.should == "html!"
end
it 'allows using wildcards in format matchers' do
respond_to do |format|
format.on('text/*') { "text!" }
format.json { "json!" }
end
req(:html).body.should == "text!"
end
it 'allows using catch all wildcards in format matchers' do
respond_to do |format|
format.on('*/*') { "anything!" }
format.json { "json!" }
end
req(:html).body.should == "anything!"
end
it 'prefers concret over generic' do
respond_to do |format|
format.on('text/*') { "text!" }
format.on('*/*') { "anything!" }
format.json { "json!" }
end
req(:json).body.should == "json!"
req(:html).body.should == "text!"
end
it 'does not set up default handlers' do
respond_to
req.should_not be_ok
status.should == 406
end
end
describe "Helpers#respond_with" do
describe "matching" do
it 'allows defining handlers by file extensions' do
respond_with(:ignore) do |format|
format.html { "html!" }
format.json { "json!" }
end
req(:html).body.should == "html!"
req(:json).body.should == "json!"
end
it 'respects quality' do
respond_with(:ignore) do |format|
format.html { "html!" }
format.json { "json!" }
end
req("text/html;q=0.7, application/json;q=0.3").body.should == "html!"
req("text/html;q=0.3, application/json;q=0.7").body.should == "json!"
end
it 'allows using mime types' do
respond_with(:ignore) do |format|
format.on('text/html') { "html!" }
format.json { "json!" }
end
req(:html).body.should == "html!"
end
it 'allows using wildcards in format matchers' do
respond_with(:ignore) do |format|
format.on('text/*') { "text!" }
format.json { "json!" }
end
req(:html).body.should == "text!"
end
it 'allows using catch all wildcards in format matchers' do
respond_with(:ignore) do |format|
format.on('*/*') { "anything!" }
format.json { "json!" }
end
req(:html).body.should == "anything!"
end
it 'prefers concret over generic' do
respond_with(:ignore) do |format|
format.on('text/*') { "text!" }
format.on('*/*') { "anything!" }
format.json { "json!" }
end
req(:json).body.should == "json!"
req(:html).body.should == "text!"
end
end
describe "default behavior" do
it 'converts objects to json out of the box' do
respond_with 'a' => 'b'
OkJson.decode(req(:json).body).should == {'a' => 'b'}
end
it 'handles multiple routes correctly' do
respond_app do
get('/') { respond_with 'a' => 'b' }
get('/:name') { respond_with 'a' => params[:name] }
end
OkJson.decode(req('/', :json).body).should == {'a' => 'b'}
OkJson.decode(req('/b', :json).body).should == {'a' => 'b'}
OkJson.decode(req('/c', :json).body).should == {'a' => 'c'}
end
it "calls to_EXT if available" do
respond_with Struct.new(:to_pdf).new("hello")
req(:pdf).body.should == "hello"
end
it 'results in a 406 if format cannot be produced' do
respond_with({})
req(:html).should_not be_ok
status.should == 406
end
end
describe 'templates' do
it 'looks for templates with name.target.engine' do
respond_with :foo, :name => 'World'
req(:html).should be_ok
body.should == "Hello World!"
end
it 'looks for templates with name.engine for specific engines' do
respond_with :bar
req(:html).should be_ok
body.should == "guten Tag!"
end
it 'does not use name.engine for engines producing other formats' do
respond_with :not_html
req(:html).should_not be_ok
status.should == 406
body.should be_empty
end
it 'falls back to #json if no template is found' do
respond_with :foo, :name => 'World'
req(:json).should be_ok
OkJson.decode(body).should == {'name' => 'World'}
end
it 'favors templates over #json' do
respond_with :bar, :name => 'World'
req(:json).should be_ok
body.should == 'json!'
end
it 'falls back to to_EXT if no template is found' do
object = {:name => 'World'}
def object.to_pdf; "hi" end
respond_with :foo, object
req(:pdf).should be_ok
body.should == "hi"
end
unless defined? JRUBY_VERSION
it 'uses yajl for json' do
respond_with :baz
req(:json).should be_ok
body.should == "\"yajl!\""
end
end
end
describe 'customizing' do
it 'allows customizing' do
respond_with(:foo, :name => 'World') { |f| f.html { 'html!' }}
req(:html).should be_ok
body.should == "html!"
end
it 'falls back to default behavior if none matches' do
respond_with(:foo, :name => 'World') { |f| f.json { 'json!' }}
req(:html).should be_ok
body.should == "Hello World!"
end
it 'favors generic rule over default behavior' do
respond_with(:foo, :name => 'World') { |f| f.on('*/*') { 'generic!' }}
req(:html).should be_ok
body.should == "generic!"
end
end
describe "inherited" do
it "registers RespondWith in an inherited app" do
app = Sinatra.new do
set :app_file, __FILE__
set :views, root + '/respond_with'
register Sinatra::RespondWith
get '/a' do
respond_with :json
end
end
self.app = Sinatra.new(app)
req('/a', :json).should_not be_ok
end
end
end
describe :respond_to do
it 'acts as global provides condition' do
respond_app do
respond_to :json, :html
get('/a') { 'ok' }
get('/b') { 'ok' }
end
req('/b', :xml).should_not be_ok
req('/b', :html).should be_ok
end
it 'still allows provides' do
respond_app do
respond_to :json, :html
get('/a') { 'ok' }
get('/b', :provides => :json) { 'ok' }
end
req('/b', :html).should_not be_ok
req('/b', :json).should be_ok
end
it 'plays well with namespaces' do
respond_app do
register Sinatra::Namespace
namespace '/a' do
respond_to :json
get { 'json' }
end
get('/b') { 'anything' }
end
req('/a', :html).should_not be_ok
req('/b', :html).should be_ok
end
end
end
sinatra-contrib-1.4.7/spec/namespace_spec.rb 0000644 0000041 0000041 00000055610 12706205017 021106 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::Namespace do
verbs = [:get, :head, :post, :put, :delete, :options]
verbs << :patch if Sinatra::VERSION >= '1.3'
def mock_app(&block)
super do
register Sinatra::Namespace
class_eval(&block)
end
end
def namespace(*args, &block)
mock_app { namespace(*args, &block) }
end
verbs.each do |verb|
describe "HTTP #{verb.to_s.upcase}" do
it 'prefixes the path with the namespace' do
namespace('/foo') { send(verb, '/bar') { 'baz' }}
send(verb, '/foo/bar').should be_ok
body.should == 'baz' unless verb == :head
send(verb, '/foo/baz').should_not be_ok
end
context 'when namespace is a string' do
it 'accepts routes with no path' do
namespace('/foo') { send(verb) { 'bar' } }
send(verb, '/foo').should be_ok
body.should == 'bar' unless verb == :head
end
it 'accepts the path as a named parameter' do
namespace('/foo') { send(verb, '/:bar') { params[:bar] }}
send(verb, '/foo/bar').should be_ok
body.should == 'bar' unless verb == :head
send(verb, '/foo/baz').should be_ok
body.should == 'baz' unless verb == :head
end
it 'accepts the path as a regular expression' do
namespace('/foo') { send(verb, /\/\d\d/) { 'bar' }}
send(verb, '/foo/12').should be_ok
body.should eq 'bar' unless verb == :head
send(verb, '/foo/123').should_not be_ok
end
end
context 'when namespace is a named parameter' do
it 'accepts routes with no path' do
namespace('/:foo') { send(verb) { 'bar' } }
send(verb, '/foo').should be_ok
body.should == 'bar' unless verb == :head
end
it 'sets the parameter correctly' do
namespace('/:foo') { send(verb, '/bar') { params[:foo] }}
send(verb, '/foo/bar').should be_ok
body.should == 'foo' unless verb == :head
send(verb, '/fox/bar').should be_ok
body.should == 'fox' unless verb == :head
send(verb, '/foo/baz').should_not be_ok
end
it 'accepts the path as a named parameter' do
namespace('/:foo') { send(verb, '/:bar') { params[:bar] }}
send(verb, '/foo/bar').should be_ok
body.should == 'bar' unless verb == :head
send(verb, '/foo/baz').should be_ok
body.should == 'baz' unless verb == :head
end
it 'accepts the path as regular expression' do
namespace('/:foo') { send(verb, %r{/bar}) { params[:foo] }}
send(verb, '/foo/bar').should be_ok
body.should == 'foo' unless verb == :head
send(verb, '/fox/bar').should be_ok
body.should == 'fox' unless verb == :head
send(verb, '/foo/baz').should_not be_ok
end
end
context 'when namespace is a regular expression' do
it 'accepts routes with no path' do
namespace(%r{/foo}) { send(verb) { 'bar' } }
send(verb, '/foo').should be_ok
body.should == 'bar' unless verb == :head
end
it 'accepts the path as a named parameter' do
namespace(%r{/foo}) { send(verb, '/:bar') { params[:bar] }}
send(verb, '/foo/bar').should be_ok
body.should == 'bar' unless verb == :head
send(verb, '/foo/baz').should be_ok
body.should == 'baz' unless verb == :head
end
it 'accepts the path as a regular expression' do
namespace(/\/\d\d/) { send(verb, /\/\d\d/) { 'foo' }}
send(verb, '/23/12').should be_ok
body.should == 'foo' unless verb == :head
send(verb, '/123/12').should_not be_ok
end
end
context 'when namespace is a splat' do
it 'accepts the path as a splat' do
namespace('/*') { send(verb, '/*') { params[:splat].join ' - ' }}
send(verb, '/foo/bar').should be_ok
body.should == 'foo - bar' unless verb == :head
end
end
describe 'before-filters' do
specify 'are triggered' do
ran = false
namespace('/foo') { before { ran = true }}
send(verb, '/foo')
ran.should be true
end
specify 'are not triggered for a different namespace' do
ran = false
namespace('/foo') { before { ran = true }}
send(verb, '/fox')
ran.should be false
end
end
describe 'after-filters' do
specify 'are triggered' do
ran = false
namespace('/foo') { after { ran = true }}
send(verb, '/foo')
ran.should be true
end
specify 'are not triggered for a different namespace' do
ran = false
namespace('/foo') { after { ran = true }}
send(verb, '/fox')
ran.should be false
end
end
describe 'conditions' do
context 'when the namespace has no prefix' do
specify 'are accepted in the namespace' do
mock_app do
namespace(:host_name => 'example.com') { send(verb) { 'yes' }}
send(verb, '/') { 'no' }
end
send(verb, '/', {}, 'HTTP_HOST' => 'example.com')
last_response.should be_ok
body.should == 'yes' unless verb == :head
send(verb, '/', {}, 'HTTP_HOST' => 'example.org')
last_response.should be_ok
body.should == 'no' unless verb == :head
end
specify 'are accepted in the route definition' do
namespace :host_name => 'example.com' do
send(verb, '/foo', :provides => :txt) { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain').should be_ok
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html').should_not be_ok
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain').should_not be_ok
end
specify 'are accepted in the before-filter' do
ran = false
namespace :provides => :txt do
before('/foo', :host_name => 'example.com') { ran = true }
send(verb, '/*') { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
ran.should be false
send(verb, '/bar', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be true
end
specify 'are accepted in the after-filter' do
ran = false
namespace :provides => :txt do
after('/foo', :host_name => 'example.com') { ran = true }
send(verb, '/*') { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
ran.should be false
send(verb, '/bar', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be true
end
end
context 'when the namespace is a string' do
specify 'are accepted in the namespace' do
namespace '/foo', :host_name => 'example.com' do
send(verb) { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com').should be_ok
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org').should_not be_ok
end
specify 'are accepted in the before-filter' do
namespace '/foo' do
before(:host_name => 'example.com') { @yes = 'yes' }
send(verb) { @yes || 'no' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com')
last_response.should be_ok
body.should == 'yes' unless verb == :head
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org')
last_response.should be_ok
body.should == 'no' unless verb == :head
end
specify 'are accepted in the after-filter' do
ran = false
namespace '/foo' do
before(:host_name => 'example.com') { ran = true }
send(verb) { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com')
ran.should be true
end
specify 'are accepted in the route definition' do
namespace '/foo' do
send(verb, :host_name => 'example.com') { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com').should be_ok
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org').should_not be_ok
end
context 'when the namespace has a condition' do
specify 'are accepted in the before-filter' do
ran = false
namespace '/', :provides => :txt do
before(:host_name => 'example.com') { ran = true }
send(verb) { 'ok' }
end
send(verb, '/', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
ran.should be false
send(verb, '/', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be true
end
specify 'are accepted in the filters' do
ran = false
namespace '/f', :provides => :txt do
before('oo', :host_name => 'example.com') { ran = true }
send(verb, '/*') { 'ok' }
end
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
ran.should be false
send(verb, '/far', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be false
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
ran.should be true
end
end
end
end
describe 'helpers' do
it 'are defined using the helpers method' do
namespace '/foo' do
helpers do
def magic
42
end
end
send verb, '/bar' do
magic.to_s
end
end
send(verb, '/foo/bar').should be_ok
body.should == '42' unless verb == :head
end
it 'can be defined as normal methods' do
namespace '/foo' do
def magic
42
end
send verb, '/bar' do
magic.to_s
end
end
send(verb, '/foo/bar').should be_ok
body.should == '42' unless verb == :head
end
it 'can be defined using module mixins' do
mixin = Module.new do
def magic
42
end
end
namespace '/foo' do
helpers mixin
send verb, '/bar' do
magic.to_s
end
end
send(verb, '/foo/bar').should be_ok
body.should == '42' unless verb == :head
end
specify 'are unavailable outside the namespace where they are defined' do
mock_app do
namespace '/foo' do
def magic
42
end
send verb, '/bar' do
magic.to_s
end
end
send verb, '/' do
magic.to_s
end
end
proc { send verb, '/' }.should raise_error(NameError)
end
specify 'are unavailable outside the namespace that they are mixed into' do
mixin = Module.new do
def magic
42
end
end
mock_app do
namespace '/foo' do
helpers mixin
send verb, '/bar' do
magic.to_s
end
end
send verb, '/' do
magic.to_s
end
end
proc { send verb, '/' }.should raise_error(NameError)
end
specify 'are available to nested namespaces' do
mock_app do
helpers do
def magic
42
end
end
namespace '/foo' do
send verb, '/bar' do
magic.to_s
end
end
end
send(verb, '/foo/bar').should be_ok
body.should == '42' unless verb == :head
end
specify 'can call super from nested definitions' do
mock_app do
helpers do
def magic
42
end
end
namespace '/foo' do
def magic
super - 19
end
send verb, '/bar' do
magic.to_s
end
end
end
send(verb, '/foo/bar').should be_ok
body.should == '23' unless verb == :head
end
end
describe 'nesting' do
it 'routes to nested namespaces' do
namespace '/foo' do
namespace '/bar' do
send(verb, '/baz') { 'OKAY!!11!'}
end
end
send(verb, '/foo/bar/baz').should be_ok
body.should == 'OKAY!!11!' unless verb == :head
end
it 'exposes helpers to nested namespaces' do
namespace '/foo' do
helpers do
def magic
42
end
end
namespace '/bar' do
send verb, '/baz' do
magic.to_s
end
end
end
send(verb, '/foo/bar/baz').should be_ok
body.should == '42' unless verb == :head
end
specify 'does not provide access to nested helper methods' do
namespace '/foo' do
namespace '/bar' do
def magic
42
end
send verb, '/baz' do
magic.to_s
end
end
send verb do
magic.to_s
end
end
proc { send verb, '/foo' }.should raise_error(NameError)
end
it 'accepts a nested namespace as a named parameter' do
namespace('/:a') { namespace('/:b') { send(verb) { params[:a] }}}
send(verb, '/foo/bar').should be_ok
body.should == 'foo' unless verb == :head
end
end
describe 'error handling' do
it 'can be customized using the not_found block' do
namespace('/de') do
not_found { 'nicht gefunden' }
end
send(verb, '/foo').status.should eq 404
last_response.body.should_not eq 'nicht gefunden' unless verb == :head
get('/en/foo').status.should eq 404
last_response.body.should_not eq 'nicht gefunden' unless verb == :head
get('/de/foo').status.should eq 404
last_response.body.should eq 'nicht gefunden' unless verb == :head
end
it 'can be customized for specific error codes' do
namespace('/de') do
error(404) { 'nicht gefunden' }
end
send(verb, '/foo').status.should eq 404
last_response.body.should_not eq 'nicht gefunden' unless verb == :head
get('/en/foo').status.should eq 404
last_response.body.should_not eq 'nicht gefunden' unless verb == :head
get('/de/foo').status.should eq 404
last_response.body.should eq 'nicht gefunden' unless verb == :head
end
it 'falls back to the handler defined in the base app' do
mock_app do
error(404) { 'not found...' }
namespace('/en') do
end
namespace('/de') do
error(404) { 'nicht gefunden' }
end
end
send(verb, '/foo').status.should eq 404
last_response.body.should eq 'not found...' unless verb == :head
get('/en/foo').status.should eq 404
last_response.body.should eq 'not found...' unless verb == :head
get('/de/foo').status.should eq 404
last_response.body.should eq 'nicht gefunden' unless verb == :head
end
it 'can be customized for specific Exception classes' do
mock_app do
class AError < StandardError; end
class BError < AError; end
error(AError) do
body('auth failed')
401
end
namespace('/en') do
get '/foo' do
raise BError
end
end
namespace('/de') do
error(AError) do
body('methode nicht erlaubt')
406
end
get '/foo' do
raise BError
end
end
end
get('/en/foo').status.should eq 401
last_response.body.should eq 'auth failed' unless verb == :head
get('/de/foo').status.should eq 406
last_response.body.should eq 'methode nicht erlaubt' unless verb == :head
end
it "allows custom error handlers when namespace is declared as /en/:id. Issue #119" do
mock_app {
class CError < StandardError;
end
error { raise "should not come here" }
namespace('/en/:id') do
error(CError) { 201 }
get '/?' do
raise CError
end
end
}
get('/en/1').status.should == 201
end
end
unless verb == :head
describe 'templates' do
specify 'default to the base app\'s template' do
mock_app do
template(:foo) { 'hi' }
send(verb, '/') { erb :foo }
namespace '/foo' do
send(verb) { erb :foo }
end
end
send(verb, '/').body.should eq 'hi'
send(verb, '/foo').body.should eq 'hi'
end
specify 'can be nested' do
mock_app do
template(:foo) { 'hi' }
send(verb, '/') { erb :foo }
namespace '/foo' do
template(:foo) { 'ho' }
send(verb) { erb :foo }
end
end
send(verb, '/').body.should eq 'hi'
send(verb, '/foo').body.should eq 'ho'
end
specify 'can use a custom views directory' do
mock_app do
set :views, File.expand_path('../namespace', __FILE__)
send(verb, '/') { erb :foo }
namespace('/foo') do
set :views, File.expand_path('../namespace/nested', __FILE__)
send(verb) { erb :foo }
end
end
send(verb, '/').body.should eq "hi\n"
send(verb, '/foo').body.should eq "ho\n"
end
specify 'default to the base app\'s layout' do
mock_app do
layout { 'he said: <%= yield %>' }
template(:foo) { 'hi' }
send(verb, '/') { erb :foo }
namespace '/foo' do
template(:foo) { 'ho' }
send(verb) { erb :foo }
end
end
send(verb, '/').body.should eq 'he said: hi'
send(verb, '/foo').body.should eq 'he said: ho'
end
specify 'can define nested layouts' do
mock_app do
layout { 'Hello <%= yield %>!' }
template(:foo) { 'World' }
send(verb, '/') { erb :foo }
namespace '/foo' do
layout { 'Hi <%= yield %>!' }
send(verb) { erb :foo }
end
end
send(verb, '/').body.should eq 'Hello World!'
send(verb, '/foo').body.should eq 'Hi World!'
end
end
end
describe 'extensions' do
specify 'provide read access to settings' do
value = nil
mock_app do
set :foo, 42
namespace '/foo' do
value = foo
end
end
value.should eq 42
end
specify 'can be registered within a namespace' do
a = b = nil
extension = Module.new { define_method(:views) { 'CUSTOM!!!' } }
mock_app do
namespace '/' do
register extension
a = views
end
b = views
end
a.should eq 'CUSTOM!!!'
b.should_not eq 'CUSTOM!!!'
end
specify 'trigger the route_added hook' do
route = nil
extension = Module.new
extension.singleton_class.class_eval do
define_method(:route_added) { |*r| route = r }
end
mock_app do
namespace '/f' do
register extension
get('oo') { }
end
get('/bar') { }
end
route[1].should eq '/foo'
end
specify 'prevent app-global settings from being changed' do
proc { namespace('/') { set :foo, :bar }}.should raise_error
end
end
end
end
describe 'settings' do
it 'provides access to top-level settings' do
mock_app do
set :foo, 'ok'
namespace '/foo' do
get '/bar' do
settings.foo
end
end
end
get('/foo/bar').status.should == 200
last_response.body.should == 'ok'
end
it 'uses some repro' do
mock_app do
set :foo, 42
namespace '/foo' do
get '/bar' do
#settings.respond_to?(:foo).to_s
settings.foo.to_s
end
end
end
get('/foo/bar').status.should == 200
last_response.body.should == '42'
end
it 'allows checking setting existence with respond_to?' do
mock_app do
set :foo, 42
namespace '/foo' do
get '/bar' do
settings.respond_to?(:foo).to_s
end
end
end
get('/foo/bar').status.should == 200
last_response.body.should == 'true'
end
end
end
sinatra-contrib-1.4.7/spec/custom_logger_spec.rb 0000644 0000041 0000041 00000001577 12706205017 022026 0 ustar www-data www-data require 'spec_helper'
require 'sinatra/custom_logger'
describe Sinatra::CustomLogger do
before do
rack_logger = @rack_logger = double
mock_app do
helpers Sinatra::CustomLogger
before do
env['rack.logger'] = rack_logger
end
get '/' do
logger.info 'Logged message'
'Response'
end
end
end
describe '#logger' do
it 'falls back to request.logger' do
expect(@rack_logger).to receive(:info).with('Logged message')
get '/'
end
context 'logger setting is set' do
before do
custom_logger = @custom_logger = double
@app.class_eval do
configure do
set :logger, custom_logger
end
end
end
it 'calls custom logger' do
expect(@custom_logger).to receive(:info).with('Logged message')
get '/'
end
end
end
end
sinatra-contrib-1.4.7/spec/json_spec.rb 0000644 0000041 0000041 00000006271 12706205017 020122 0 ustar www-data www-data require 'multi_json'
require 'spec_helper'
require 'okjson'
shared_examples_for "a json encoder" do |lib, const|
before do
begin
require lib if lib
@encoder = eval(const)
rescue LoadError
pending "unable to load #{lib}"
end
end
it "allows setting :encoder to #{const}" do
enc = @encoder
mock_app { get('/') { json({'foo' => 'bar'}, :encoder => enc) }}
results_in 'foo' => 'bar'
end
it "allows setting settings.json_encoder to #{const}" do
enc = @encoder
mock_app do
set :json_encoder, enc
get('/') { json 'foo' => 'bar' }
end
results_in 'foo' => 'bar'
end
end
describe Sinatra::JSON do
def mock_app(&block)
super do
class_eval(&block)
end
end
def results_in(obj)
OkJson.decode(get('/').body).should == obj
end
it "encodes objects to json out of the box" do
mock_app { get('/') { json :foo => [1, 'bar', nil] } }
results_in 'foo' => [1, 'bar', nil]
end
it "sets the content type to 'application/json'" do
mock_app { get('/') { json({}) } }
get('/')["Content-Type"].should include("application/json")
end
it "allows overriding content type with :content_type" do
mock_app { get('/') { json({}, :content_type => "foo/bar") } }
get('/')["Content-Type"].should == "foo/bar"
end
it "accepts shorthands for :content_type" do
mock_app { get('/') { json({}, :content_type => :js) } }
get('/')["Content-Type"].should == "application/javascript;charset=utf-8"
end
it 'calls generate on :encoder if available' do
enc = Object.new
def enc.generate(obj) obj.inspect end
mock_app { get('/') { json(42, :encoder => enc) }}
get('/').body.should == '42'
end
it 'calls encode on :encoder if available' do
enc = Object.new
def enc.encode(obj) obj.inspect end
mock_app { get('/') { json(42, :encoder => enc) }}
get('/').body.should == '42'
end
it 'sends :encoder as method call if it is a Symbol' do
mock_app { get('/') { json(42, :encoder => :inspect) }}
get('/').body.should == '42'
end
it 'calls generate on settings.json_encoder if available' do
enc = Object.new
def enc.generate(obj) obj.inspect end
mock_app do
set :json_encoder, enc
get('/') { json 42 }
end
get('/').body.should == '42'
end
it 'calls encode on settings.json_encode if available' do
enc = Object.new
def enc.encode(obj) obj.inspect end
mock_app do
set :json_encoder, enc
get('/') { json 42 }
end
get('/').body.should == '42'
end
it 'sends settings.json_encode as method call if it is a Symbol' do
mock_app do
set :json_encoder, :inspect
get('/') { json 42 }
end
get('/').body.should == '42'
end
describe('Yajl') { it_should_behave_like "a json encoder", "yajl", "Yajl::Encoder" } unless defined? JRUBY_VERSION
describe('JSON') { it_should_behave_like "a json encoder", "json", "::JSON" }
describe('OkJson') { it_should_behave_like "a json encoder", nil, "OkJson" }
describe('to_json') { it_should_behave_like "a json encoder", "json", ":to_json" }
describe('without') { it_should_behave_like "a json encoder", nil, "Sinatra::JSON" }
end
sinatra-contrib-1.4.7/spec/cookies_spec.rb 0000644 0000041 0000041 00000046013 12706205017 020603 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::Cookies do
def cookie_route(*cookies, &block)
result = nil
set_cookie(cookies)
@cookie_app.get('/') do
result = instance_eval(&block)
"ok"
end
get '/', {}, @headers || {}
last_response.should be_ok
body.should be == "ok"
result
end
def cookies(*set_cookies)
cookie_route(*set_cookies) { cookies }
end
before do
app = nil
mock_app do
helpers Sinatra::Cookies
app = self
end
@cookie_app = app
clear_cookies
end
describe :cookie_route do
it 'runs the block' do
ran = false
cookie_route { ran = true }
ran.should be true
end
it 'returns the block result' do
cookie_route { 42 }.should be == 42
end
end
describe :== do
it 'is comparable to hashes' do
cookies.should be == {}
end
it 'is comparable to anything that responds to to_hash' do
other = Struct.new(:to_hash).new({})
cookies.should be == other
end
end
describe :[] do
it 'allows access to request cookies' do
cookies("foo=bar")["foo"].should be == "bar"
end
it 'takes symbols as keys' do
cookies("foo=bar")[:foo].should be == "bar"
end
it 'returns nil for missing keys' do
cookies("foo=bar")['bar'].should be_nil
end
it 'allows access to response cookies' do
cookie_route do
response.set_cookie 'foo', 'bar'
cookies['foo']
end.should be == 'bar'
end
it 'favors response cookies over request cookies' do
cookie_route('foo=bar') do
response.set_cookie 'foo', 'baz'
cookies['foo']
end.should be == 'baz'
end
it 'takes the last value for response cookies' do
cookie_route do
response.set_cookie 'foo', 'bar'
response.set_cookie 'foo', 'baz'
cookies['foo']
end.should be == 'baz'
end
end
describe :[]= do
it 'sets cookies to httponly' do
cookie_route do
cookies['foo'] = 'bar'
response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
end.should include('HttpOnly')
end
it 'sets domain to nil if localhost' do
@headers = {'HTTP_HOST' => 'localhost'}
cookie_route do
cookies['foo'] = 'bar'
response['Set-Cookie']
end.should_not include("domain")
end
it 'sets the domain' do
cookie_route do
cookies['foo'] = 'bar'
response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
end.should include('domain=example.org')
end
it 'sets path to / by default' do
cookie_route do
cookies['foo'] = 'bar'
response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
end.should include('path=/')
end
it 'sets path to the script_name if app is nested' do
cookie_route do
request.script_name = '/foo'
cookies['foo'] = 'bar'
response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
end.should include('path=/foo')
end
it 'sets a cookie' do
cookie_route { cookies['foo'] = 'bar' }
cookie_jar['foo'].should be == 'bar'
end
it 'adds a value to the cookies hash' do
cookie_route do
cookies['foo'] = 'bar'
cookies['foo']
end.should be == 'bar'
end
end
describe :assoc do
it 'behaves like Hash#assoc' do
cookies('foo=bar').assoc('foo') == ['foo', 'bar']
end
end if Hash.method_defined? :assoc
describe :clear do
it 'removes request cookies from cookies hash' do
jar = cookies('foo=bar')
jar['foo'].should be == 'bar'
jar.clear
jar['foo'].should be_nil
end
it 'removes response cookies from cookies hash' do
cookie_route do
cookies['foo'] = 'bar'
cookies.clear
cookies['foo']
end.should be_nil
end
it 'expires existing cookies' do
cookie_route("foo=bar") do
cookies.clear
response['Set-Cookie']
end.should include("foo=;", "expires=", "1970 00:00:00")
end
end
describe :compare_by_identity? do
it { cookies.should_not be_compare_by_identity }
end
describe :default do
it { cookies.default.should be_nil }
end
describe :default_proc do
it { cookies.default_proc.should be_nil }
end
describe :delete do
it 'removes request cookies from cookies hash' do
jar = cookies('foo=bar')
jar['foo'].should be == 'bar'
jar.delete 'foo'
jar['foo'].should be_nil
end
it 'removes response cookies from cookies hash' do
cookie_route do
cookies['foo'] = 'bar'
cookies.delete 'foo'
cookies['foo']
end.should be_nil
end
it 'expires existing cookies' do
cookie_route("foo=bar") do
cookies.delete 'foo'
response['Set-Cookie']
end.should include("foo=;", "expires=", "1970 00:00:00")
end
it 'honours the app cookie_options' do
@cookie_app.class_eval do
set :cookie_options, {
:path => '/foo',
:domain => 'bar.com',
:secure => true,
:httponly => true
}
end
cookie_header = cookie_route("foo=bar") do
cookies.delete 'foo'
response['Set-Cookie']
end
cookie_header.should include("path=/foo;", "domain=bar.com;", "secure;", "HttpOnly")
end
it 'does not touch other cookies' do
cookie_route("foo=bar", "bar=baz") do
cookies.delete 'foo'
cookies['bar']
end.should be == 'baz'
end
it 'returns the previous value for request cookies' do
cookie_route("foo=bar") do
cookies.delete "foo"
end.should be == "bar"
end
it 'returns the previous value for response cookies' do
cookie_route do
cookies['foo'] = 'bar'
cookies.delete "foo"
end.should be == "bar"
end
it 'returns nil for non-existing cookies' do
cookie_route { cookies.delete("foo") }.should be_nil
end
end
describe :delete_if do
it 'deletes cookies that match the block' do
cookie_route('foo=bar') do
cookies['bar'] = 'baz'
cookies['baz'] = 'foo'
cookies.delete_if { |*a| a.include? 'bar' }
cookies.values_at 'foo', 'bar', 'baz'
end.should be == [nil, nil, 'foo']
end
end
describe :each do
it 'loops through cookies' do
keys = []
foo = nil
bar = nil
cookie_route('foo=bar', 'bar=baz') do
cookies.each do |key, value|
foo = value if key == 'foo'
bar = value if key == 'bar'
keys << key
end
end
keys.sort.should be == ['bar', 'foo']
foo.should be == 'bar'
bar.should be == 'baz'
end
it 'favors response over request cookies' do
seen = false
cookie_route('foo=bar') do
cookies[:foo] = 'baz'
cookies.each do |key, value|
key.should == 'foo'
value.should == 'baz'
seen.should == false
seen = true
end
end
end
it 'does not loop through deleted cookies' do
cookie_route('foo=bar') do
cookies.delete :foo
cookies.each { fail }
end
end
it 'returns an enumerator' do
cookie_route('foo=bar') do
enum = cookies.each
enum.each { |key, value| key.should == 'foo' }
end
end
end
describe :each_key do
it 'loops through cookies' do
keys = []
cookie_route('foo=bar', 'bar=baz') do
cookies.each_key do |key|
keys << key
end
end
keys.sort.should be == ['bar', 'foo']
end
it 'only yields keys once' do
seen = false
cookie_route('foo=bar') do
cookies[:foo] = 'baz'
cookies.each_key do |key|
seen.should == false
seen = true
end
end
end
it 'does not loop through deleted cookies' do
cookie_route('foo=bar') do
cookies.delete :foo
cookies.each_key { fail }
end
end
it 'returns an enumerator' do
cookie_route('foo=bar') do
enum = cookies.each_key
enum.each { |key| key.should == 'foo' }
end
end
end
describe :each_pair do
it 'loops through cookies' do
keys = []
foo = nil
bar = nil
cookie_route('foo=bar', 'bar=baz') do
cookies.each_pair do |key, value|
foo = value if key == 'foo'
bar = value if key == 'bar'
keys << key
end
end
keys.sort.should be == ['bar', 'foo']
foo.should be == 'bar'
bar.should be == 'baz'
end
it 'favors response over request cookies' do
seen = false
cookie_route('foo=bar') do
cookies[:foo] = 'baz'
cookies.each_pair do |key, value|
key.should == 'foo'
value.should == 'baz'
seen.should == false
seen = true
end
end
end
it 'does not loop through deleted cookies' do
cookie_route('foo=bar') do
cookies.delete :foo
cookies.each_pair { fail }
end
end
it 'returns an enumerator' do
cookie_route('foo=bar') do
enum = cookies.each_pair
enum.each { |key, value| key.should == 'foo' }
end
end
end
describe :each_value do
it 'loops through cookies' do
values = []
cookie_route('foo=bar', 'bar=baz') do
cookies.each_value do |value|
values << value
end
end
values.sort.should be == ['bar', 'baz']
end
it 'favors response over request cookies' do
seen = false
cookie_route('foo=bar') do
cookies[:foo] = 'baz'
cookies.each_value do |value|
value.should == 'baz'
seen.should == false
seen = true
end
end
end
it 'does not loop through deleted cookies' do
cookie_route('foo=bar') do
cookies.delete :foo
cookies.each_value { fail }
end
end
it 'returns an enumerator' do
cookie_route('foo=bar') do
enum = cookies.each_value
enum.each { |value| value.should == 'bar' }
end
end
end
describe :empty? do
it 'returns true if there are no cookies' do
cookies.should be_empty
end
it 'returns false if there are request cookies' do
cookies('foo=bar').should_not be_empty
end
it 'returns false if there are response cookies' do
cookie_route do
cookies['foo'] = 'bar'
cookies.empty?
end.should be false
end
it 'becomes true if response cookies are removed' do
cookie_route do
cookies['foo'] = 'bar'
cookies.delete :foo
cookies.empty?
end.should be true
end
it 'becomes true if request cookies are removed' do
cookie_route('foo=bar') do
cookies.delete :foo
cookies.empty?
end.should be_truthy
end
it 'becomes true after clear' do
cookie_route('foo=bar', 'bar=baz') do
cookies['foo'] = 'bar'
cookies.clear
cookies.empty?
end.should be_truthy
end
end
describe :fetch do
it 'returns values from request cookies' do
cookies('foo=bar').fetch('foo').should be == 'bar'
end
it 'returns values from response cookies' do
cookie_route do
cookies['foo'] = 'bar'
cookies.fetch('foo')
end.should be == 'bar'
end
it 'favors response over request cookies' do
cookie_route('foo=baz') do
cookies['foo'] = 'bar'
cookies.fetch('foo')
end.should be == 'bar'
end
it 'raises an exception if key does not exist' do
error = if defined? JRUBY_VERSION
IndexError
else
RUBY_VERSION >= '1.9' ? KeyError : IndexError
end
expect { cookies.fetch('foo') }.to raise_exception(error)
end
it 'returns the block result if missing' do
cookies.fetch('foo') { 'bar' }.should be == 'bar'
end
end
describe :flatten do
it { cookies('foo=bar').flatten.should be == {'foo' => 'bar'}.flatten }
end if Hash.method_defined? :flatten
describe :has_key? do
it 'checks request cookies' do
cookies('foo=bar').should have_key('foo')
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.should have_key(:foo)
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.should_not have_key('foo')
end
end
describe :has_value? do
it 'checks request cookies' do
cookies('foo=bar').should have_value('bar')
end
it 'checks response cookies' do
jar = cookies
jar[:foo] = 'bar'
jar.should have_value('bar')
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.should_not have_value('bar')
end
end
describe :include? do
it 'checks request cookies' do
cookies('foo=bar').should include('foo')
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.should include(:foo)
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.should_not include('foo')
end
end
describe :index do
it 'checks request cookies' do
cookies('foo=bar').index('bar').should be == 'foo'
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.index('bar').should be == 'foo'
end
it 'returns nil when missing' do
cookies('foo=bar').index('baz').should be_nil
end
end if RUBY_VERSION < '1.9'
describe :keep_if do
it 'removes entries' do
jar = cookies('foo=bar', 'bar=baz')
jar.keep_if { |*args| args == ['bar', 'baz'] }
jar.should be == {'bar' => 'baz'}
end
end
describe :key do
it 'checks request cookies' do
cookies('foo=bar').key('bar').should be == 'foo'
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.key('bar').should be == 'foo'
end
it 'returns nil when missing' do
cookies('foo=bar').key('baz').should be_nil
end
end
describe :key? do
it 'checks request cookies' do
cookies('foo=bar').key?('foo').should be true
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.key?(:foo).should be true
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.key?('foo').should be false
end
end
describe :keys do
it { cookies('foo=bar').keys.should == ['foo'] }
end
describe :length do
it { cookies.length.should == 0 }
it { cookies('foo=bar').length.should == 1 }
end
describe :member? do
it 'checks request cookies' do
cookies('foo=bar').member?('foo').should be true
end
it 'checks response cookies' do
jar = cookies
jar['foo'] = 'bar'
jar.member?(:foo).should be true
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.member?('foo').should be false
end
end
describe :merge do
it 'is mergable with a hash' do
cookies('foo=bar').merge(:bar => :baz).should be == {"foo" => "bar", :bar => :baz}
end
it 'does not create cookies' do
jar = cookies('foo=bar')
jar.merge(:bar => 'baz')
jar.should_not include(:bar)
end
it 'takes a block for conflict resolution' do
update = {'foo' => 'baz', 'bar' => 'baz'}
merged = cookies('foo=bar').merge(update) do |key, old, other|
key.should be == 'foo'
old.should be == 'bar'
other.should be == 'baz'
'foo'
end
merged['foo'].should be == 'foo'
end
end
describe :merge! do
it 'creates cookies' do
jar = cookies('foo=bar')
jar.merge! :bar => 'baz'
jar.should include('bar')
end
it 'overrides existing values' do
jar = cookies('foo=bar')
jar.merge! :foo => "baz"
jar["foo"].should be == "baz"
end
it 'takes a block for conflict resolution' do
update = {'foo' => 'baz', 'bar' => 'baz'}
jar = cookies('foo=bar')
jar.merge!(update) do |key, old, other|
key.should be == 'foo'
old.should be == 'bar'
other.should be == 'baz'
'foo'
end
jar['foo'].should be == 'foo'
end
end
describe :rassoc do
it 'behaves like Hash#assoc' do
cookies('foo=bar').rassoc('bar') == ['foo', 'bar']
end
end if Hash.method_defined? :rassoc
describe :reject do
it 'removes entries from new hash' do
jar = cookies('foo=bar', 'bar=baz')
sub = jar.reject { |*args| args == ['bar', 'baz'] }
sub.should be == {'foo' => 'bar'}
jar['bar'].should be == 'baz'
end
end
describe :reject! do
it 'removes entries' do
jar = cookies('foo=bar', 'bar=baz')
jar.reject! { |*args| args == ['bar', 'baz'] }
jar.should be == {'foo' => 'bar'}
end
end
describe :replace do
it 'replaces entries' do
jar = cookies('foo=bar', 'bar=baz')
jar.replace 'foo' => 'baz', 'baz' => 'bar'
jar.should be == {'foo' => 'baz', 'baz' => 'bar'}
end
end
describe :select do
it 'removes entries from new hash' do
jar = cookies('foo=bar', 'bar=baz')
sub = jar.select { |*args| args != ['bar', 'baz'] }
sub.should be == {'foo' => 'bar'}.select { true }
jar['bar'].should be == 'baz'
end
end
describe :select! do
it 'removes entries' do
jar = cookies('foo=bar', 'bar=baz')
jar.select! { |*args| args != ['bar', 'baz'] }
jar.should be == {'foo' => 'bar'}
end
end if Hash.method_defined? :select!
describe :shift do
it 'removes from the hash' do
jar = cookies('foo=bar')
jar.shift.should be == ['foo', 'bar']
jar.should_not include('bar')
end
end
describe :size do
it { cookies.size.should == 0 }
it { cookies('foo=bar').size.should == 1 }
end
describe :update do
it 'creates cookies' do
jar = cookies('foo=bar')
jar.update :bar => 'baz'
jar.should include('bar')
end
it 'overrides existing values' do
jar = cookies('foo=bar')
jar.update :foo => "baz"
jar["foo"].should be == "baz"
end
it 'takes a block for conflict resolution' do
merge = {'foo' => 'baz', 'bar' => 'baz'}
jar = cookies('foo=bar')
jar.update(merge) do |key, old, other|
key.should be == 'foo'
old.should be == 'bar'
other.should be == 'baz'
'foo'
end
jar['foo'].should be == 'foo'
end
end
describe :value? do
it 'checks request cookies' do
cookies('foo=bar').value?('bar').should be true
end
it 'checks response cookies' do
jar = cookies
jar[:foo] = 'bar'
jar.value?('bar').should be true
end
it 'does not use deleted cookies' do
jar = cookies('foo=bar')
jar.delete :foo
jar.value?('bar').should be false
end
end
describe :values do
it { cookies('foo=bar', 'bar=baz').values.sort.should be == ['bar', 'baz'] }
end
describe :values_at do
it { cookies('foo=bar', 'bar=baz').values_at('foo').should be == ['bar'] }
end
end
sinatra-contrib-1.4.7/spec/content_for_spec.rb 0000644 0000041 0000041 00000014651 12706205017 021472 0 ustar www-data www-data require 'spec_helper'
describe Sinatra::ContentFor do
subject do
Sinatra.new do
helpers Sinatra::ContentFor
set :views, File.expand_path("../content_for", __FILE__)
end.new!
end
Tilt.prefer Tilt::ERBTemplate
extend Forwardable
def_delegators :subject, :content_for, :yield_content
def render(engine, template)
subject.send(:render, engine, template, :layout => false).gsub(/\s/, '')
end
describe "without templates" do
it 'renders blocks declared with the same key you use when rendering' do
content_for(:foo) { "foo" }
yield_content(:foo).should == "foo"
end
it 'renders blocks more than once' do
content_for(:foo) { "foo" }
3.times { yield_content(:foo).should == "foo" }
end
it 'does not render a block with a different key' do
content_for(:bar) { "bar" }
yield_content(:foo).should be_empty
end
it 'renders multiple blocks with the same key' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
yield_content(:foo).should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
3.times { yield_content(:foo).should == "foobarbaz" }
end
it 'passes values to the blocks' do
content_for(:foo) { |a| a.upcase }
yield_content(:foo, 'a').should == "A"
yield_content(:foo, 'b').should == "B"
end
end
# TODO: liquid radius markaby builder nokogiri
engines = %w[erb erubis haml slim]
engines.each do |inner|
describe inner.capitalize do
before :all do
begin
require inner
rescue LoadError => e
pending "Skipping: " << e.message
end
end
describe "with yield_content in Ruby" do
it 'renders blocks declared with the same key you use when rendering' do
render inner, :same_key
yield_content(:foo).strip.should == "foo"
end
it 'renders blocks more than once' do
render inner, :same_key
3.times { yield_content(:foo).strip.should == "foo" }
end
it 'does not render a block with a different key' do
render inner, :different_key
yield_content(:foo).should be_empty
end
it 'renders multiple blocks with the same key' do
render inner, :multiple_blocks
yield_content(:foo).gsub(/\s/, '').should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
render inner, :multiple_blocks
3.times { yield_content(:foo).gsub(/\s/, '').should == "foobarbaz" }
end
it 'passes values to the blocks' do
render inner, :takes_values
yield_content(:foo, 1, 2).gsub(/\s/, '').should == "12"
end
end
describe "with content_for in Ruby" do
it 'renders blocks declared with the same key you use when rendering' do
content_for(:foo) { "foo" }
render(inner, :layout).should == "foo"
end
it 'renders blocks more than once' do
content_for(:foo) { "foo" }
render(inner, :multiple_yields).should == "foofoofoo"
end
it 'does not render a block with a different key' do
content_for(:bar) { "foo" }
render(inner, :layout).should be_empty
end
it 'renders multiple blocks with the same key' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
render(inner, :layout).should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
render(inner, :multiple_yields).should == "foobarbazfoobarbazfoobarbaz"
end
it 'passes values to the blocks' do
content_for(:foo) { |a,b| "#{a}#{b}" }
render(inner, :passes_values).should == "12"
end
end
describe "with content_for? in Ruby" do
it 'renders block if key is set' do
content_for(:foo) { "foot" }
render(inner, :footer).should == "foot"
end
it 'does not render a block if different key' do
content_for(:different_key) { "foot" }
render(inner, :footer).should be_empty
end
end
engines.each do |outer|
describe "with yield_content in #{outer.capitalize}" do
def body
last_response.body.gsub(/\s/, '')
end
before :all do
begin
require outer
rescue LoadError => e
pending "Skipping: " << e.message
end
end
before do
mock_app do
helpers Sinatra::ContentFor
set inner, :layout_engine => outer
set :views, File.expand_path("../content_for", __FILE__)
get('/:view') { render(inner, params[:view].to_sym) }
get('/:layout/:view') do
render inner, params[:view].to_sym, :layout => params[:layout].to_sym
end
end
end
it 'renders blocks declared with the same key you use when rendering' do
get('/same_key').should be_ok
body.should == "foo"
end
it 'renders blocks more than once' do
get('/multiple_yields/same_key').should be_ok
body.should == "foofoofoo"
end
it 'does not render a block with a different key' do
get('/different_key').should be_ok
body.should be_empty
end
it 'renders multiple blocks with the same key' do
get('/multiple_blocks').should be_ok
body.should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
get('/multiple_yields/multiple_blocks').should be_ok
body.should == "foobarbazfoobarbazfoobarbaz"
end
it 'passes values to the blocks' do
get('/passes_values/takes_values').should be_ok
body.should == "12"
end
end
end
end
end
end
sinatra-contrib-1.4.7/lib/ 0000755 0000041 0000041 00000000000 12706205017 015420 5 ustar www-data www-data sinatra-contrib-1.4.7/lib/sinatra/ 0000755 0000041 0000041 00000000000 12706205017 017061 5 ustar www-data www-data sinatra-contrib-1.4.7/lib/sinatra/namespace.rb 0000644 0000041 0000041 00000020501 12706205017 021340 0 ustar www-data www-data require 'backports'
require 'sinatra/base'
require 'sinatra/decompile'
module Sinatra
# = Sinatra::Namespace
#
# Sinatra::Namespace is an extension that adds namespaces to an
# application. This namespaces will allow you to share a path prefix for the
# routes within the namespace, and define filters, conditions and error
# handlers exclusively for them. Besides that, you can also register helpers
# and extensions that will be used only within the namespace.
#
# == Usage
#
# Once you have loaded the extension (see below), you can use the +namespace+
# method to define namespaces in your application.
#
# You can define a namespace by a path prefix:
#
# namespace '/blog' do
# get { haml :blog }
# get '/:entry_permalink' do
# @entry = Entry.find_by_permalink!(params[:entry_permalink])
# haml :entry
# end
#
# # More blog routes...
# end
#
# by a condition:
#
# namespace :host_name => 'localhost' do
# get('/admin/dashboard') { haml :dashboard }
# get('/admin/login') { haml :login }
#
# # More admin routes...
# end
#
# or both:
#
# namespace '/admin', :host_name => 'localhost' do
# get('/dashboard') { haml :dashboard }
# get('/login') { haml :login }
# post('/login') { login_user }
#
# # More admin routes...
# end
#
# When you define a filter or an error handler, or register an extension or a
# set of helpers within a namespace, they only affect the routes defined in
# it. For instance, lets define a before filter to prevent the access of
# unauthorized users to the admin section of the application:
#
# namespace '/admin' do
# helpers AdminHelpers
# before { authenticate unless request.path_info == '/admin/login' }
#
# get '/dashboard' do
# # Only authenticated users can access here...
# haml :dashboard
# end
#
# # More admin routes...
# end
#
# get '/' do
# # Any user can access here...
# haml :index
# end
#
# Well, they actually also affect the nested namespaces:
#
# namespace '/admin' do
# helpers AdminHelpers
# before { authenticate unless request.path_info == '/admin/login' }
#
# namespace '/users' do
# get do
# # Only authenticated users can access here...
# @users = User.all
# haml :users
# end
#
# # More user admin routes...
# end
#
# # More admin routes...
# end
#
# === Classic Application Setup
#
# To be able to use namespaces in a classic application all you need to do is
# require the extension:
#
# require "sinatra"
# require "sinatra/namespace"
#
# # The rest of your classic application code goes here...
#
# === Modular Application Setup
#
# To be able to use namespaces in a modular application all you need to do is
# require the extension, and then, register it:
#
# require "sinatra/base"
# require "sinatra/namespace"
#
# class MyApp < Sinatra::Base
# register Sinatra::Namespace
#
# # The rest of your modular application code goes here...
# end
#
module Namespace
def self.new(base, pattern, conditions = {}, &block)
Module.new do
#quelch uninitialized variable warnings, since these get used by compile method.
@pattern, @conditions = nil, nil
extend NamespacedMethods
include InstanceMethods
@base, @extensions, @errors = base, [], {}
@pattern, @conditions = compile(pattern, conditions)
@templates = Hash.new { |h,k| @base.templates[k] }
namespace = self
before { extend(@namespace = namespace) }
class_eval(&block)
end
end
module InstanceMethods
def settings
@namespace
end
def template_cache
super.fetch(:nested, @namespace) { Tilt::Cache.new }
end
end
module SharedMethods
def namespace(pattern, conditions = {}, &block)
Sinatra::Namespace.new(self, pattern, conditions, &block)
end
end
module NamespacedMethods
include SharedMethods
include Sinatra::Decompile
attr_reader :base, :templates
def self.prefixed(*names)
names.each { |n| define_method(n) { |*a, &b| prefixed(n, *a, &b) }}
end
prefixed :before, :after, :delete, :get, :head, :options, :patch, :post, :put
def helpers(*extensions, &block)
class_eval(&block) if block_given?
include(*extensions) if extensions.any?
end
def register(*extensions, &block)
extensions << Module.new(&block) if block_given?
@extensions += extensions
extensions.each do |extension|
extend extension
extension.registered(self) if extension.respond_to?(:registered)
end
end
def invoke_hook(name, *args)
@extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
end
def not_found(&block)
error(Sinatra::NotFound, &block)
end
def errors
base.errors.merge(namespace_errors)
end
def namespace_errors
@errors
end
def error(*codes, &block)
args = Sinatra::Base.send(:compile!, "ERROR", regexpify(@pattern), block)
codes = codes.map { |c| Array(c) }.flatten
codes << Exception if codes.empty?
codes.each do |c|
errors = @errors[c] ||= []
errors << args
end
end
def respond_to(*args)
return @conditions[:provides] || base.respond_to if args.empty?
@conditions[:provides] = args
end
def set(key, value = self, &block)
raise ArgumentError, "may not set #{key}" if key != :views
return key.each { |k,v| set(k, v) } if block.nil? and value == self
block ||= proc { value }
singleton_class.send(:define_method, key, &block)
end
def enable(*opts)
opts.each { |key| set(key, true) }
end
def disable(*opts)
opts.each { |key| set(key, false) }
end
def template(name, &block)
filename, line = caller_locations.first
templates[name] = [block, filename, line.to_i]
end
def layout(name=:layout, &block)
template name, &block
end
private
def app
base.respond_to?(:base) ? base.base : base
end
def compile(pattern, conditions, default_pattern = nil)
if pattern.respond_to? :to_hash
conditions = conditions.merge pattern.to_hash
pattern = nil
end
base_pattern, base_conditions = @pattern, @conditions
pattern ||= default_pattern
base_pattern ||= base.pattern if base.respond_to? :pattern
base_conditions ||= base.conditions if base.respond_to? :conditions
[ prefixed_path(base_pattern, pattern),
(base_conditions || {}).merge(conditions) ]
end
def prefixed_path(a, b)
return a || b || // unless a and b
a, b = decompile(a), decompile(b) unless a.class == b.class
a, b = regexpify(a), regexpify(b) unless a.class == b.class
path = a.class.new "#{a}#{b}"
path = /^#{path}$/ if path.is_a? Regexp and base == app
path
end
def regexpify(pattern)
pattern = Sinatra::Base.send(:compile, pattern).first.inspect
pattern.gsub! /^\/(\^|\\A)?|(\$|\\z)?\/$/, ''
Regexp.new pattern
end
def prefixed(method, pattern = nil, conditions = {}, &block)
default = '*' if method == :before or method == :after
pattern, conditions = compile pattern, conditions, default
result = base.send(method, pattern, conditions, &block)
invoke_hook :route_added, method.to_s.upcase, pattern, block
result
end
def method_missing(method, *args, &block)
base.send(method, *args, &block)
end
def respond_to?(method, include_private = false)
super || base.respond_to?(method, include_private)
end
end
module BaseMethods
include SharedMethods
end
def self.extend_object(base)
base.extend BaseMethods
end
end
register Sinatra::Namespace
Delegator.delegate :namespace
end
sinatra-contrib-1.4.7/lib/sinatra/decompile.rb 0000644 0000041 0000041 00000007313 12706205017 021353 0 ustar www-data www-data require 'sinatra/base'
require 'backports'
require 'uri'
module Sinatra
# = Sinatra::Decompile
#
# Sinatra::Decompile is an extension that provides a method,
# conveniently called +decompile+, that will generate a String pattern for a
# given route.
#
# == Usage
#
# === Classic Application
#
# To use the extension in a classic application all you need to do is require
# it:
#
# require "sinatra"
# require "sinatra/decompile"
#
# # Your classic application code goes here...
#
# This will add the +decompile+ method to the application/class scope, but
# you can also call it as Sinatra::Decompile.decompile.
#
# === Modular Application
#
# To use the extension in a modular application you need to require it, and
# then, tell the application you will use it:
#
# require "sinatra/base"
# require "sinatra/decompile"
#
# class MyApp < Sinatra::Base
# register Sinatra::Decompile
#
# # The rest of your modular application code goes here...
# end
#
# This will add the +decompile+ method to the application/class scope. You
# can choose not to register the extension, but instead of calling
# +decompile+, you will need to call Sinatra::Decompile.decompile.
#
module Decompile
extend self
##
# Regenerates a string pattern for a given route
#
# Example:
#
# class Sinatra::Application
# routes.each do |verb, list|
# puts "#{verb}:"
# list.each do |data|
# puts "\t" << decompile(data)
# end
# end
# end
#
# Will return the internal Regexp if it's unable to reconstruct the pattern,
# which likely indicates that a Regexp was used in the first place.
#
# You can also use this to check whether you could actually use a string
# pattern instead of your regexp:
#
# decompile /^/foo$/ # => '/foo'
def decompile(pattern, keys = nil, *)
# Everything in here is basically just the reverse of
# Sinatra::Base#compile
#
# Sinatra 2.0 will come with a mechanism for this, making this obsolete.
pattern, keys = pattern if pattern.respond_to? :to_ary
keys, str = keys.try(:dup), pattern.inspect
return pattern unless str.start_with? '/' and str.end_with? '/'
str.gsub! /^\/(\^|\\A)?|(\$|\\z)?\/$/, ''
str.gsub! encoded(' '), ' '
return pattern if str =~ /^[\.\+]/
str.gsub! '((?:[^\.\/?#%]|(?:%[^2].|%[2][^Ee]))+)', '([^\/?#]+)'
str.gsub! '((?:[^\/?#%]|(?:%[^2].|%[2][^Ee]))+)', '([^\/?#]+)'
str.gsub! /\([^\(\)]*\)|\([^\(\)]*\([^\(\)]*\)[^\(\)]*\)/ do |part|
case part
when '(.*?)'
return pattern if keys.shift != 'splat'
'*'
when /^\(\?\:(\\*.)\|%[\w\[\]]+\)$/
$1
when /^\(\?\:(%\d+)\|([^\)]+|\([^\)]+\))\)$/
URI.unescape($1)
when '([^\/?#]+)'
return pattern if keys.empty?
":" << keys.shift
when /^\(\?\:\\?(.)\|/
char = $1
return pattern unless encoded(char) == part
Regexp.escape(char)
else
return pattern
end
end
str.gsub /(.)([\.\+\(\)\/])/ do
return pattern if $1 != "\\"
$2
end
end
private
def encoded(char)
return super if defined? super
enc = uri_parser.escape(char)
enc = "(?:#{escaped(char, enc).join('|')})" if enc == char
enc = "(?:#{enc}|#{encoded('+')})" if char == " "
enc
end
def uri_parser
#TODO: Remove check after dropping support for 1.8.7
@_uri_parser ||= defined?(URI::Parser) ? URI::Parser.new : URI
end
end
register Decompile
end
sinatra-contrib-1.4.7/lib/sinatra/contrib.rb 0000644 0000041 0000041 00000001601 12706205017 021044 0 ustar www-data www-data require 'sinatra/contrib/setup'
module Sinatra
module Contrib
##
# Common middleware that doesn't bring run time overhead if not used
# or breaks if external dependencies are missing. Will extend
# Sinatra::Application by default.
module Common
register :ConfigFile
register :MultiRoute
register :Namespace
register :RespondWith
helpers :Capture
helpers :ContentFor
helpers :Cookies
helpers :EngineTracking
helpers :JSON
helpers :LinkHeader
helpers :Streaming
end
##
# Other extensions you don't want to be loaded unless needed.
module Custom
# register :Compass
register :Decompile
register :Reloader
end
##
# Stuff that aren't Sinatra extensions, technically.
autoload :Extension
autoload :TestHelpers
end
register Sinatra::Contrib::Common
end
sinatra-contrib-1.4.7/lib/sinatra/reloader.rb 0000755 0000041 0000041 00000031745 12706205017 021220 0 ustar www-data www-data require 'sinatra/base'
module Sinatra
# = Sinatra::Reloader
#
# Extension to reload modified files. Useful during development,
# since it will automatically require files defining routes, filters,
# error handlers and inline templates, with every incoming request,
# but only if they have been updated.
#
# == Usage
#
# === Classic Application
#
# To enable the reloader in a classic application all you need to do is
# require it:
#
# require "sinatra"
# require "sinatra/reloader" if development?
#
# # Your classic application code goes here...
#
# === Modular Application
#
# To enable the reloader in a modular application all you need to do is
# require it, and then, register it:
#
# require "sinatra/base"
# require "sinatra/reloader"
#
# class MyApp < Sinatra::Base
# configure :development do
# register Sinatra::Reloader
# end
#
# # Your modular application code goes here...
# end
#
# == Using the Reloader in Other Environments
#
# By default, the reloader is only enabled for the development
# environment. Similar to registering the reloader in a modular
# application, a classic application requires manually enabling the
# extension for it to be available in a non-development environment.
#
# require "sinatra"
# require "sinatra/reloader"
#
# configure :production do
# enable :reloader
# end
#
# == Changing the Reloading Policy
#
# You can refine the reloading policy with +also_reload+ and
# +dont_reload+, to customize which files should, and should not, be
# reloaded, respectively.
#
# === Classic Application
#
# Simply call the methods:
#
# require "sinatra"
# require "sinatra/reloader" if development?
#
# also_reload '/path/to/some/file'
# dont_reload '/path/to/other/file'
#
# # Your classic application code goes here...
#
# === Modular Application
#
# Call the methods inside the +configure+ block:
#
# require "sinatra/base"
# require "sinatra/reloader"
#
# class MyApp < Sinatra::Base
# configure :development do
# register Sinatra::Reloader
# also_reload '/path/to/some/file'
# dont_reload '/path/to/other/file'
# end
#
# # Your modular application code goes here...
# end
#
module Reloader
# Watches a file so it can tell when it has been updated, and what
# elements does it contain.
class Watcher
# Represents an element of a Sinatra application that may need to
# be reloaded. An element could be:
# * a route
# * a filter
# * an error handler
# * a middleware
# * inline templates
#
# Its +representation+ attribute is there to allow to identify the
# element within an application, that is, to match it with its
# Sinatra's internal representation.
class Element < Struct.new(:type, :representation)
end
# Collection of file +Watcher+ that can be associated with a
# Sinatra application. That way, we can know which files belong
# to a given application and which files have been modified. It
# also provides a mechanism to inform a Watcher of the elements
# defined in the file being watched and if its changes should be
# ignored.
class List
@app_list_map = Hash.new { |hash, key| hash[key] = new }
# Returns the +List+ for the application +app+.
def self.for(app)
@app_list_map[app]
end
# Creates a new +List+ instance.
def initialize
@path_watcher_map = Hash.new do |hash, key|
hash[key] = Watcher.new(key)
end
end
# Lets the +Watcher+ for the file located at +path+ know that the
# +element+ is defined there, and adds the +Watcher+ to the +List+,
# if it isn't already there.
def watch(path, element)
watcher_for(path).elements << element
end
# Tells the +Watcher+ for the file located at +path+ to ignore
# the file changes, and adds the +Watcher+ to the +List+, if
# it isn't already there.
def ignore(path)
watcher_for(path).ignore
end
# Adds a +Watcher+ for the file located at +path+ to the
# +List+, if it isn't already there.
def watcher_for(path)
@path_watcher_map[File.expand_path(path)]
end
alias watch_file watcher_for
# Returns an array with all the watchers in the +List+.
def watchers
@path_watcher_map.values
end
# Returns an array with all the watchers in the +List+ that
# have been updated.
def updated
watchers.find_all(&:updated?)
end
end
attr_reader :path, :elements, :mtime
# Creates a new +Watcher+ instance for the file located at +path+.
def initialize(path)
@ignore = nil
@path, @elements = path, []
update
end
# Indicates whether or not the file being watched has been modified.
def updated?
!ignore? && !removed? && mtime != File.mtime(path)
end
# Updates the mtime of the file being watched.
def update
@mtime = File.mtime(path)
end
# Indicates whether or not the file being watched has inline
# templates.
def inline_templates?
elements.any? { |element| element.type == :inline_templates }
end
# Informs that the modifications to the file being watched
# should be ignored.
def ignore
@ignore = true
end
# Indicates whether or not the modifications to the file being
# watched should be ignored.
def ignore?
!!@ignore
end
# Indicates whether or not the file being watched has been removed.
def removed?
!File.exist?(path)
end
end
MUTEX_FOR_PERFORM = Mutex.new
# When the extension is registered it extends the Sinatra application
# +klass+ with the modules +BaseMethods+ and +ExtensionMethods+ and
# defines a before filter to +perform+ the reload of the modified files.
def self.registered(klass)
@reloader_loaded_in ||= {}
return if @reloader_loaded_in[klass]
@reloader_loaded_in[klass] = true
klass.extend BaseMethods
klass.extend ExtensionMethods
klass.set(:reloader) { klass.development? }
klass.set(:reload_templates) { klass.reloader? }
klass.before do
if klass.reloader?
MUTEX_FOR_PERFORM.synchronize { Reloader.perform(klass) }
end
end
klass.set(:inline_templates, klass.app_file) if klass == Sinatra::Application
end
# Reloads the modified files, adding, updating and removing the
# needed elements.
def self.perform(klass)
Watcher::List.for(klass).updated.each do |watcher|
klass.set(:inline_templates, watcher.path) if watcher.inline_templates?
watcher.elements.each { |element| klass.deactivate(element) }
$LOADED_FEATURES.delete(watcher.path)
require watcher.path
watcher.update
end
end
# Contains the methods defined in Sinatra::Base that are overridden.
module BaseMethods
# Protects Sinatra::Base.run! from being called more than once.
def run!(*args)
if settings.reloader?
super unless running?
else
super
end
end
# Does everything Sinatra::Base#route does, but it also tells the
# +Watcher::List+ for the Sinatra application to watch the defined
# route.
#
# Note: We are using #compile! so we don't interfere with extensions
# changing #route.
def compile!(verb, path, block, options = {})
source_location = block.respond_to?(:source_location) ?
block.source_location.first : caller_files[1]
signature = super
watch_element(
source_location, :route, { :verb => verb, :signature => signature }
)
signature
end
# Does everything Sinatra::Base#inline_templates= does, but it also
# tells the +Watcher::List+ for the Sinatra application to watch the
# inline templates in +file+ or the file who made the call to this
# method.
def inline_templates=(file=nil)
file = (file.nil? || file == true) ?
(caller_files[1] || File.expand_path($0)) : file
watch_element(file, :inline_templates)
super
end
# Does everything Sinatra::Base#use does, but it also tells the
# +Watcher::List+ for the Sinatra application to watch the middleware
# being used.
def use(middleware, *args, &block)
path = caller_files[1] || File.expand_path($0)
watch_element(path, :middleware, [middleware, args, block])
super
end
# Does everything Sinatra::Base#add_filter does, but it also tells
# the +Watcher::List+ for the Sinatra application to watch the defined
# filter.
def add_filter(type, path = nil, options = {}, &block)
source_location = block.respond_to?(:source_location) ?
block.source_location.first : caller_files[1]
result = super
watch_element(source_location, :"#{type}_filter", filters[type].last)
result
end
# Does everything Sinatra::Base#error does, but it also tells the
# +Watcher::List+ for the Sinatra application to watch the defined
# error handler.
def error(*codes, &block)
path = caller_files[1] || File.expand_path($0)
result = super
codes.each do |c|
watch_element(path, :error, :code => c, :handler => @errors[c])
end
result
end
# Does everything Sinatra::Base#register does, but it also lets the
# reloader know that an extension is being registered, because the
# elements defined in its +registered+ method need a special treatment.
def register(*extensions, &block)
start_registering_extension
result = super
stop_registering_extension
result
end
# Does everything Sinatra::Base#register does and then registers the
# reloader in the +subclass+.
def inherited(subclass)
result = super
subclass.register Sinatra::Reloader
result
end
end
# Contains the methods that the extension adds to the Sinatra application.
module ExtensionMethods
# Removes the +element+ from the Sinatra application.
def deactivate(element)
case element.type
when :route then
verb = element.representation[:verb]
signature = element.representation[:signature]
(routes[verb] ||= []).delete(signature)
when :middleware then
@middleware.delete(element.representation)
when :before_filter then
filters[:before].delete(element.representation)
when :after_filter then
filters[:after].delete(element.representation)
when :error then
code = element.representation[:code]
handler = element.representation[:handler]
@errors.delete(code) if @errors[code] == handler
end
end
# Indicates with a +glob+ which files should be reloaded if they
# have been modified. It can be called several times.
def also_reload(*glob)
Dir[*glob].each { |path| Watcher::List.for(self).watch_file(path) }
end
# Indicates with a +glob+ which files should not be reloaded even if
# they have been modified. It can be called several times.
def dont_reload(*glob)
Dir[*glob].each { |path| Watcher::List.for(self).ignore(path) }
end
private
# attr_reader :register_path warn on -w (private attribute)
def register_path; @register_path ||= nil; end
# Indicates an extesion is being registered.
def start_registering_extension
@register_path = caller_files[2]
end
# Indicates the extesion has already been registered.
def stop_registering_extension
@register_path = nil
end
# Indicates whether or not an extension is being registered.
def registering_extension?
!register_path.nil?
end
# Builds a Watcher::Element from +type+ and +representation+ and
# tells the Watcher::List for the current application to watch it
# in the file located at +path+.
#
# If an extension is being registered, it also tells the list to
# watch it in the file where the extension has been registered.
# This prevents the duplication of the elements added by the
# extension in its +registered+ method with every reload.
def watch_element(path, type, representation=nil)
list = Watcher::List.for(self)
element = Watcher::Element.new(type, representation)
list.watch(path, element)
list.watch(register_path, element) if registering_extension?
end
end
end
register Reloader
Delegator.delegate :also_reload, :dont_reload
end
sinatra-contrib-1.4.7/lib/sinatra/json.rb 0000644 0000041 0000041 00000006642 12706205017 020367 0 ustar www-data www-data require 'sinatra/base'
require 'multi_json'
module Sinatra
# = Sinatra::JSON
#
# Sinatra::JSON adds a helper method, called +json+, for (obviously)
# json generation.
#
# == Usage
#
# === Classic Application
#
# In a classic application simply require the helper, and start using it:
#
# require "sinatra"
# require "sinatra/json"
#
# # define a route that uses the helper
# get '/' do
# json :foo => 'bar'
# end
#
# # The rest of your classic application code goes here...
#
# === Modular Application
#
# In a modular application you need to require the helper, and then tell the
# application you will use it:
#
# require "sinatra/base"
# require "sinatra/json"
#
# class MyApp < Sinatra::Base
#
# # define a route that uses the helper
# get '/' do
# json :foo => 'bar'
# end
#
# # The rest of your modular application code goes here...
# end
#
# === Encoders
#
# By default it will try to call +to_json+ on the object, but if it doesn't
# respond to that message, it will use its own rather simple encoder. You can
# easily change that anyways. To use +JSON+, simply require it:
#
# require 'json'
#
# The same goes for Yajl::Encoder:
#
# require 'yajl'
#
# For other encoders, besides requiring them, you need to define the
# :json_encoder setting. For instance, for the +Whatever+ encoder:
#
# require 'whatever'
# set :json_encoder, Whatever
#
# To force +json+ to simply call +to_json+ on the object:
#
# set :json_encoder, :to_json
#
# Actually, it can call any method:
#
# set :json_encoder, :my_fancy_json_method
#
# === Content-Type
#
# It will automatically set the content type to "application/json". As
# usual, you can easily change that, with the :json_content_type
# setting:
#
# set :json_content_type, :js
#
# === Overriding the Encoder and the Content-Type
#
# The +json+ helper will also take two options :encoder and
# :content_type. The values of this options are the same as the
# :json_encoder and :json_content_type settings,
# respectively. You can also pass those to the json method:
#
# get '/' do
# json({:foo => 'bar'}, :encoder => :to_json, :content_type => :js)
# end
#
module JSON
class << self
def encode(object)
::MultiJson.dump(object)
end
end
def json(object, options = {})
content_type resolve_content_type(options)
resolve_encoder_action object, resolve_encoder(options)
end
private
def resolve_content_type(options = {})
options[:content_type] || settings.json_content_type
end
def resolve_encoder(options = {})
options[:json_encoder] || settings.json_encoder
end
def resolve_encoder_action(object, encoder)
[:encode, :generate].each do |method|
return encoder.send(method, object) if encoder.respond_to? method
end
if encoder.is_a? Symbol
object.__send__(encoder)
else
fail "#{encoder} does not respond to #generate nor #encode"
end #if
end #resolve_encoder_action
end #JSON
Base.set :json_encoder do
::MultiJson
end
Base.set :json_content_type, :json
# Load the JSON helpers in modular style automatically
Base.helpers JSON
end
sinatra-contrib-1.4.7/lib/sinatra/capture.rb 0000644 0000041 0000041 00000005562 12706205017 021061 0 ustar www-data www-data require 'sinatra/base'
require 'sinatra/engine_tracking'
require 'backports'
module Sinatra
#
# = Sinatra::Capture
#
# Extension that enables blocks inside other extensions.
# It currently works for erb, slim and haml.
# Enables mixing of different template languages.
#
# Example:
#
# # in hello_world.erb
#
# Say
# <% a = capture do %>World<% end %>
# Hello <%= a %>!
#
# # in hello_world.slim
#
# | Say
# - a = capture do
# | World
# | Hello #{a}!
#
# # in hello_world.haml
#
# Say
# - a = capture do
# World
# Hello #{a.strip}!
#
#
# You can also use nested blocks.
#
# Example
#
# # in hello_world.erb
#
# Say
# <% a = capture do %>
# <% b = capture do %>World<% end %>
# <%= b %>!
# <% end %>
# Hello <%= a.strip %>
#
#
# The main advantage of capture is mixing of different template engines.
#
# Example
#
# # in mix_me_up.slim
#
# - two = capture do
# - erb "<%= 1 + 1 %>"
# | 1 + 1 = #{two}
#
# == Usage
#
# === Classic Application
#
# In a classic application simply require the helpers, and start using them:
#
# require "sinatra"
# require "sinatra/capture"
#
# # The rest of your classic application code goes here...
#
# === Modular Application
#
# In a modular application you need to require the helpers, and then tell
# the application you will use them:
#
# require "sinatra/base"
# require "sinatra/capture"
#
# class MyApp < Sinatra::Base
# helpers Sinatra::Capture
#
# # The rest of your modular application code goes here...
# end
#
module Capture
include Sinatra::EngineTracking
DUMMIES = {
:haml => "!= capture_haml(*args, &block)",
:erubis => "<% @capture = yield(*args) %>",
:slim => "== yield(*args)"
}
def capture(*args, &block)
@capture = nil
if current_engine == :ruby
result = block[*args]
elsif current_engine == :erb || current_engine == :slim
@_out_buf, _buf_was = '', @_out_buf
block[*args]
result = eval('@_out_buf', block.binding)
@_out_buf = _buf_was
else
buffer = eval '_buf if defined?(_buf)', block.binding
old_buffer = buffer.dup if buffer
dummy = DUMMIES.fetch(current_engine)
options = { :layout => false, :locals => {:args => args, :block => block }}
buffer.try :clear
result = render(current_engine, dummy, options, &block)
end
result.strip.empty? && @capture ? @capture : result
ensure
buffer.try :replace, old_buffer
end
def capture_later(&block)
engine = current_engine
proc { |*a| with_engine(engine) { @capture = capture(*a, &block) }}
end
end
helpers Capture
end
sinatra-contrib-1.4.7/lib/sinatra/respond_with.rb 0000644 0000041 0000041 00000017754 12706205017 022131 0 ustar www-data www-data require 'sinatra/json'
require 'sinatra/base'
$KCODE = "UTF-8" unless RUBY_VERSION > "1.9.0"
module Sinatra
#
# = Sinatra::RespondWith
#
# These extensions let Sinatra automatically choose what template to render or
# action to perform depending on the request's Accept header.
#
# Example:
#
# # Without Sinatra::RespondWith
# get '/' do
# data = { :name => 'example' }
# request.accept.each do |type|
# case type.to_s
# when 'text/html'
# halt haml(:index, :locals => data)
# when 'text/json'
# halt data.to_json
# when 'application/atom+xml'
# halt nokogiri(:'index.atom', :locals => data)
# when 'application/xml', 'text/xml'
# halt nokogiri(:'index.xml', :locals => data)
# when 'text/plain'
# halt 'just an example'
# end
# end
# error 406
# end
#
# # With Sinatra::RespondWith
# get '/' do
# respond_with :index, :name => 'example' do |f|
# f.txt { 'just an example' }
# end
# end
#
# Both helper methods +respond_to+ and +respond_with+ let you define custom
# handlers like the one above for +text/plain+. +respond_with+ additionally
# takes a template name and/or an object to offer the following default
# behavior:
#
# * If a template name is given, search for a template called
# +name.format.engine+ (+index.xml.nokogiri+ in the above example).
# * If a template name is given, search for a templated called +name.engine+
# for engines known to result in the requested format (+index.haml+).
# * If a file extension associated with the mime type is known to Sinatra, and
# the object responds to +to_extension+, call that method and use the result
# (+data.to_json+).
#
# == Security
#
# Since methods are triggered based on client input, this can lead to security
# issues (but not as severe as those might appear in the first place: keep in
# mind that only known file extensions are used). You should limit
# the possible formats you serve.
#
# This is possible with the +provides+ condition:
#
# get '/', :provides => [:html, :json, :xml, :atom] do
# respond_with :index, :name => 'example'
# end
#
# However, since you have to set +provides+ for every route, this extension
# adds an app global (class method) `respond_to`, that lets you define content
# types for all routes:
#
# respond_to :html, :json, :xml, :atom
# get('/a') { respond_with :index, :name => 'a' }
# get('/b') { respond_with :index, :name => 'b' }
#
# == Custom Types
#
# Use the +on+ method for defining actions for custom types:
#
# get '/' do
# respond_to do |f|
# f.xml { nokogiri :index }
# f.on('application/custom') { custom_action }
# f.on('text/*') { data.to_s }
# f.on('*/*') { "matches everything" }
# end
# end
#
# Definition order does not matter.
module RespondWith
class Format
def initialize(app)
@app, @map, @generic, @default = app, {}, {}, nil
end
def on(type, &block)
@app.settings.mime_types(type).each do |mime|
case mime
when '*/*' then @default = block
when /^([^\/]+)\/\*$/ then @generic[$1] = block
else @map[mime] = block
end
end
end
def finish
yield self if block_given?
mime_type = @app.content_type ||
@app.request.preferred_type(@map.keys) ||
@app.request.preferred_type ||
'text/html'
type = mime_type.split(/\s*;\s*/, 2).first
handlers = [@map[type], @generic[type[/^[^\/]+/]], @default].compact
handlers.each do |block|
if result = block.call(type)
@app.content_type mime_type
@app.halt result
end
end
@app.halt 406
end
def method_missing(method, *args, &block)
return super if args.any? or block.nil? or not @app.mime_type(method)
on(method, &block)
end
end
module Helpers
include Sinatra::JSON
def respond_with(template, object = nil, &block)
object, template = template, nil unless Symbol === template
format = Format.new(self)
format.on "*/*" do |type|
exts = settings.ext_map[type]
exts << :xml if type.end_with? '+xml'
if template
args = template_cache.fetch(type, template) { template_for(template, exts) }
if args.any?
locals = { :object => object }
locals.merge! object.to_hash if object.respond_to? :to_hash
renderer = args.first
options = args[1..-1] + [{:locals => locals}]
halt send(renderer, *options)
end
end
if object
exts.each do |ext|
halt json(object) if ext == :json
next unless object.respond_to? method = "to_#{ext}"
halt(*object.send(method))
end
end
false
end
format.finish(&block)
end
def respond_to(&block)
Format.new(self).finish(&block)
end
private
def template_for(name, exts)
# in production this is cached, so don't worry too much about runtime
possible = []
settings.template_engines[:all].each do |engine|
exts.each { |ext| possible << [engine, "#{name}.#{ext}"] }
end
exts.each do |ext|
settings.template_engines[ext].each { |e| possible << [e, name] }
end
possible.each do |engine, template|
# not exactly like Tilt[engine], but does not trigger a require
if Tilt.respond_to?(:mappings)
klass = Tilt.mappings[Tilt.normalize(engine)].first
else
klass = Tilt[engine]
end
find_template(settings.views, template, klass) do |file|
next unless File.exist? file
return settings.rendering_method(engine) << template.to_sym
end
end
[] # nil or false would not be cached
end
end
def remap_extensions
ext_map.clear
Rack::Mime::MIME_TYPES.each { |e,t| ext_map[t] << e[1..-1].to_sym }
ext_map['text/javascript'] << 'js'
ext_map['text/xml'] << 'xml'
end
def mime_type(*)
result = super
remap_extensions
result
end
def respond_to(*formats)
if formats.any?
@respond_to ||= []
@respond_to.concat formats
elsif @respond_to.nil? and superclass.respond_to? :respond_to
superclass.respond_to
else
@respond_to
end
end
def rendering_method(engine)
return [engine] if Sinatra::Templates.method_defined? engine
return [:mab] if engine.to_sym == :markaby
[:render, :engine]
end
private
def compile!(verb, path, block, options = {})
options[:provides] ||= respond_to if respond_to
super
end
def self.jrubyify(engs)
not_supported = [:markdown]
engs.keys.each do |key|
engs[key].collect! { |eng| (eng == :yajl) ? :json_pure : eng }
engs[key].delete_if { |eng| not_supported.include?(eng) }
end
engs
end
def self.engines
engines = {
:css => [:less, :sass, :scss],
:xml => [:builder, :nokogiri],
:js => [:coffee],
:html => [:erb, :erubis, :haml, :slim, :liquid, :radius, :mab,
:markdown, :textile, :rdoc],
:all => (Sinatra::Templates.instance_methods.map(&:to_sym) +
[:mab] - [:find_template, :markaby]),
:json => [:yajl],
}
engines.default = []
(defined? JRUBY_VERSION) ? jrubyify(engines) : engines
end
def self.registered(base)
base.set :ext_map, Hash.new { |h,k| h[k] = [] }
base.set :template_engines, engines
base.remap_extensions
base.helpers Helpers
end
end
register RespondWith
Delegator.delegate :respond_to
end
sinatra-contrib-1.4.7/lib/sinatra/test_helpers.rb 0000644 0000041 0000041 00000003704 12706205017 022113 0 ustar www-data www-data require 'sinatra/base'
require 'rack/test'
require 'rack'
require 'forwardable'
module Sinatra
Base.set :environment, :test
module TestHelpers
class Session < Rack::Test::Session
def global_env
@global_env ||= {}
end
private
def default_env
super.merge global_env
end
end
include Rack::Test::Methods
extend Forwardable
attr_accessor :settings
def_delegators :last_response, :body, :headers, :status, :errors
def_delegators :app, :configure, :set, :enable, :disable, :use, :helpers, :register
def_delegators :current_session, :env_for
def_delegators :rack_mock_session, :cookie_jar
def mock_app(base = Sinatra::Base, &block)
inner = nil
@app = Sinatra.new(base) do
inner = self
class_eval(&block)
end
@settings = inner
app
end
def app=(base)
@app = base
end
alias set_app app=
def app
@app ||= Class.new Sinatra::Base
Rack::Lint.new @app
end
unless method_defined? :options
def options(uri, params = {}, env = {}, &block)
env = env_for(uri, env.merge(:method => "OPTIONS", :params => params))
current_session.send(:process_request, uri, env, &block)
end
end
unless method_defined? :patch
def patch(uri, params = {}, env = {}, &block)
env = env_for(uri, env.merge(:method => "PATCH", :params => params))
current_session.send(:process_request, uri, env, &block)
end
end
def last_request?
last_request
true
rescue Rack::Test::Error
false
end
def session
return {} unless last_request?
raise Rack::Test::Error, "session not enabled for app" unless last_env["rack.session"] or app.session?
last_request.session
end
def last_env
last_request.env
end
def build_rack_test_session(name) # :nodoc:
Session.new rack_mock_session(name)
end
end
end
sinatra-contrib-1.4.7/lib/sinatra/multi_route.rb 0000644 0000041 0000041 00000004166 12706205017 021765 0 ustar www-data www-data require 'sinatra/base'
module Sinatra
# = Sinatra::MultiRoute
#
# Create multiple routes with one statement.
#
# == Usage
#
# Use this extension to create a handler for multiple routes:
#
# get '/foo', '/bar' do
# # ...
# end
#
# Or for multiple verbs:
#
# route :get, :post, '/' do
# # ...
# end
#
# Or for multiple verbs and multiple routes:
#
# route :get, :post, ['/foo', '/bar'] do
# # ...
# end
#
# Or even for custom verbs:
#
# route 'LIST', '/' do
# # ...
# end
#
# === Classic Application
#
# To use the extension in a classic application all you need to do is require
# it:
#
# require "sinatra"
# require "sinatra/multi_route"
#
# # Your classic application code goes here...
#
# === Modular Application
#
# To use the extension in a modular application you need to require it, and
# then, tell the application you will use it:
#
# require "sinatra/base"
# require "sinatra/multi_route"
#
# class MyApp < Sinatra::Base
# register Sinatra::MultiRoute
#
# # The rest of your modular application code goes here...
# end
#
module MultiRoute
def head(*args, &block) super(*route_args(args), &block) end
def delete(*args, &block) super(*route_args(args), &block) end
def get(*args, &block) super(*route_args(args), &block) end
def options(*args, &block) super(*route_args(args), &block) end
def patch(*args, &block) super(*route_args(args), &block) end
def post(*args, &block) super(*route_args(args), &block) end
def put(*args, &block) super(*route_args(args), &block) end
def route(*args, &block)
options = Hash === args.last ? args.pop : {}
routes = [*args.pop]
args.each do |verb|
verb = verb.to_s.upcase if Symbol === verb
routes.each do |route|
super(verb, route, options, &block)
end
end
end
private
def route_args(args)
options = Hash === args.last ? args.pop : {}
[args, options]
end
end
register MultiRoute
end
sinatra-contrib-1.4.7/lib/sinatra/contrib/ 0000755 0000041 0000041 00000000000 12706205017 020521 5 ustar www-data www-data sinatra-contrib-1.4.7/lib/sinatra/contrib/version.rb 0000644 0000041 0000041 00000000506 12706205017 022534 0 ustar www-data www-data module Sinatra
module Contrib
def self.version
VERSION
end
SIGNATURE = [1, 4, 7]
VERSION = SIGNATURE.join('.')
VERSION.extend Comparable
def VERSION.<=>(other)
other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
SIGNATURE <=> Array(other)
end
end
end
sinatra-contrib-1.4.7/lib/sinatra/contrib/all.rb 0000644 0000041 0000041 00000000101 12706205017 021606 0 ustar www-data www-data require 'sinatra/contrib'
Sinatra.register Sinatra::Contrib::All
sinatra-contrib-1.4.7/lib/sinatra/contrib/setup.rb 0000644 0000041 0000041 00000002135 12706205017 022207 0 ustar www-data www-data require 'sinatra/base'
require 'sinatra/contrib/version'
require 'backports'
module Sinatra
module Contrib
module Loader
def extensions
@extensions ||= {:helpers => [], :register => []}
end
def register(name, path = nil)
autoload name, path, :register
end
def helpers(name, path = nil)
autoload name, path, :helpers
end
def autoload(name, path = nil, method = nil)
path ||= "sinatra/#{name.to_s.underscore}"
extensions[method] << name if method
Sinatra.autoload(name, path)
end
def registered(base)
@extensions.each do |method, list|
list = list.map { |name| Sinatra.const_get name }
base.send(method, *list) unless base == ::Sinatra::Application
end
end
end
module Common
extend Loader
end
module Custom
extend Loader
end
module All
def self.registered(base)
base.register Common, Custom
end
end
extend Loader
def self.registered(base)
base.register Common, Custom
end
end
end
sinatra-contrib-1.4.7/lib/sinatra/link_header.rb 0000644 0000041 0000041 00000007234 12706205017 021661 0 ustar www-data www-data require 'sinatra/base'
module Sinatra
# = Sinatra::LinkHeader
#
# Sinatra::LinkHeader adds a set of helper methods to generate link
# HTML tags and their corresponding Link HTTP headers.
#
# == Usage
#
# Once you had set up the helpers in your application (see below), you will
# be able to call the following methods from inside your route handlers,
# filters and templates:
#
# +prefetch+::
# Sets the Link HTTP headers and returns HTML tags to prefetch the given
# resources.
#
# +stylesheet+::
# Sets the Link HTTP headers and returns HTML tags to use the given
# stylesheets.
#
# +link+::
# Sets the Link HTTP headers and returns the corresponding HTML tags
# for the given resources.
#
# +link_headers+::
# Returns the corresponding HTML tags for the current Link HTTP headers.
#
# === Classic Application
#
# In a classic application simply require the helpers, and start using them:
#
# require "sinatra"
# require "sinatra/link_header"
#
# # The rest of your classic application code goes here...
#
# === Modular Application
#
# In a modular application you need to require the helpers, and then tell
# the application you will use them:
#
# require "sinatra/base"
# require "sinatra/link_header"
#
# class MyApp < Sinatra::Base
# helpers Sinatra::LinkHeader
#
# # The rest of your modular application code goes here...
# end
#
module LinkHeader
##
# Sets Link HTTP header and returns HTML tags for telling the browser to
# prefetch given resources (only supported by Opera and Firefox at the
# moment).
def prefetch(*urls)
link(:prefetch, *urls)
end
##
# Sets Link HTTP header and returns HTML tags for using stylesheets.
def stylesheet(*urls)
urls << {} unless urls.last.respond_to? :to_hash
urls.last[:type] ||= mime_type(:css)
link(:stylesheet, *urls)
end
##
# Sets Link HTTP header and returns corresponding HTML tags.
#
# Example:
#
# # Sets header:
# # Link: ; rel="next"
# # Returns String:
# # ''
# link '/foo', :rel => :next
#
# # Multiple URLs
# link :stylesheet, '/a.css', '/b.css'
def link(*urls)
opts = urls.last.respond_to?(:to_hash) ? urls.pop : {}
opts[:rel] = urls.shift unless urls.first.respond_to? :to_str
options = opts.map { |k, v| " #{k}=#{v.to_s.inspect}" }
html_pattern = ""
http_pattern = ["<%s>", *options].join ";"
link = (response["Link"] ||= "")
urls.map do |url|
link << "\n" unless link.empty?
link << (http_pattern % url)
html_pattern % url
end.join "\n"
end
##
# Takes the current value of th Link header(s) and generates HTML tags
# from it.
#
# Example:
#
# get '/' do
# # You can of course use fancy helpers like #link, #stylesheet
# # or #prefetch
# response["Link"] = '; rel="next"'
# haml :some_page
# end
#
# __END__
#
# @@ layout
# %head= link_headers
# %body= yield
def link_headers
yield if block_given?
return "" unless response.include? "Link"
response["Link"].lines.map do |line|
url, *opts = line.split(';').map(&:strip)
""
end.join "\n"
end
def self.registered(base)
puts "WARNING: #{self} is a helpers module, not an extension."
end
end
helpers LinkHeader
end
sinatra-contrib-1.4.7/lib/sinatra/engine_tracking.rb 0000644 0000041 0000041 00000002700 12706205017 022534 0 ustar www-data www-data require 'sinatra/base'
module Sinatra
module EngineTracking
attr_reader :current_engine
def erb?
@current_engine == :erb
end
def erubis?
@current_engine == :erubis or
erb? && Tilt[:erb] == Tilt::ErubisTemplate
end
def haml?
@current_engine == :haml
end
def sass?
@current_engine == :sass
end
def scss?
@current_engine == :scss
end
def less?
@current_engine == :less
end
def builder?
@current_engine == :builder
end
def liquid?
@current_engine == :liquid
end
def markdown?
@current_engine == :markdown
end
def textile?
@current_engine == :textile
end
def rdoc?
@current_engine == :rdoc
end
def radius?
@current_engine == :radius
end
def markaby?
@current_engine == :markaby
end
def coffee?
@current_engine == :coffee
end
def nokogiri?
@current_engine == :nokogiri
end
def slim?
@current_engine == :slim
end
def creole?
@current_engine == :creole
end
def initialize(*)
@current_engine = :ruby
super
end
def with_engine(engine)
@current_engine, engine_was = engine.to_sym, @current_engine
yield
ensure
@current_engine = engine_was
end
private
def render(engine, *)
with_engine(engine) { super }
end
end
helpers EngineTracking
end
sinatra-contrib-1.4.7/lib/sinatra/config_file.rb 0000644 0000041 0000041 00000012342 12706205017 021654 0 ustar www-data www-data require 'sinatra/base'
require 'yaml'
require 'erb'
module Sinatra
# = Sinatra::ConfigFile
#
# Sinatra::ConfigFile is an extension that allows you to load the
# application's configuration from YAML files. It automatically detects if
# the files contains specific environment settings and it will use the
# corresponding to the current one.
#
# You can access those options through +settings+ within the application. If
# you try to get the value for a setting that hasn't been defined in the
# config file for the current environment, you will get whatever it was set
# to in the application.
#
# == Usage
#
# Once you have written your configurations to a YAML file you can tell the
# extension to load them. See below for more information about how these
# files are interpreted.
#
# For the examples, lets assume the following config.yml file:
#
# greeting: Welcome to my file configurable application
#
# === Classic Application
#
# require "sinatra"
# require "sinatra/config_file"
#
# config_file 'path/to/config.yml'
#
# get '/' do
# @greeting = settings.greeting
# haml :index
# end
#
# # The rest of your classic application code goes here...
#
# === Modular Application
#
# require "sinatra/base"
# require "sinatra/config_file"
#
# class MyApp < Sinatra::Base
# register Sinatra::ConfigFile
#
# config_file 'path/to/config.yml'
#
# get '/' do
# @greeting = settings.greeting
# haml :index
# end
#
# # The rest of your modular application code goes here...
# end
#
# === Config File Format
#
# In its most simple form this file is just a key-value list:
#
# foo: bar
# something: 42
# nested:
# a: 1
# b: 2
#
# But it also can provide specific environment configuration. There are two
# ways to do that: at the file level and at the settings level.
#
# At the settings level (e.g. in 'path/to/config.yml'):
#
# development:
# foo: development
# bar: bar
# test:
# foo: test
# bar: bar
# production:
# foo: production
# bar: bar
#
# Or at the file level:
#
# foo:
# development: development
# test: test
# production: production
# bar: bar
#
# In either case, settings.foo will return the environment name, and
# settings.bar will return "bar".
#
# Be aware that if you have a different environment, besides development,
# test and production, you will also need to adjust the +environments+
# setting, otherwise the settings will not load. For instance, when
# you also have a staging environment:
#
# set :environments, %w{development test production staging}
#
# If you wish to provide defaults that may be shared among all the environments,
# this can be done by using one of the existing environments as the default using
# the YAML alias, and then overwriting values in the other environments:
#
# development: &common_settings
# foo: 'foo'
# bar: 'bar'
#
# production:
# <<: *common_settings
# bar: 'baz' # override the default value
#
module ConfigFile
# When the extension is registered sets the +environments+ setting to the
# traditional environments: development, test and production.
def self.registered(base)
base.set :environments, %w[test production development]
end
# Loads the configuration from the YAML files whose +paths+ are passed as
# arguments, filtering the settings for the current environment. Note that
# these +paths+ can actually be globs.
def config_file(*paths)
Dir.chdir(root || '.') do
paths.each do |pattern|
Dir.glob(pattern) do |file|
$stderr.puts "loading config file '#{file}'" if logging?
document = IO.read(file)
document = ERB.new(document).result if file.split('.').include?('erb')
yaml = config_for_env(YAML.load(document)) || {}
yaml.each_pair do |key, value|
for_env = config_for_env(value)
set key, for_env unless value and for_env.nil? and respond_to? key
end
end
end
end
end
private
# Given a +hash+ with some application configuration it returns the
# settings applicable to the current environment. Note that this can only
# be done when all the keys of +hash+ are environment names included in the
# +environments+ setting (which is an Array of Strings). Also, the
# returned config is a indifferently accessible Hash, which means that you
# can get its values using Strings or Symbols as keys.
def config_for_env(hash)
if hash.respond_to? :keys and hash.keys.all? { |k| environments.include? k.to_s }
hash = hash[environment.to_s] || hash[environment.to_sym]
end
if hash.respond_to? :to_hash
indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
indifferent_hash.merge hash.to_hash
else
hash
end
end
end
register ConfigFile
Delegator.delegate :config_file
end
sinatra-contrib-1.4.7/lib/sinatra/content_for.rb 0000644 0000041 0000041 00000007320 12706205017 021730 0 ustar www-data www-data require 'sinatra/base'
require 'sinatra/capture'
module Sinatra
# = Sinatra::ContentFor
#
# Sinatra::ContentFor is a set of helpers that allows you to capture
# blocks inside views to be rendered later during the request. The most
# common use is to populate different parts of your layout from your view.
#
# The currently supported engines are: Erb, Erubis, Haml and Slim.
#
# == Usage
#
# You call +content_for+, generally from a view, to capture a block of markup
# giving it an identifier:
#
# # index.erb
# <% content_for :some_key do %>
# ...
# <% end %>
#
# Then, you call +yield_content+ with that identifier, generally from a
# layout, to render the captured block:
#
# # layout.erb
# <%= yield_content :some_key %>
#
# === Classic Application
#
# To use the helpers in a classic application all you need to do is require
# them:
#
# require "sinatra"
# require "sinatra/content_for"
#
# # Your classic application code goes here...
#
# === Modular Application
#
# To use the helpers in a modular application you need to require them, and
# then, tell the application you will use them:
#
# require "sinatra/base"
# require "sinatra/content_for"
#
# class MyApp < Sinatra::Base
# helpers Sinatra::ContentFor
#
# # The rest of your modular application code goes here...
# end
#
# == And How Is This Useful?
#
# For example, some of your views might need a few javascript tags and
# stylesheets, but you don't want to force this files in all your pages.
# Then you can put <%= yield_content :scripts_and_styles %> on your
# layout, inside the
tag, and each view can call content_for
# setting the appropriate set of tags that should be added to the layout.
#
module ContentFor
include Capture
# Capture a block of content to be rendered later. For example:
#
# <% content_for :head do %>
#
# <% end %>
#
# You can call +content_for+ multiple times with the same key
# (in the example +:head+), and when you render the blocks for
# that key all of them will be rendered, in the same order you
# captured them.
#
# Your blocks can also receive values, which are passed to them
# by yield_content
def content_for(key, &block)
content_blocks[key.to_sym] << capture_later(&block)
end
# Check if a block of content with the given key was defined. For
# example:
#
# <% content_for :head do %>
#
# <% end %>
#
# <% if content_for? :head %>
# content "head" was defined.
# <% end %>
def content_for?(key)
content_blocks[key.to_sym].any?
end
# Render the captured blocks for a given key. For example:
#
#
# Example
# <%= yield_content :head %>
#
#
# Would render everything you declared with content_for
# :head before closing the tag.
#
# You can also pass values to the content blocks by passing them
# as arguments after the key:
#
# <%= yield_content :head, 1, 2 %>
#
# Would pass 1 and 2 to all the blocks registered
# for :head.
def yield_content(key, *args)
content_blocks[key.to_sym].map { |b| capture(*args, &b) }.join
end
private
def content_blocks
@content_blocks ||= Hash.new {|h,k| h[k] = [] }
end
end
helpers ContentFor
end
sinatra-contrib-1.4.7/lib/sinatra/custom_logger.rb 0000644 0000041 0000041 00000002651 12706205017 022263 0 ustar www-data www-data module Sinatra
# = Sinatra::CustomLogger
#
# CustomLogger extension allows you to define your own logger instance
# using +logger+ setting. That logger then will be available
# as #logger helper method in your routes and views.
#
# == Usage
#
# === Classic Application
#
# To define your custom logger instance in a classic application:
#
# require 'sinatra'
# require 'sinatra/custom_logger'
# require 'logger'
#
# set :logger, Logger.new(STDOUT)
#
# get '/' do
# logger.info 'Some message' # STDOUT logger is used
# # Other code...
# end
#
# === Modular Application
#
# The same for modular application:
#
# require 'sinatra/base'
# require 'sinatra/custom_logger'
# require 'logger'
#
# class MyApp < Sinatra::Base
# helpers Sinatra::CustomLogger
#
# configure :development, :production do
# logger = Logger.new(File.open("#{root}/log/#{environment}.log", 'a'))
# logger.level = Logger::DEBUG if development?
# set :logger, logger
# end
#
# get '/' do
# logger.info 'Some message' # File-based logger is used
# # Other code...
# end
# end
#
module CustomLogger
def logger
if settings.respond_to?(:logger)
settings.logger
else
request.logger
end
end
end
helpers CustomLogger
end
sinatra-contrib-1.4.7/lib/sinatra/streaming.rb 0000644 0000041 0000041 00000013172 12706205017 021403 0 ustar www-data www-data require 'sinatra/base'
require 'backports'
module Sinatra
# = Sinatra::Streaming
#
# Sinatra 1.3 introduced the +stream+ helper. This addon improves the
# streaming API by making the stream object imitate an IO object, turning
# it into a real Deferrable and making the body play nicer with middleware
# unaware of streaming.
#
# == IO-like behavior
#
# This is useful when passing the stream object to a library expecting an
# IO or StringIO object.
#
# get '/' do
# stream do |out|
# out.puts "Hello World!", "How are you?"
# out.write "Written #{out.pos} bytes so far!\n"
# out.putc(65) unless out.closed?
# out.flush
# end
# end
#
# == Better Middleware Handling
#
# Blocks passed to #map! or #map will actually be applied when streaming
# takes place (as you might have suspected, #map! applies modifications
# to the current body, while #map creates a new one):
#
# class StupidMiddleware
# def initialize(app) @app = app end
#
# def call(env)
# status, headers, body = @app.call(env)
# body.map! { |e| e.upcase }
# [status, headers, body]
# end
# end
#
# use StupidMiddleware
#
# get '/' do
# stream do |out|
# out.puts "still"
# sleep 1
# out.puts "streaming"
# end
# end
#
# Even works if #each is used to generate an Enumerator:
#
# def call(env)
# status, headers, body = @app.call(env)
# body = body.each.map { |s| s.upcase }
# [status, headers, body]
# end
#
# Note that both examples violate the Rack specification.
#
# == Setup
#
# In a classic application:
#
# require "sinatra"
# require "sinatra/streaming"
#
# In a modular application:
#
# require "sinatra/base"
# require "sinatra/streaming"
#
# class MyApp < Sinatra::Base
# helpers Sinatra::Streaming
# end
module Streaming
def stream(*)
stream = super
stream.extend Stream
stream.app = self
env['async.close'].callback { stream.close } if env.key? 'async.close'
stream
end
module Stream
attr_accessor :app, :lineno, :pos, :transformer, :closed
alias tell pos
alias closed? closed
def self.extended(obj)
obj.closed, obj.lineno, obj.pos = false, 0, 0
obj.callback { obj.closed = true }
obj.errback { obj.closed = true }
end
def <<(data)
raise IOError, 'not opened for writing' if closed?
data = data.to_s
data = @transformer[data] if @transformer
@pos += data.bytesize
super(data)
end
def each
# that way body.each.map { ... } works
return self unless block_given?
super
end
def map(&block)
# dup would not copy the mixin
clone.map!(&block)
end
def map!(&block)
if @transformer
inner, outer = @transformer, block
block = proc { |value| outer[inner[value]] }
end
@transformer = block
self
end
def write(data)
self << data
data.to_s.bytesize
end
alias syswrite write
alias write_nonblock write
def print(*args)
args.each { |arg| self << arg }
nil
end
def printf(format, *args)
print(format.to_s % args)
end
def putc(c)
print c.chr
end
def puts(*args)
args.each { |arg| self << "#{arg}\n" }
nil
end
def close_read
raise IOError, "closing non-duplex IO for reading"
end
def closed_read?
true
end
def closed_write?
closed?
end
def external_encoding
Encoding.find settings.default_encoding
rescue NameError
settings.default_encoding
end
def closed?
@closed
end
def settings
app.settings
end
def rewind
@pos = @lineno = 0
end
def not_open_for_reading(*)
raise IOError, "not opened for reading"
end
alias bytes not_open_for_reading
alias eof? not_open_for_reading
alias eof not_open_for_reading
alias getbyte not_open_for_reading
alias getc not_open_for_reading
alias gets not_open_for_reading
alias read not_open_for_reading
alias read_nonblock not_open_for_reading
alias readbyte not_open_for_reading
alias readchar not_open_for_reading
alias readline not_open_for_reading
alias readlines not_open_for_reading
alias readpartial not_open_for_reading
alias sysread not_open_for_reading
alias ungetbyte not_open_for_reading
alias ungetc not_open_for_reading
private :not_open_for_reading
def enum_not_open_for_reading(*)
not_open_for_reading if block_given?
enum_for(:not_open_for_reading)
end
alias chars enum_not_open_for_reading
alias each_line enum_not_open_for_reading
alias each_byte enum_not_open_for_reading
alias each_char enum_not_open_for_reading
alias lines enum_not_open_for_reading
undef enum_not_open_for_reading
def dummy(*) end
alias flush dummy
alias fsync dummy
alias internal_encoding dummy
alias pid dummy
undef dummy
def seek(*)
0
end
alias sysseek seek
def sync
true
end
def tty?
false
end
alias isatty tty?
end
end
helpers Streaming
end
sinatra-contrib-1.4.7/lib/sinatra/extension.rb 0000644 0000041 0000041 00000005104 12706205017 021422 0 ustar www-data www-data require 'sinatra/base'
require 'backports/basic_object' unless defined? BasicObject
module Sinatra
# = Sinatra::Extension
#
# Sinatra::Extension is a mixin that provides some syntactic sugar
# for your extensions. It allows you to call almost any
# Sinatra::Base method directly inside your extension
# module. This means you can use +get+ to define a route, +before+
# to define a before filter, +set+ to define a setting and so on.
#
# Is important to be aware that this mixin remembers the method calls you
# make, and then, when your extension is registered, replays them on the
# Sinatra application that has been extended. In order to do that, it
# defines a registered method, so, if your extension defines one
# too, remember to call +super+.
#
# == Usage
#
# Just require the mixin and extend your extension with it:
#
# require 'sinatra/extension'
#
# module MyExtension
# extend Sinatra::Extension
#
# # set some settings for development
# configure :development do
# set :reload_stuff, true
# end
#
# # define a route
# get '/' do
# 'Hello World'
# end
#
# # The rest of your extension code goes here...
# end
#
# You can also create an extension with the +new+ method:
#
# MyExtension = Sinatra::Extension.new do
# # Your extension code goes here...
# end
#
# This is useful when you just want to pass a block to
# Sinatra::Base.register.
module Extension
def self.new(&block)
ext = Module.new.extend(self)
ext.class_eval(&block)
ext
end
def settings
self
end
def configure(*args, &block)
record(:configure, *args) { |c| c.instance_exec(c, &block) }
end
def registered(base = nil, &block)
base ? replay(base) : record(:class_eval, &block)
end
private
def record(method, *args, &block)
recorded_methods << [method, args, block]
end
def replay(object)
recorded_methods.each { |m, a, b| object.send(m, *a, &b) }
end
def recorded_methods
@recorded_methods ||= []
end
def method_missing(method, *args, &block)
return super unless Sinatra::Base.respond_to? method
record(method, *args, &block)
DontCall.new(method)
end
class DontCall < BasicObject
def initialize(method) @method = method end
def method_missing(*) fail "not supposed to use result of #@method!" end
def inspect; "#<#{self.class}: #{@method}>" end
end
end
end
sinatra-contrib-1.4.7/lib/sinatra/cookies.rb 0000644 0000041 0000041 00000015602 12706205017 021046 0 ustar www-data www-data require 'sinatra/base'
require 'backports'
module Sinatra
# = Sinatra::Cookies
#
# Easy way to deal with cookies
#
# == Usage
#
# Allows you to read cookies:
#
# get '/' do
# "value: #{cookies[:something]}"
# end
#
# And of course to write cookies:
#
# get '/set' do
# cookies[:something] = 'foobar'
# redirect to('/')
# end
#
# And generally behaves like a hash:
#
# get '/demo' do
# cookies.merge! 'foo' => 'bar', 'bar' => 'baz'
# cookies.keep_if { |key, value| key.start_with? 'b' }
# foo, bar = cookies.values_at 'foo', 'bar'
# "size: #{cookies.length}"
# end
#
# === Classic Application
#
# In a classic application simply require the helpers, and start using them:
#
# require "sinatra"
# require "sinatra/cookies"
#
# # The rest of your classic application code goes here...
#
# === Modular Application
#
# In a modular application you need to require the helpers, and then tell
# the application to use them:
#
# require "sinatra/base"
# require "sinatra/cookies"
#
# class MyApp < Sinatra::Base
# helpers Sinatra::Cookies
#
# # The rest of your modular application code goes here...
# end
#
module Cookies
class Jar
include Enumerable
attr_reader :options
def initialize(app)
@response_string = nil
@response_hash = {}
@response = app.response
@request = app.request
@deleted = []
@options = {
:path => @request.script_name.to_s.empty? ? '/' : @request.script_name,
:domain => @request.host == 'localhost' ? nil : @request.host,
:secure => @request.secure?,
:httponly => true
}
if app.settings.respond_to? :cookie_options
@options.merge! app.settings.cookie_options
end
end
def ==(other)
other.respond_to? :to_hash and to_hash == other.to_hash
end
def [](key)
response_cookies[key.to_s] || request_cookies[key.to_s]
end
def []=(key, value)
@response.set_cookie key.to_s, @options.merge(:value => value)
end
def assoc(key)
to_hash.assoc(key.to_s)
end if Hash.method_defined? :assoc
def clear
each_key { |k| delete(k) }
end
def compare_by_identity?
false
end
def default
nil
end
alias default_proc default
def delete(key)
result = self[key]
@response.delete_cookie(key.to_s, @options)
result
end
def delete_if
return enum_for(__method__) unless block_given?
each { |k, v| delete(k) if yield(k, v) }
self
end
def each(&block)
return enum_for(__method__) unless block_given?
to_hash.each(&block)
end
def each_key(&block)
return enum_for(__method__) unless block_given?
to_hash.each_key(&block)
end
alias each_pair each
def each_value(&block)
return enum_for(__method__) unless block_given?
to_hash.each_value(&block)
end
def empty?
to_hash.empty?
end
def fetch(key, &block)
response_cookies.fetch(key.to_s) do
request_cookies.fetch(key.to_s, &block)
end
end
def flatten
to_hash.flatten
end if Hash.method_defined? :flatten
def has_key?(key)
response_cookies.has_key? key.to_s or request_cookies.has_key? key.to_s
end
def has_value?(value)
response_cookies.has_value? value or request_cookies.has_value? value
end
def hash
to_hash.hash
end
alias include? has_key?
alias member? has_key?
def index(value)
warn "Hash#index is deprecated; use Hash#key" if RUBY_VERSION > '1.9'
key(value)
end
def inspect
"<##{self.class}: #{to_hash.inspect[1..-2]}>"
end
def invert
to_hash.invert
end if Hash.method_defined? :invert
def keep_if
return enum_for(__method__) unless block_given?
delete_if { |*a| not yield(*a) }
end
def key(value)
to_hash.key(value)
end
alias key? has_key?
def keys
to_hash.keys
end
def length
to_hash.length
end
def merge(other, &block)
to_hash.merge(other, &block)
end
def merge!(other)
other.each_pair do |key, value|
if block_given? and include? key
self[key] = yield(key.to_s, self[key], value)
else
self[key] = value
end
end
end
def rassoc(value)
to_hash.rassoc(value)
end
def rehash
response_cookies.rehash
request_cookies.rehash
self
end
def reject(&block)
return enum_for(__method__) unless block_given?
to_hash.reject(&block)
end
alias reject! delete_if
def replace(other)
select! { |k, v| other.include?(k) or other.include?(k.to_s) }
merge! other
end
def select(&block)
return enum_for(__method__) unless block_given?
to_hash.select(&block)
end
alias select! keep_if if Hash.method_defined? :select!
def shift
key, value = to_hash.shift
delete(key)
[key, value]
end
alias size length
def sort(&block)
to_hash.sort(&block)
end if Hash.method_defined? :sort
alias store []=
def to_hash
request_cookies.merge(response_cookies)
end
def to_a
to_hash.to_a
end
def to_s
to_hash.to_s
end
alias update merge!
alias value? has_value?
def values
to_hash.values
end
def values_at(*list)
list.map { |k| self[k] }
end
private
def warn(message)
super "#{caller.first[/^[^:]:\d+:/]} warning: #{message}"
end
def deleted
parse_response
@deleted
end
def response_cookies
parse_response
@response_hash
end
def parse_response
string = @response['Set-Cookie']
return if @response_string == string
hash = {}
string.each_line do |line|
key, value = line.split(';', 2).first.to_s.split('=', 2)
next if key.nil?
key = Rack::Utils.unescape(key)
if line =~ /expires=Thu, 01[-\s]Jan[-\s]1970/
@deleted << key
else
@deleted.delete key
hash[key] = value
end
end
@response_hash.replace hash
@response_string = string
end
def request_cookies
@request.cookies.reject { |key, value| deleted.include? key }
end
end
def cookies
@cookies ||= Jar.new(self)
end
end
helpers Cookies
end
sinatra-contrib-1.4.7/sinatra-contrib.gemspec 0000644 0000041 0000041 00000015766 12706205017 021335 0 ustar www-data www-data # -*- encoding: utf-8 -*-
# Run `rake sinatra-contrib.gemspec` to update the gemspec.
require File.expand_path('../lib/sinatra/contrib/version', __FILE__)
Gem::Specification.new do |s|
s.name = "sinatra-contrib"
s.version = Sinatra::Contrib::VERSION
s.description = "Collection of useful Sinatra extensions"
s.homepage = "http://github.com/sinatra/sinatra-contrib"
s.license = "MIT"
s.summary = s.description
# generated from git shortlog -sn
s.authors = [
"Konstantin Haase",
"Zachary Scott",
"Gabriel Andretta",
"Trevor Bramble",
"Katrina Owen",
"Ashley Williams",
"Nicolas Sanguinetti",
"Hrvoje Šimić",
"Masahiro Fujiwara",
"Rafael Magana",
"Vipul A M",
"ashley williams",
"Jack Chu",
"Sumeet Singh",
"Ilya Shindyapin",
"lest",
"Jake Worth",
"Kashyap",
"Matt Lyon",
"Matthew Conway",
"Meck",
"Michi Huber",
"Nic Benders",
"Patricio Mac Adden",
"Reed Lipman",
"Samy Dindane",
"Sergey Nartimov",
"Thibaut Sacreste",
"Uchio KONDO",
"Will Bailey",
"mono",
"Adrian Pacała",
"undr",
"Aish",
"Alexey Chernenkov",
"Andrew Crump",
"Anton Davydov",
"Bo Jeanes",
"David Asabina",
"Eliot Shepard",
"Eric Marden",
"Gray Manley",
"Guillaume Bouteille",
"Jamie Hodge",
"Julie Ng",
"Koichi Sasada",
"Kyle Lacy",
"Lars Vonk",
"Martin Frost",
"Mathieu Allaire"
]
# generated from git shortlog -sne
s.email = [
"konstantin.mailinglists@googlemail.com",
"ohhgabriel@gmail.com",
"inbox@trevorbramble.com",
"e@zzak.io",
"zachary@zacharyscott.net",
"katrina.owen@gmail.com",
"ashley@bocoup.com",
"contacto@nicolassanguinetti.info",
"shime.ferovac@gmail.com",
"raf.magana@gmail.com",
"m-fujiwara@axsh.net",
"vipulnsward@gmail.com",
"konstantin.haase@gmail.com",
"jack@jackchu.com",
"ashley666ashley@gmail.com",
"ilya@shindyapin.com",
"just.lest@gmail.com",
"kashyap.kmbc@gmail.com",
"ortuna@gmail.com",
"tbramble@chef.io",
"jworth@prevailhs.com",
"mail@zzak.io",
"nic@newrelic.com",
"patriciomacadden@gmail.com",
"rmlipman@gmail.com",
"samy@dindane.com",
"just.lest@gmail.com",
"thibaut.sacreste@gmail.com",
"udzura@udzura.jp",
"will.bailey@gmail.com",
"mono@mono0x.net",
"altpacala@gmail.com",
"undr@yandex.ru",
"aisha.fenton@visfleet.com",
"laise@pisem.net",
"andrew.crump@ieee.org",
"antondavydov.o@gmail.com",
"me@bjeanes.com",
"david@supr.nu",
"eshepard@slower.net",
"eric.marden@gmail.com",
"g.manley@tukaiz.com",
"duffman@via.ecp.fr",
"jamiehodge@me.com",
"uxjulie@gmail.com",
"ko1@atdot.net",
"kylewlacy@me.com",
"lars.vonk@gmail.com",
"blame@kth.se",
"mathieuallaire@gmail.com",
"matt@flowerpowered.com",
"himself@mattonrails.com",
"yesmeck@gmail.com",
"michi.huber@gmail.com"
]
# generated from git ls-files
s.files = [
"LICENSE",
"README.md",
"Rakefile",
"ideas.md",
"lib/sinatra/capture.rb",
"lib/sinatra/config_file.rb",
"lib/sinatra/content_for.rb",
"lib/sinatra/contrib.rb",
"lib/sinatra/contrib/all.rb",
"lib/sinatra/contrib/setup.rb",
"lib/sinatra/contrib/version.rb",
"lib/sinatra/cookies.rb",
"lib/sinatra/custom_logger.rb",
"lib/sinatra/decompile.rb",
"lib/sinatra/engine_tracking.rb",
"lib/sinatra/extension.rb",
"lib/sinatra/json.rb",
"lib/sinatra/link_header.rb",
"lib/sinatra/multi_route.rb",
"lib/sinatra/namespace.rb",
"lib/sinatra/reloader.rb",
"lib/sinatra/respond_with.rb",
"lib/sinatra/streaming.rb",
"lib/sinatra/test_helpers.rb",
"sinatra-contrib.gemspec",
"spec/capture_spec.rb",
"spec/config_file/key_value.yml",
"spec/config_file/key_value.yml.erb",
"spec/config_file/key_value_override.yml",
"spec/config_file/missing_env.yml",
"spec/config_file/with_envs.yml",
"spec/config_file/with_nested_envs.yml",
"spec/config_file_spec.rb",
"spec/content_for/different_key.erb",
"spec/content_for/different_key.erubis",
"spec/content_for/different_key.haml",
"spec/content_for/different_key.slim",
"spec/content_for/footer.erb",
"spec/content_for/footer.erubis",
"spec/content_for/footer.haml",
"spec/content_for/footer.slim",
"spec/content_for/layout.erb",
"spec/content_for/layout.erubis",
"spec/content_for/layout.haml",
"spec/content_for/layout.slim",
"spec/content_for/multiple_blocks.erb",
"spec/content_for/multiple_blocks.erubis",
"spec/content_for/multiple_blocks.haml",
"spec/content_for/multiple_blocks.slim",
"spec/content_for/multiple_yields.erb",
"spec/content_for/multiple_yields.erubis",
"spec/content_for/multiple_yields.haml",
"spec/content_for/multiple_yields.slim",
"spec/content_for/passes_values.erb",
"spec/content_for/passes_values.erubis",
"spec/content_for/passes_values.haml",
"spec/content_for/passes_values.slim",
"spec/content_for/same_key.erb",
"spec/content_for/same_key.erubis",
"spec/content_for/same_key.haml",
"spec/content_for/same_key.slim",
"spec/content_for/takes_values.erb",
"spec/content_for/takes_values.erubis",
"spec/content_for/takes_values.haml",
"spec/content_for/takes_values.slim",
"spec/content_for_spec.rb",
"spec/cookies_spec.rb",
"spec/custom_logger_spec.rb",
"spec/decompile_spec.rb",
"spec/extension_spec.rb",
"spec/json_spec.rb",
"spec/link_header_spec.rb",
"spec/multi_route_spec.rb",
"spec/namespace/foo.erb",
"spec/namespace/nested/foo.erb",
"spec/namespace_spec.rb",
"spec/okjson.rb",
"spec/reloader/app.rb.erb",
"spec/reloader_spec.rb",
"spec/respond_with/bar.erb",
"spec/respond_with/bar.json.erb",
"spec/respond_with/baz.yajl",
"spec/respond_with/foo.html.erb",
"spec/respond_with/not_html.sass",
"spec/respond_with_spec.rb",
"spec/spec_helper.rb",
"spec/streaming_spec.rb"
]
s.add_dependency "sinatra", "~> 1.4.0"
s.add_dependency "backports", ">= 2.0"
s.add_dependency "tilt", ">= 1.3", "< 3"
s.add_dependency "rack-test"
s.add_dependency "rack-protection"
s.add_dependency "multi_json"
s.add_development_dependency "rspec", "~> 2.3"
s.add_development_dependency "haml"
s.add_development_dependency "erubis"
s.add_development_dependency "slim"
s.add_development_dependency "less"
s.add_development_dependency "sass"
s.add_development_dependency "builder"
s.add_development_dependency "liquid"
s.add_development_dependency "redcarpet"
s.add_development_dependency "RedCloth"
s.add_development_dependency "asciidoctor"
s.add_development_dependency "radius"
s.add_development_dependency "coffee-script"
s.add_development_dependency "nokogiri"
s.add_development_dependency "creole"
s.add_development_dependency "wikicloth"
s.add_development_dependency "markaby"
s.add_development_dependency "rake", "< 11"
end
sinatra-contrib-1.4.7/LICENSE 0000644 0000041 0000041 00000002137 12706205017 015662 0 ustar www-data www-data The MIT License (MIT)
Copyright (c) 2008-2011 Nicolas Sanguinetti, entp.com, Konstantin Haase
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.
sinatra-contrib-1.4.7/README.md 0000644 0000041 0000041 00000007240 12706205017 016134 0 ustar www-data www-data [](http://travis-ci.org/sinatra/sinatra-contrib)
Collection of common Sinatra extensions, semi-officially supported.
# Goals
* For every future Sinatra release, have at least one fully compatible release
* High code quality, high test coverage
* Include plugins people usually ask for a lot
# Included extensions
## Common Extensions
These are common extension which will not add significant overhead or change any
behavior of already existing APIs. They do not add any dependencies not already
installed with this gem.
Currently included:
* `sinatra/capture`: Let's you capture the content of blocks in templates.
* `sinatra/config_file`: Allows loading configuration from yaml files.
* `sinatra/content_for`: Adds Rails-style `content_for` helpers to Haml, Erb,
Erubis and Slim.
* `sinatra/cookies`: A `cookies` helper for reading and writing cookies.
* `sinatra/engine_tracking`: Adds methods like `haml?` that allow helper
methods to check whether they are called from within a template.
* `sinatra/json`: Adds a `#json` helper method to return JSON documents.
* `sinatra/link_header`: Helpers for generating `link` HTML tags and
corresponding `Link` HTTP headers. Adds `link`, `stylesheet` and `prefetch`
helper methods.
* `sinatra/multi_route`: Adds ability to define one route block for multiple
routes and multiple or custom HTTP verbs.
* `sinatra/namespace`: Adds namespace support to Sinatra.
* `sinatra/respond_with`: Choose action and/or template automatically
depending on the incoming request. Adds helpers `respond_to` and
`respond_with`.
* `sinatra/custom_logger`: This extension allows you to define your own
logger instance using +logger+ setting. That logger then will
be available as #logger helper method in your routes and views.
## Custom Extensions
These extensions may add additional dependencies and enhance the behavior of the
existing APIs.
Currently included:
* `sinatra/decompile`: Recreates path patterns from Sinatra's internal data
structures (used by other extensions).
* `sinatra/reloader`: Automatically reloads Ruby files on code changes.
## Other Tools
* `sinatra/extension`: Mixin for writing your own Sinatra extensions.
* `sinatra/test_helpers`: Helper methods to ease testing your Sinatra
application. Partly extracted from Sinatra. Testing framework agnostic
# Installation
Add `gem 'sinatra-contrib'` to *Gemfile*, then execute `bundle install`.
If you don't use Bundler, install the gem manually by executing `gem install sinatra-contrib` in your command line.
# Usage
## Classic Style
A single extension (example: sinatra-content-for):
``` ruby
require 'sinatra'
require 'sinatra/content_for'
```
Common extensions:
``` ruby
require 'sinatra'
require 'sinatra/contrib'
```
All extensions:
``` ruby
require 'sinatra'
require 'sinatra/contrib/all'
```
## Modular Style
A single extension (example: sinatra-content-for):
``` ruby
require 'sinatra/base'
require 'sinatra/content_for'
require 'sinatra/namespace'
class MyApp < Sinatra::Base
# Note: Some modules are extensions, some helpers, see the specific
# documentation or the source
helpers Sinatra::ContentFor
register Sinatra::Namespace
end
```
Common extensions:
``` ruby
require 'sinatra/base'
require 'sinatra/contrib'
class MyApp < Sinatra::Base
register Sinatra::Contrib
end
```
All extensions:
``` ruby
require 'sinatra/base'
require 'sinatra/contrib/all'
class MyApp < Sinatra::Base
register Sinatra::Contrib
end
```
## Documentation
For more info check the [official docs](http://www.sinatrarb.com/contrib/) and
[api docs](http://rubydoc.info/gems/sinatra-contrib/1.4.0/frames).