pirj-sinatra-contrib 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.md +135 -0
- data/Rakefile +61 -0
- data/ideas.md +29 -0
- data/lib/sinatra/capture.rb +42 -0
- data/lib/sinatra/config_file.rb +151 -0
- data/lib/sinatra/content_for.rb +111 -0
- data/lib/sinatra/contrib.rb +39 -0
- data/lib/sinatra/contrib/all.rb +2 -0
- data/lib/sinatra/contrib/setup.rb +53 -0
- data/lib/sinatra/contrib/version.rb +45 -0
- data/lib/sinatra/decompile.rb +113 -0
- data/lib/sinatra/engine_tracking.rb +96 -0
- data/lib/sinatra/extension.rb +95 -0
- data/lib/sinatra/json.rb +134 -0
- data/lib/sinatra/link_header.rb +132 -0
- data/lib/sinatra/namespace.rb +282 -0
- data/lib/sinatra/reloader.rb +384 -0
- data/lib/sinatra/respond_with.rb +245 -0
- data/lib/sinatra/streaming.rb +267 -0
- data/lib/sinatra/test_helpers.rb +87 -0
- data/sinatra-contrib.gemspec +121 -0
- data/spec/capture_spec.rb +80 -0
- data/spec/config_file/key_value.yml +6 -0
- data/spec/config_file/missing_env.yml +4 -0
- data/spec/config_file/with_envs.yml +7 -0
- data/spec/config_file/with_nested_envs.yml +11 -0
- data/spec/config_file_spec.rb +44 -0
- data/spec/content_for/different_key.erb +1 -0
- data/spec/content_for/different_key.erubis +1 -0
- data/spec/content_for/different_key.haml +2 -0
- data/spec/content_for/different_key.slim +2 -0
- data/spec/content_for/layout.erb +1 -0
- data/spec/content_for/layout.erubis +1 -0
- data/spec/content_for/layout.haml +1 -0
- data/spec/content_for/layout.slim +1 -0
- data/spec/content_for/multiple_blocks.erb +4 -0
- data/spec/content_for/multiple_blocks.erubis +4 -0
- data/spec/content_for/multiple_blocks.haml +8 -0
- data/spec/content_for/multiple_blocks.slim +8 -0
- data/spec/content_for/multiple_yields.erb +3 -0
- data/spec/content_for/multiple_yields.erubis +3 -0
- data/spec/content_for/multiple_yields.haml +3 -0
- data/spec/content_for/multiple_yields.slim +3 -0
- data/spec/content_for/passes_values.erb +1 -0
- data/spec/content_for/passes_values.erubis +1 -0
- data/spec/content_for/passes_values.haml +1 -0
- data/spec/content_for/passes_values.slim +1 -0
- data/spec/content_for/same_key.erb +1 -0
- data/spec/content_for/same_key.erubis +1 -0
- data/spec/content_for/same_key.haml +2 -0
- data/spec/content_for/same_key.slim +2 -0
- data/spec/content_for/takes_values.erb +1 -0
- data/spec/content_for/takes_values.erubis +1 -0
- data/spec/content_for/takes_values.haml +3 -0
- data/spec/content_for/takes_values.slim +3 -0
- data/spec/content_for_spec.rb +201 -0
- data/spec/decompile_spec.rb +44 -0
- data/spec/extension_spec.rb +33 -0
- data/spec/json_spec.rb +115 -0
- data/spec/link_header_spec.rb +100 -0
- data/spec/namespace/foo.erb +1 -0
- data/spec/namespace/nested/foo.erb +1 -0
- data/spec/namespace_spec.rb +623 -0
- data/spec/okjson.rb +581 -0
- data/spec/reloader/app.rb.erb +40 -0
- data/spec/reloader_spec.rb +441 -0
- data/spec/respond_with/bar.erb +1 -0
- data/spec/respond_with/bar.json.erb +1 -0
- data/spec/respond_with/foo.html.erb +1 -0
- data/spec/respond_with/not_html.sass +2 -0
- data/spec/respond_with_spec.rb +289 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/streaming_spec.rb +436 -0
- metadata +252 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'backports'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
|
7
|
+
# = Sinatra::Streaming
|
8
|
+
#
|
9
|
+
# Sinatra 1.3 introduced the +stream+ helper. This addon improves the
|
10
|
+
# streaming API by making the stream object immitate an IO object, turing
|
11
|
+
# it into a real Deferrable and making the body play nicer with middleware
|
12
|
+
# unaware of streaming.
|
13
|
+
#
|
14
|
+
# == IO-like behavior
|
15
|
+
#
|
16
|
+
# This is useful when passing the stream object to a library expecting an
|
17
|
+
# IO or StringIO object.
|
18
|
+
#
|
19
|
+
# get '/' do
|
20
|
+
# stream do |out|
|
21
|
+
# out.puts "Hello World!", "How are you?"
|
22
|
+
# out.write "Written #{out.pos} bytes so far!\n"
|
23
|
+
# out.putc(65) unless out.closed?
|
24
|
+
# out.flush
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# == Proper Deferrable
|
29
|
+
#
|
30
|
+
# Handy when using EventMachine.
|
31
|
+
#
|
32
|
+
# list = []
|
33
|
+
#
|
34
|
+
# get '/' do
|
35
|
+
# stream(false) do |out|
|
36
|
+
# list << out
|
37
|
+
# out.callback { list.delete out }
|
38
|
+
# out.errback do
|
39
|
+
# logger.warn "lost connection"
|
40
|
+
# list.delete out
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# == Better Middleware Handling
|
46
|
+
#
|
47
|
+
# Blocks passed to #map! or #map will actually be applied while streaming
|
48
|
+
# (as you might suspect, #map! applies modifications to the current body,
|
49
|
+
# #map creates a new one):
|
50
|
+
#
|
51
|
+
# class StupidMiddleware
|
52
|
+
# def initialize(app) @app = app end
|
53
|
+
#
|
54
|
+
# def call(env)
|
55
|
+
# status, headers, body = @app.call(env)
|
56
|
+
# body.map! { |e| e.upcase }
|
57
|
+
# [status, headers, body]
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# use StupidMiddleware
|
62
|
+
#
|
63
|
+
# get '/' do
|
64
|
+
# stream do |out|
|
65
|
+
# out.puts "still"
|
66
|
+
# sleep 1
|
67
|
+
# out.puts "streaming"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# Even works if #each is used to generate an Enumerator:
|
72
|
+
#
|
73
|
+
# def call(env)
|
74
|
+
# status, headers, body = @app.call(env)
|
75
|
+
# body = body.each.map { |s| s.upcase }
|
76
|
+
# [status, headers, body]
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# Note that both examples violate the Rack specification.
|
80
|
+
#
|
81
|
+
# == Setup
|
82
|
+
#
|
83
|
+
# In a classic application:
|
84
|
+
#
|
85
|
+
# require "sinatra"
|
86
|
+
# require "sinatra/streaming"
|
87
|
+
#
|
88
|
+
# In a modular application:
|
89
|
+
#
|
90
|
+
# require "sinatra/base"
|
91
|
+
# require "sinatra/streaming"
|
92
|
+
#
|
93
|
+
# class MyApp < Sinatra::Base
|
94
|
+
# helpers Streaming
|
95
|
+
# end
|
96
|
+
module Streaming
|
97
|
+
def stream(*)
|
98
|
+
stream = super
|
99
|
+
stream.extend Stream
|
100
|
+
stream.app = self
|
101
|
+
env['async.close'].callback { stream.close } if env.key? 'async.close'
|
102
|
+
stream
|
103
|
+
end
|
104
|
+
|
105
|
+
module Stream
|
106
|
+
include EventMachine::Deferrable
|
107
|
+
|
108
|
+
attr_accessor :app, :lineno, :pos, :transformer, :closed
|
109
|
+
alias tell pos
|
110
|
+
alias closed? closed
|
111
|
+
|
112
|
+
def self.extended(obj)
|
113
|
+
obj.closed, obj.lineno, obj.pos = false, 0, 0
|
114
|
+
obj.callback { obj.closed = true }
|
115
|
+
obj.errback { obj.closed = true }
|
116
|
+
end
|
117
|
+
|
118
|
+
def <<(data)
|
119
|
+
raise IOError, 'not opened for writing' if closed?
|
120
|
+
data = data.to_s
|
121
|
+
data = @transformer[data] if @transformer
|
122
|
+
@pos += data.bytesize
|
123
|
+
super(data)
|
124
|
+
end
|
125
|
+
|
126
|
+
def each
|
127
|
+
# that way body.each.map { ... } works
|
128
|
+
return self unless block_given?
|
129
|
+
super
|
130
|
+
end
|
131
|
+
|
132
|
+
def map(&block)
|
133
|
+
# dup would not copy the mixin
|
134
|
+
clone.map!(&block)
|
135
|
+
end
|
136
|
+
|
137
|
+
def map!(&block)
|
138
|
+
if @transformer
|
139
|
+
inner, outer = @transformer, block
|
140
|
+
block = proc { |value| outer[inner[value]] }
|
141
|
+
end
|
142
|
+
@transformer = block
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def write(data)
|
147
|
+
self << data
|
148
|
+
data.to_s.bytesize
|
149
|
+
end
|
150
|
+
|
151
|
+
alias syswrite write
|
152
|
+
alias write_nonblock write
|
153
|
+
|
154
|
+
def print(*args)
|
155
|
+
args.each { |arg| self << arg }
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def printf(format, *args)
|
160
|
+
print(format.to_s % args)
|
161
|
+
end
|
162
|
+
|
163
|
+
def putc(c)
|
164
|
+
print c.chr
|
165
|
+
end
|
166
|
+
|
167
|
+
def puts(*args)
|
168
|
+
args.each { |arg| self << "#{arg}\n" }
|
169
|
+
nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def close
|
173
|
+
@scheduler.schedule { succeed }
|
174
|
+
nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def close_read
|
178
|
+
raise IOError, "closing non-duplex IO for reading"
|
179
|
+
end
|
180
|
+
|
181
|
+
def closed_read?
|
182
|
+
true
|
183
|
+
end
|
184
|
+
|
185
|
+
def closed_write?
|
186
|
+
closed?
|
187
|
+
end
|
188
|
+
|
189
|
+
def external_encoding
|
190
|
+
Encoding.find settings.default_encoding
|
191
|
+
rescue NameError
|
192
|
+
settings.default_encoding
|
193
|
+
end
|
194
|
+
|
195
|
+
def closed?
|
196
|
+
@closed
|
197
|
+
end
|
198
|
+
|
199
|
+
def settings
|
200
|
+
app.settings
|
201
|
+
end
|
202
|
+
|
203
|
+
def rewind
|
204
|
+
@pos = @lineno = 0
|
205
|
+
end
|
206
|
+
|
207
|
+
def not_open_for_reading(*)
|
208
|
+
raise IOError, "not opened for reading"
|
209
|
+
end
|
210
|
+
|
211
|
+
alias bytes not_open_for_reading
|
212
|
+
alias eof? not_open_for_reading
|
213
|
+
alias eof not_open_for_reading
|
214
|
+
alias getbyte not_open_for_reading
|
215
|
+
alias getc not_open_for_reading
|
216
|
+
alias gets not_open_for_reading
|
217
|
+
alias read not_open_for_reading
|
218
|
+
alias read_nonblock not_open_for_reading
|
219
|
+
alias readbyte not_open_for_reading
|
220
|
+
alias readchar not_open_for_reading
|
221
|
+
alias readline not_open_for_reading
|
222
|
+
alias readlines not_open_for_reading
|
223
|
+
alias readpartial not_open_for_reading
|
224
|
+
alias sysread not_open_for_reading
|
225
|
+
alias ungetbyte not_open_for_reading
|
226
|
+
alias ungetc not_open_for_reading
|
227
|
+
private :not_open_for_reading
|
228
|
+
|
229
|
+
def enum_not_open_for_reading(*)
|
230
|
+
not_open_for_reading if block_given?
|
231
|
+
enum_for(:not_open_for_reading)
|
232
|
+
end
|
233
|
+
|
234
|
+
alias chars enum_not_open_for_reading
|
235
|
+
alias each_line enum_not_open_for_reading
|
236
|
+
alias each_byte enum_not_open_for_reading
|
237
|
+
alias each_char enum_not_open_for_reading
|
238
|
+
alias lines enum_not_open_for_reading
|
239
|
+
undef enum_not_open_for_reading
|
240
|
+
|
241
|
+
def dummy(*) end
|
242
|
+
alias flush dummy
|
243
|
+
alias fsync dummy
|
244
|
+
alias internal_encoding dummy
|
245
|
+
alias pid dummy
|
246
|
+
undef dummy
|
247
|
+
|
248
|
+
def seek(*)
|
249
|
+
0
|
250
|
+
end
|
251
|
+
|
252
|
+
alias sysseek seek
|
253
|
+
|
254
|
+
def sync
|
255
|
+
true
|
256
|
+
end
|
257
|
+
|
258
|
+
def tty?
|
259
|
+
false
|
260
|
+
end
|
261
|
+
|
262
|
+
alias isatty tty?
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
helpers Streaming
|
267
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Sinatra
|
7
|
+
Base.set :environment, :test
|
8
|
+
|
9
|
+
module TestHelpers
|
10
|
+
class Session < Rack::Test::Session
|
11
|
+
def global_env
|
12
|
+
@global_env ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def default_env
|
18
|
+
super.merge global_env
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
include Rack::Test::Methods
|
23
|
+
extend Forwardable
|
24
|
+
attr_accessor :settings
|
25
|
+
|
26
|
+
def_delegators :last_response, :body, :headers, :status, :errors
|
27
|
+
def_delegators :app, :configure, :set, :enable, :disable, :use, :helpers, :register
|
28
|
+
def_delegators :current_session, :env_for
|
29
|
+
def_delegators :rack_mock_session, :cookie_jar
|
30
|
+
|
31
|
+
def mock_app(base = Sinatra::Base, &block)
|
32
|
+
inner = nil
|
33
|
+
@app = Sinatra.new(base) do
|
34
|
+
inner = self
|
35
|
+
class_eval(&block)
|
36
|
+
end
|
37
|
+
@settings = inner
|
38
|
+
app
|
39
|
+
end
|
40
|
+
|
41
|
+
def app=(base)
|
42
|
+
@app = base
|
43
|
+
end
|
44
|
+
|
45
|
+
alias set_app app=
|
46
|
+
|
47
|
+
def app
|
48
|
+
@app ||= Class.new Sinatra::Base
|
49
|
+
Rack::Lint.new @app
|
50
|
+
end
|
51
|
+
|
52
|
+
unless method_defined? :options
|
53
|
+
def options(uri, params = {}, env = {}, &block)
|
54
|
+
env = env_for(uri, env.merge(:method => "OPTIONS", :params => params))
|
55
|
+
current_session.send(:process_request, uri, env, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
unless method_defined? :patch
|
60
|
+
def patch(uri, params = {}, env = {}, &block)
|
61
|
+
env = env_for(uri, env.merge(:method => "PATCH", :params => params))
|
62
|
+
current_session.send(:process_request, uri, env, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def last_request?
|
67
|
+
last_request
|
68
|
+
true
|
69
|
+
rescue Rack::Test::Error
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def session
|
74
|
+
return {} unless last_request?
|
75
|
+
raise Rack::Test:Error, "session not enabled for app" unless last_env["rack.session"] or app.session?
|
76
|
+
last_request.session
|
77
|
+
end
|
78
|
+
|
79
|
+
def last_env
|
80
|
+
last_request.env
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_rack_test_session(name) # :nodoc:
|
84
|
+
Session.new rack_mock_session(name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Run `rake sinatra-contrib.gemspec` to update the gemspec.
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "pirj-sinatra-contrib"
|
4
|
+
s.version = "1.3.0"
|
5
|
+
s.description = "Collection of useful Sinatra extensions"
|
6
|
+
s.homepage = "http://github.com/sinatra/sinatra-contrib"
|
7
|
+
s.summary = s.description
|
8
|
+
|
9
|
+
# generated from git shortlog -sn
|
10
|
+
s.authors = [
|
11
|
+
"Konstantin Haase",
|
12
|
+
"Gabriel Andretta",
|
13
|
+
"Nicolas Sanguinetti",
|
14
|
+
"Eliot Shepard",
|
15
|
+
"Andrew Crump",
|
16
|
+
"Matt Lyon",
|
17
|
+
"undr"
|
18
|
+
]
|
19
|
+
|
20
|
+
# generated from git shortlog -sne
|
21
|
+
s.email = [
|
22
|
+
"konstantin.mailinglists@googlemail.com",
|
23
|
+
"ohhgabriel@gmail.com",
|
24
|
+
"contacto@nicolassanguinetti.info",
|
25
|
+
"eshepard@slower.net",
|
26
|
+
"andrew.crump@ieee.org",
|
27
|
+
"matt@flowerpowered.com",
|
28
|
+
"undr@yandex.ru"
|
29
|
+
]
|
30
|
+
|
31
|
+
# generated from git ls-files
|
32
|
+
s.files = [
|
33
|
+
"LICENSE",
|
34
|
+
"README.md",
|
35
|
+
"Rakefile",
|
36
|
+
"ideas.md",
|
37
|
+
"lib/sinatra/capture.rb",
|
38
|
+
"lib/sinatra/config_file.rb",
|
39
|
+
"lib/sinatra/content_for.rb",
|
40
|
+
"lib/sinatra/contrib.rb",
|
41
|
+
"lib/sinatra/contrib/all.rb",
|
42
|
+
"lib/sinatra/contrib/setup.rb",
|
43
|
+
"lib/sinatra/contrib/version.rb",
|
44
|
+
"lib/sinatra/decompile.rb",
|
45
|
+
"lib/sinatra/engine_tracking.rb",
|
46
|
+
"lib/sinatra/extension.rb",
|
47
|
+
"lib/sinatra/json.rb",
|
48
|
+
"lib/sinatra/link_header.rb",
|
49
|
+
"lib/sinatra/namespace.rb",
|
50
|
+
"lib/sinatra/reloader.rb",
|
51
|
+
"lib/sinatra/respond_with.rb",
|
52
|
+
"lib/sinatra/streaming.rb",
|
53
|
+
"lib/sinatra/test_helpers.rb",
|
54
|
+
"sinatra-contrib.gemspec",
|
55
|
+
"spec/capture_spec.rb",
|
56
|
+
"spec/config_file/key_value.yml",
|
57
|
+
"spec/config_file/missing_env.yml",
|
58
|
+
"spec/config_file/with_envs.yml",
|
59
|
+
"spec/config_file/with_nested_envs.yml",
|
60
|
+
"spec/config_file_spec.rb",
|
61
|
+
"spec/content_for/different_key.erb",
|
62
|
+
"spec/content_for/different_key.erubis",
|
63
|
+
"spec/content_for/different_key.haml",
|
64
|
+
"spec/content_for/different_key.slim",
|
65
|
+
"spec/content_for/layout.erb",
|
66
|
+
"spec/content_for/layout.erubis",
|
67
|
+
"spec/content_for/layout.haml",
|
68
|
+
"spec/content_for/layout.slim",
|
69
|
+
"spec/content_for/multiple_blocks.erb",
|
70
|
+
"spec/content_for/multiple_blocks.erubis",
|
71
|
+
"spec/content_for/multiple_blocks.haml",
|
72
|
+
"spec/content_for/multiple_blocks.slim",
|
73
|
+
"spec/content_for/multiple_yields.erb",
|
74
|
+
"spec/content_for/multiple_yields.erubis",
|
75
|
+
"spec/content_for/multiple_yields.haml",
|
76
|
+
"spec/content_for/multiple_yields.slim",
|
77
|
+
"spec/content_for/passes_values.erb",
|
78
|
+
"spec/content_for/passes_values.erubis",
|
79
|
+
"spec/content_for/passes_values.haml",
|
80
|
+
"spec/content_for/passes_values.slim",
|
81
|
+
"spec/content_for/same_key.erb",
|
82
|
+
"spec/content_for/same_key.erubis",
|
83
|
+
"spec/content_for/same_key.haml",
|
84
|
+
"spec/content_for/same_key.slim",
|
85
|
+
"spec/content_for/takes_values.erb",
|
86
|
+
"spec/content_for/takes_values.erubis",
|
87
|
+
"spec/content_for/takes_values.haml",
|
88
|
+
"spec/content_for/takes_values.slim",
|
89
|
+
"spec/content_for_spec.rb",
|
90
|
+
"spec/decompile_spec.rb",
|
91
|
+
"spec/extension_spec.rb",
|
92
|
+
"spec/json_spec.rb",
|
93
|
+
"spec/link_header_spec.rb",
|
94
|
+
"spec/namespace/foo.erb",
|
95
|
+
"spec/namespace/nested/foo.erb",
|
96
|
+
"spec/namespace_spec.rb",
|
97
|
+
"spec/okjson.rb",
|
98
|
+
"spec/reloader/app.rb.erb",
|
99
|
+
"spec/reloader_spec.rb",
|
100
|
+
"spec/respond_with/bar.erb",
|
101
|
+
"spec/respond_with/bar.json.erb",
|
102
|
+
"spec/respond_with/foo.html.erb",
|
103
|
+
"spec/respond_with/not_html.sass",
|
104
|
+
"spec/respond_with_spec.rb",
|
105
|
+
"spec/spec_helper.rb",
|
106
|
+
"spec/streaming_spec.rb"
|
107
|
+
]
|
108
|
+
|
109
|
+
s.add_dependency "sinatra", "~> 1.3.0"
|
110
|
+
s.add_dependency "backports", ">= 2.0"
|
111
|
+
s.add_dependency "tilt", "~> 1.3"
|
112
|
+
s.add_dependency "rack-test"
|
113
|
+
s.add_dependency "rack-protection"
|
114
|
+
s.add_dependency "eventmachine"
|
115
|
+
|
116
|
+
s.add_development_dependency "rspec", "~> 2.3"
|
117
|
+
s.add_development_dependency "haml"
|
118
|
+
s.add_development_dependency "erubis"
|
119
|
+
s.add_development_dependency "slim"
|
120
|
+
s.add_development_dependency "rake"
|
121
|
+
end
|