sinatra-contrib 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +135 -0
  3. data/Rakefile +75 -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/cookies.rb +331 -0
  13. data/lib/sinatra/decompile.rb +113 -0
  14. data/lib/sinatra/engine_tracking.rb +96 -0
  15. data/lib/sinatra/extension.rb +95 -0
  16. data/lib/sinatra/json.rb +134 -0
  17. data/lib/sinatra/link_header.rb +132 -0
  18. data/lib/sinatra/multi_route.rb +81 -0
  19. data/lib/sinatra/namespace.rb +282 -0
  20. data/lib/sinatra/reloader.rb +384 -0
  21. data/lib/sinatra/respond_with.rb +245 -0
  22. data/lib/sinatra/streaming.rb +267 -0
  23. data/lib/sinatra/test_helpers.rb +87 -0
  24. data/sinatra-contrib.gemspec +125 -0
  25. data/spec/capture_spec.rb +80 -0
  26. data/spec/config_file/key_value.yml +6 -0
  27. data/spec/config_file/missing_env.yml +4 -0
  28. data/spec/config_file/with_envs.yml +7 -0
  29. data/spec/config_file/with_nested_envs.yml +11 -0
  30. data/spec/config_file_spec.rb +44 -0
  31. data/spec/content_for/different_key.erb +1 -0
  32. data/spec/content_for/different_key.erubis +1 -0
  33. data/spec/content_for/different_key.haml +2 -0
  34. data/spec/content_for/different_key.slim +2 -0
  35. data/spec/content_for/layout.erb +1 -0
  36. data/spec/content_for/layout.erubis +1 -0
  37. data/spec/content_for/layout.haml +1 -0
  38. data/spec/content_for/layout.slim +1 -0
  39. data/spec/content_for/multiple_blocks.erb +4 -0
  40. data/spec/content_for/multiple_blocks.erubis +4 -0
  41. data/spec/content_for/multiple_blocks.haml +8 -0
  42. data/spec/content_for/multiple_blocks.slim +8 -0
  43. data/spec/content_for/multiple_yields.erb +3 -0
  44. data/spec/content_for/multiple_yields.erubis +3 -0
  45. data/spec/content_for/multiple_yields.haml +3 -0
  46. data/spec/content_for/multiple_yields.slim +3 -0
  47. data/spec/content_for/passes_values.erb +1 -0
  48. data/spec/content_for/passes_values.erubis +1 -0
  49. data/spec/content_for/passes_values.haml +1 -0
  50. data/spec/content_for/passes_values.slim +1 -0
  51. data/spec/content_for/same_key.erb +1 -0
  52. data/spec/content_for/same_key.erubis +1 -0
  53. data/spec/content_for/same_key.haml +2 -0
  54. data/spec/content_for/same_key.slim +2 -0
  55. data/spec/content_for/takes_values.erb +1 -0
  56. data/spec/content_for/takes_values.erubis +1 -0
  57. data/spec/content_for/takes_values.haml +3 -0
  58. data/spec/content_for/takes_values.slim +3 -0
  59. data/spec/content_for_spec.rb +201 -0
  60. data/spec/cookies_spec.rb +782 -0
  61. data/spec/decompile_spec.rb +44 -0
  62. data/spec/extension_spec.rb +33 -0
  63. data/spec/json_spec.rb +115 -0
  64. data/spec/link_header_spec.rb +100 -0
  65. data/spec/multi_route_spec.rb +45 -0
  66. data/spec/namespace/foo.erb +1 -0
  67. data/spec/namespace/nested/foo.erb +1 -0
  68. data/spec/namespace_spec.rb +623 -0
  69. data/spec/okjson.rb +581 -0
  70. data/spec/reloader/app.rb.erb +40 -0
  71. data/spec/reloader_spec.rb +441 -0
  72. data/spec/respond_with/bar.erb +1 -0
  73. data/spec/respond_with/bar.json.erb +1 -0
  74. data/spec/respond_with/foo.html.erb +1 -0
  75. data/spec/respond_with/not_html.sass +2 -0
  76. data/spec/respond_with_spec.rb +289 -0
  77. data/spec/spec_helper.rb +6 -0
  78. data/spec/streaming_spec.rb +436 -0
  79. metadata +256 -0
@@ -0,0 +1,111 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/capture'
3
+
4
+ module Sinatra
5
+
6
+ # = Sinatra::ContentFor
7
+ #
8
+ # <tt>Sinatra::ContentFor</tt> is a set of helpers that allows you to capture
9
+ # blocks inside views to be rendered later during the request. The most
10
+ # common use is to populate different parts of your layout from your view.
11
+ #
12
+ # The currently supported engines are: Erb, Erubis, Haml and Slim.
13
+ #
14
+ # == Usage
15
+ #
16
+ # You call +content_for+, generally from a view, to capture a block of markup
17
+ # giving it an identifier:
18
+ #
19
+ # # index.erb
20
+ # <% content_for :some_key do %>
21
+ # <chunk of="html">...</chunk>
22
+ # <% end %>
23
+ #
24
+ # Then, you call +yield_content+ with that identifier, generally from a
25
+ # layout, to render the captured block:
26
+ #
27
+ # # layout.erb
28
+ # <%= yield_content :some_key %>
29
+ #
30
+ # === Classic Application
31
+ #
32
+ # To use the helpers in a classic application all you need to do is require
33
+ # them:
34
+ #
35
+ # require "sinatra"
36
+ # require "sinatra/content_for"
37
+ #
38
+ # # Your classic application code goes here...
39
+ #
40
+ # === Modular Application
41
+ #
42
+ # To use the helpers in a modular application you need to require them, and
43
+ # then, tell the application you will use them:
44
+ #
45
+ # require "sinatra/base"
46
+ # require "sinatra/content_for"
47
+ #
48
+ # class MyApp < Sinatra::Base
49
+ # register Sinatra::ContentFor
50
+ #
51
+ # # The rest of your modular application code goes here...
52
+ # end
53
+ #
54
+ # == And How Is This Useful?
55
+ #
56
+ # For example, some of your views might need a few javascript tags and
57
+ # stylesheets, but you don't want to force this files in all your pages.
58
+ # Then you can put <tt><% yield_content :scripts_and_styles %></tt> on your
59
+ # layout, inside the <head> tag, and each view can call <tt>content_for</tt>
60
+ # setting the appropriate set of tags that should be added to the layout.
61
+ #
62
+ module ContentFor
63
+ include Capture
64
+
65
+ # Capture a block of content to be rendered later. For example:
66
+ #
67
+ # <% content_for :head do %>
68
+ # <script type="text/javascript" src="/foo.js"></script>
69
+ # <% end %>
70
+ #
71
+ # You can call +content_for+ multiple times with the same key
72
+ # (in the example +:head+), and when you render the blocks for
73
+ # that key all of them will be rendered, in the same order you
74
+ # captured them.
75
+ #
76
+ # Your blocks can also receive values, which are passed to them
77
+ # by <tt>yield_content</tt>
78
+ def content_for(key, &block)
79
+ content_blocks[key.to_sym] << capture_later(&block)
80
+ end
81
+
82
+ # Render the captured blocks for a given key. For example:
83
+ #
84
+ # <head>
85
+ # <title>Example</title>
86
+ # <%= yield_content :head %>
87
+ # </head>
88
+ #
89
+ # Would render everything you declared with <tt>content_for
90
+ # :head</tt> before closing the <tt><head></tt> tag.
91
+ #
92
+ # You can also pass values to the content blocks by passing them
93
+ # as arguments after the key:
94
+ #
95
+ # <%= yield_content :head, 1, 2 %>
96
+ #
97
+ # Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered
98
+ # for <tt>:head</tt>.
99
+ def yield_content(key, *args)
100
+ content_blocks[key.to_sym].map { |b| capture(*args, &b) }.join
101
+ end
102
+
103
+ private
104
+
105
+ def content_blocks
106
+ @content_blocks ||= Hash.new {|h,k| h[k] = [] }
107
+ end
108
+ end
109
+
110
+ helpers ContentFor
111
+ end
@@ -0,0 +1,39 @@
1
+ require 'sinatra/contrib/setup'
2
+
3
+ module Sinatra
4
+ module Contrib
5
+ ##
6
+ # Common middleware that doesn't bring run time overhead if not used
7
+ # or breaks if external dependencies are missing. Will extend
8
+ # Sinatra::Application by default.
9
+ module Common
10
+ register :ConfigFile
11
+ register :MultiRoute
12
+ register :Namespace
13
+ register :RespondWith
14
+
15
+ helpers :Capture
16
+ helpers :ContentFor
17
+ helpers :Cookies
18
+ helpers :EngineTracking
19
+ helpers :JSON
20
+ helpers :LinkHeader
21
+ helpers :Streaming
22
+ end
23
+
24
+ ##
25
+ # Other extensions you don't want to be loaded unless needed.
26
+ module Custom
27
+ # register :Compass
28
+ register :Decompile
29
+ register :Reloader
30
+ end
31
+
32
+ ##
33
+ # Stuff that aren't Sinatra extensions, technically.
34
+ autoload :Extension
35
+ autoload :TestHelpers
36
+ end
37
+
38
+ register Sinatra::Contrib::Common
39
+ end
@@ -0,0 +1,2 @@
1
+ require 'sinatra/contrib'
2
+ Sinatra.register Sinatra::Contrib::All
@@ -0,0 +1,53 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/contrib/version'
3
+ require 'backports'
4
+
5
+ module Sinatra
6
+ module Contrib
7
+ module Loader
8
+ def extensions
9
+ @extensions ||= {:helpers => [], :register => []}
10
+ end
11
+
12
+ def register(name, path = nil)
13
+ autoload name, path, :register
14
+ end
15
+
16
+ def helpers(name, path = nil)
17
+ autoload name, path, :helpers
18
+ end
19
+
20
+ def autoload(name, path = nil, method = nil)
21
+ path ||= "sinatra/#{name.to_s.underscore}"
22
+ extensions[method] << name if method
23
+ Sinatra.autoload(name, path)
24
+ end
25
+
26
+ def registered(base)
27
+ @extensions.each do |meth, list|
28
+ list = list.map { |name| Sinatra.const_get name }
29
+ base.send(meth, *list) unless base == ::Sinatra::Application
30
+ end
31
+ end
32
+ end
33
+
34
+ module Common
35
+ extend Loader
36
+ end
37
+
38
+ module Custom
39
+ extend Loader
40
+ end
41
+
42
+ module All
43
+ def self.registered(base)
44
+ base.register Common, Custom
45
+ end
46
+ end
47
+
48
+ extend Loader
49
+ def self.registered(base)
50
+ base.register Common, Custom
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ module Sinatra
2
+ module Contrib
3
+ def self.version
4
+ VERSION
5
+ end
6
+
7
+ module VERSION
8
+ extend Comparable
9
+
10
+ MAJOR = 1
11
+ MINOR = 3
12
+ TINY = 0
13
+ SIGNATURE = [MAJOR, MINOR, TINY]
14
+ STRING = SIGNATURE.join '.'
15
+
16
+ def self.major; MAJOR end
17
+ def self.minor; MINOR end
18
+ def self.tiny; TINY end
19
+ def self.to_s; STRING end
20
+
21
+ def self.hash
22
+ STRING.hash
23
+ end
24
+
25
+ def self.<=>(other)
26
+ other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
27
+ SIGNATURE <=> Array(other)
28
+ end
29
+
30
+ def self.inspect
31
+ STRING.inspect
32
+ end
33
+
34
+ def self.respond_to?(meth, *)
35
+ return true if super
36
+ meth.to_s !~ /^__|^to_str$/ and STRING.respond_to? meth
37
+ end
38
+
39
+ def self.method_missing(meth, *args, &block)
40
+ return super unless STRING.respond_to?(meth)
41
+ STRING.send(meth, *args, &block)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,331 @@
1
+ require 'sinatra/base'
2
+ require 'backports'
3
+
4
+ module Sinatra
5
+ # = Sinatra::Cookies
6
+ #
7
+ # Easy way to deal with cookies
8
+ #
9
+ # == Usage
10
+ #
11
+ # Allows you to read cookies:
12
+ #
13
+ # get '/' do
14
+ # "value: #{cookie[:something]}"
15
+ # end
16
+ #
17
+ # And of course to write cookies:
18
+ #
19
+ # get '/set' do
20
+ # cookies[:something] = 'foobar'
21
+ # redirect to('/')
22
+ # end
23
+ #
24
+ # And generally behaves like a hash:
25
+ #
26
+ # get '/demo' do
27
+ # cookies.merge! 'foo' => 'bar', 'bar' => 'baz'
28
+ # cookies.keep_if { |key, value| key.start_with? 'b' }
29
+ # foo, bar = cookies.values_at 'foo', 'bar'
30
+ # "size: #{cookies.length}"
31
+ # end
32
+ #
33
+ # === Classic Application
34
+ #
35
+ # In a classic application simply require the helpers, and start using them:
36
+ #
37
+ # require "sinatra"
38
+ # require "sinatra/cookies"
39
+ #
40
+ # # The rest of your classic application code goes here...
41
+ #
42
+ # === Modular Application
43
+ #
44
+ # In a modular application you need to require the helpers, and then tell
45
+ # the application you will use them:
46
+ #
47
+ # require "sinatra/base"
48
+ # require "sinatra/link_header"
49
+ #
50
+ # class MyApp < Sinatra::Base
51
+ # helpers Sinatra::Cookies
52
+ #
53
+ # # The rest of your modular application code goes here...
54
+ # end
55
+ #
56
+ module Cookies
57
+ class Jar
58
+ include Enumerable
59
+ attr_reader :options
60
+
61
+ def initialize(app)
62
+ @response_string = nil
63
+ @response_hash = {}
64
+ @response = app.response
65
+ @request = app.request
66
+ @deleted = []
67
+
68
+ @options = {
69
+ :path => @request.script_name,
70
+ :domain => @request.host,
71
+ :secure => @request.secure?,
72
+ :httponly => true
73
+ }
74
+
75
+ @options[:path] = '/' if @options[:path].to_s.empty?
76
+
77
+ if app.settings.respond_to? :cookie_options
78
+ @options.merge! app.settings.cookie_options
79
+ end
80
+ end
81
+
82
+ def ==(other)
83
+ other.respond_to? :to_hash and to_hash == other.to_hash
84
+ end
85
+
86
+ def [](key)
87
+ response_cookies[key.to_s] || request_cookies[key.to_s]
88
+ end
89
+
90
+ def []=(key, value)
91
+ @response.set_cookie key.to_s, @options.merge(:value => value)
92
+ end
93
+
94
+ def assoc(key)
95
+ to_hash.assoc(key.to_s)
96
+ end if Hash.method_defined? :assoc
97
+
98
+ def clear
99
+ each_key { |k| delete(k) }
100
+ end
101
+
102
+ def compare_by_identity?
103
+ false
104
+ end
105
+
106
+ def default
107
+ nil
108
+ end
109
+
110
+ alias default_proc default
111
+
112
+ def delete(key)
113
+ result = self[key]
114
+ @response.delete_cookie(key.to_s)
115
+ result
116
+ end
117
+
118
+ def delete_if
119
+ return enum_for(__method__) unless block_given?
120
+ each { |k, v| delete(k) if yield(k, v) }
121
+ self
122
+ end
123
+
124
+ def each(&block)
125
+ return enum_for(__method__) unless block_given?
126
+ to_hash.each(&block)
127
+ end
128
+
129
+ def each_key(&block)
130
+ return enum_for(__method__) unless block_given?
131
+ to_hash.each_key(&block)
132
+ end
133
+
134
+ alias each_pair each
135
+
136
+ def each_value(&block)
137
+ return enum_for(__method__) unless block_given?
138
+ to_hash.each_value(&block)
139
+ end
140
+
141
+ def empty?
142
+ to_hash.empty?
143
+ end
144
+
145
+ def fetch(key, &block)
146
+ response_cookies.fetch(key.to_s) do
147
+ request_cookies.fetch(key.to_s, &block)
148
+ end
149
+ end
150
+
151
+ def flatten
152
+ to_hash.flatten
153
+ end if Hash.method_defined? :flatten
154
+
155
+ def has_key?(key)
156
+ response_cookies.has_key? key.to_s or request_cookies.has_key? key.to_s
157
+ end
158
+
159
+ def has_value?(value)
160
+ response_cookies.has_value? value or request_cookies.has_value? value
161
+ end
162
+
163
+ def hash
164
+ to_hash.hash
165
+ end
166
+
167
+ alias include? has_key?
168
+ alias member? has_key?
169
+
170
+ def index(value)
171
+ warn "Hash#index is deprecated; use Hash#key" if RUBY_VERSION > '1.9'
172
+ key(value)
173
+ end
174
+
175
+ def inspect
176
+ "<##{self.class}: #{to_hash.inspect[1..-2]}>"
177
+ end
178
+
179
+ def invert
180
+ to_hash.invert
181
+ end if Hash.method_defined? :invert
182
+
183
+ def keep_if
184
+ return enum_for(__method__) unless block_given?
185
+ delete_if { |*a| not yield(*a) }
186
+ end
187
+
188
+ def key(value)
189
+ to_hash.key(value)
190
+ end
191
+
192
+ alias key? has_key?
193
+
194
+ def keys
195
+ to_hash.keys
196
+ end
197
+
198
+ def length
199
+ to_hash.length
200
+ end
201
+
202
+ def merge(other, &block)
203
+ to_hash.merge(other, &block)
204
+ end
205
+
206
+ def merge!(other)
207
+ other.each_pair do |key, value|
208
+ if block_given? and include? key
209
+ self[key] = yield(key.to_s, self[key], value)
210
+ else
211
+ self[key] = value
212
+ end
213
+ end
214
+ end
215
+
216
+ def rassoc(value)
217
+ to_hash.rassoc(value)
218
+ end
219
+
220
+ def rehash
221
+ response_cookies.rehash
222
+ request_cookies.rehash
223
+ self
224
+ end
225
+
226
+ def reject(&block)
227
+ return enum_for(__method__) unless block_given?
228
+ to_hash.reject(&block)
229
+ end
230
+
231
+ alias reject! delete_if
232
+
233
+ def replace(other)
234
+ select! { |k, v| other.include?(k) or other.include?(k.to_s) }
235
+ merge! other
236
+ end
237
+
238
+ def select(&block)
239
+ return enum_for(__method__) unless block_given?
240
+ to_hash.select(&block)
241
+ end
242
+
243
+ alias select! keep_if if Hash.method_defined? :select!
244
+
245
+ def shift
246
+ key, value = to_hash.shift
247
+ delete(key)
248
+ [key, value]
249
+ end
250
+
251
+ alias size length
252
+
253
+ def sort(&block)
254
+ to_hash.sort(&block)
255
+ end if Hash.method_defined? :sort
256
+
257
+ alias store []=
258
+
259
+ def to_hash
260
+ request_cookies.merge(response_cookies)
261
+ end
262
+
263
+ def to_a
264
+ to_hash.to_a
265
+ end
266
+
267
+ def to_s
268
+ to_hash.to_s
269
+ end
270
+
271
+ alias update merge!
272
+ alias value? has_value?
273
+
274
+ def values
275
+ to_hash.values
276
+ end
277
+
278
+ def values_at(*list)
279
+ list.map { |k| self[k] }
280
+ end
281
+
282
+ private
283
+
284
+ def warn(message)
285
+ super "#{caller.first[/^[^:]:\d+:/]} warning: #{message}"
286
+ end
287
+
288
+ def deleted
289
+ parse_response
290
+ @deleted
291
+ end
292
+
293
+ def response_cookies
294
+ parse_response
295
+ @response_hash
296
+ end
297
+
298
+ def parse_response
299
+ string = @response['Set-Cookie']
300
+ return if @response_string == string
301
+
302
+ hash = {}
303
+
304
+ string.each_line do |line|
305
+ key, value = line.split(';', 2).first.to_s.split('=', 2)
306
+ next if key.nil?
307
+ key = Rack::Utils.unescape(key)
308
+ if line.include? "expires=Thu, 01-Jan-1970 00:00:00 GMT"
309
+ @deleted << key
310
+ else
311
+ @deleted.delete key
312
+ hash[key] = value
313
+ end
314
+ end
315
+
316
+ @response_hash.replace hash
317
+ @response_string = string
318
+ end
319
+
320
+ def request_cookies
321
+ @request.cookies.reject { |key, value| deleted.include? key }
322
+ end
323
+ end
324
+
325
+ def cookies
326
+ @cookies ||= Jar.new(self)
327
+ end
328
+ end
329
+
330
+ helpers Cookies
331
+ end