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.
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