pirj-sinatra-contrib 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +135 -0
  3. data/Rakefile +61 -0
  4. data/ideas.md +29 -0
  5. data/lib/sinatra/capture.rb +42 -0
  6. data/lib/sinatra/config_file.rb +151 -0
  7. data/lib/sinatra/content_for.rb +111 -0
  8. data/lib/sinatra/contrib.rb +39 -0
  9. data/lib/sinatra/contrib/all.rb +2 -0
  10. data/lib/sinatra/contrib/setup.rb +53 -0
  11. data/lib/sinatra/contrib/version.rb +45 -0
  12. data/lib/sinatra/decompile.rb +113 -0
  13. data/lib/sinatra/engine_tracking.rb +96 -0
  14. data/lib/sinatra/extension.rb +95 -0
  15. data/lib/sinatra/json.rb +134 -0
  16. data/lib/sinatra/link_header.rb +132 -0
  17. data/lib/sinatra/namespace.rb +282 -0
  18. data/lib/sinatra/reloader.rb +384 -0
  19. data/lib/sinatra/respond_with.rb +245 -0
  20. data/lib/sinatra/streaming.rb +267 -0
  21. data/lib/sinatra/test_helpers.rb +87 -0
  22. data/sinatra-contrib.gemspec +121 -0
  23. data/spec/capture_spec.rb +80 -0
  24. data/spec/config_file/key_value.yml +6 -0
  25. data/spec/config_file/missing_env.yml +4 -0
  26. data/spec/config_file/with_envs.yml +7 -0
  27. data/spec/config_file/with_nested_envs.yml +11 -0
  28. data/spec/config_file_spec.rb +44 -0
  29. data/spec/content_for/different_key.erb +1 -0
  30. data/spec/content_for/different_key.erubis +1 -0
  31. data/spec/content_for/different_key.haml +2 -0
  32. data/spec/content_for/different_key.slim +2 -0
  33. data/spec/content_for/layout.erb +1 -0
  34. data/spec/content_for/layout.erubis +1 -0
  35. data/spec/content_for/layout.haml +1 -0
  36. data/spec/content_for/layout.slim +1 -0
  37. data/spec/content_for/multiple_blocks.erb +4 -0
  38. data/spec/content_for/multiple_blocks.erubis +4 -0
  39. data/spec/content_for/multiple_blocks.haml +8 -0
  40. data/spec/content_for/multiple_blocks.slim +8 -0
  41. data/spec/content_for/multiple_yields.erb +3 -0
  42. data/spec/content_for/multiple_yields.erubis +3 -0
  43. data/spec/content_for/multiple_yields.haml +3 -0
  44. data/spec/content_for/multiple_yields.slim +3 -0
  45. data/spec/content_for/passes_values.erb +1 -0
  46. data/spec/content_for/passes_values.erubis +1 -0
  47. data/spec/content_for/passes_values.haml +1 -0
  48. data/spec/content_for/passes_values.slim +1 -0
  49. data/spec/content_for/same_key.erb +1 -0
  50. data/spec/content_for/same_key.erubis +1 -0
  51. data/spec/content_for/same_key.haml +2 -0
  52. data/spec/content_for/same_key.slim +2 -0
  53. data/spec/content_for/takes_values.erb +1 -0
  54. data/spec/content_for/takes_values.erubis +1 -0
  55. data/spec/content_for/takes_values.haml +3 -0
  56. data/spec/content_for/takes_values.slim +3 -0
  57. data/spec/content_for_spec.rb +201 -0
  58. data/spec/decompile_spec.rb +44 -0
  59. data/spec/extension_spec.rb +33 -0
  60. data/spec/json_spec.rb +115 -0
  61. data/spec/link_header_spec.rb +100 -0
  62. data/spec/namespace/foo.erb +1 -0
  63. data/spec/namespace/nested/foo.erb +1 -0
  64. data/spec/namespace_spec.rb +623 -0
  65. data/spec/okjson.rb +581 -0
  66. data/spec/reloader/app.rb.erb +40 -0
  67. data/spec/reloader_spec.rb +441 -0
  68. data/spec/respond_with/bar.erb +1 -0
  69. data/spec/respond_with/bar.json.erb +1 -0
  70. data/spec/respond_with/foo.html.erb +1 -0
  71. data/spec/respond_with/not_html.sass +2 -0
  72. data/spec/respond_with_spec.rb +289 -0
  73. data/spec/spec_helper.rb +6 -0
  74. data/spec/streaming_spec.rb +436 -0
  75. 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