scorched 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e4ea3f73fb031a956003067b827230358bb5f0e
4
- data.tar.gz: e8e9ff7012cd3cfaf471b855daab89f915ce285d
3
+ metadata.gz: bbeb1df9d3b27b4e455d9c0ee30d282da0875a58
4
+ data.tar.gz: bf7ee84acc65b7bd2cd355afdca30150ac8b8f6a
5
5
  SHA512:
6
- metadata.gz: 2d0da75971382d0108cf9585a55c95a13ce918d9f10ead66eac0c6cd182e710e821456a633830a16728b7d2d37ea3e81f37132dc1a9f5a6ae94ac3466a4eaaf7
7
- data.tar.gz: d78bcf8bf3ee287f2fc880da0c6e4d956f2e1b1bb1a34f121127dfe8402eb0f2ebd66f14922e47d3cbd0f5407330fa5a5a4e33f7f4c029b2524cfff28f54d4d8
6
+ metadata.gz: a546b0e44c56adb26cc23d5d0fe40a60485467a50639c05fd36fadd8ce7dab591de8ff06b73c73756739ace69ab34a56402e9179d49e56b7a4920993050292d4
7
+ data.tar.gz: 3f85d181a8db836196db23099b6d5b49a424bad7d2f56c9e714021127ddcb9c4cf61664ec24b251d0affbd2aa4ea7fd0ea542b87f2a5124ba3100bd202938611
@@ -3,7 +3,17 @@ Milestones
3
3
 
4
4
  Changelog
5
5
  ---------
6
- <<<<<<< HEAD
6
+ ### v0.7
7
+ * Logging preparations made. Now just have to decide on a logging strategy, such as what to log, how verbose the messages should be, etc.
8
+ * Environment-specific defaults added. The environment variable ``RACK_ENV`` is used to determine the current environment.
9
+ * Non-Development
10
+ * ``config[:static_dir] = false``
11
+ * Development
12
+ * ``config[:show_exceptions] = true``
13
+ * ``config[:logger] = Logger.new(STDOUT)``
14
+ * Add developer-friendly 404 error page. This is implemented as an after filter, and won't have any effect if the response body is set.
15
+ * ``absolute`` method now returns forward slash if script name is empty.
16
+
7
17
  ### v0.6
8
18
  * ``view_config`` options hash renamed to ``render_defaults`` which better reflects its function.
9
19
 
@@ -70,7 +80,8 @@ Some of these remaining features may be broken out into a separate contributor l
70
80
 
71
81
  Unlikely
72
82
  --------
73
- * Mutex locking option? I'm of the opinion that the web server should be configured for the concurrency model of the application, rather than the framework.
83
+ * Mutex locking option - I'm of the opinion that the web server should be configured for the concurrency model of the application, rather than the framework.
84
+ * Using Rack::Protection by default - The problem here is that a good portion of Rack::Protection involves sessions, and given that Scorched doesn't itself load any session middleware, these components of Rack::Protection would have to be excluded. I wouldn't want to invoke a false sense of security
85
+
74
86
 
75
-
76
87
  More things will be added to these lists as they're thought of and considered.
data/README.md CHANGED
@@ -32,23 +32,23 @@ _**Note**: Scorched requires Ruby 2.0 as it makes use of a couple of new feature
32
32
 
33
33
  The Errors of Our Past
34
34
  ----------------------
35
- One of the big mistakes made by a lot of other Ruby frameworks, was to not leverage the power of the class. The consequences of this made for some awkwardness. Helpers for example, are a classical reinvention of what classes and modules were already made to solve. Scorched implements Controllers as Classes, which in addition to having their own DSL, allow defining and calling traditional class methods. The decision to allow developers to implement helpers and other common functionality as proper methods not only makes Controllers somewhat more predictable and familiar, but of course allow such helpers to be inheritable via plain-old Class inheritance.
35
+ One of the mistakes made by a lot of other Ruby frameworks, was to not leverage the power of the class. The consequences of this made for some awkwardness. Helpers for example, are a classical reinvention of what classes and modules were already made to solve. Scorched implements Controllers as classes, which in addition to having their own DSL, allow defining and calling traditional instance methods. The decision to allow developers to implement helpers and other common functionality as proper methods not only makes Controllers somewhat more predictable and familiar, but of course allow such helpers to be inheritable via plain-old class inheritance.
36
36
 
37
37
  Perhaps another design oversight of other frameworks, has been the lack of consideration for the hierarchical nature of websites, and the fact that sub-directories are often expected to inherit attributes of their parents. Scorched supports sub-controllers to any arbitrary depth, with each controllers configuration, filters, route conditions, etc, applied along the way. This can assist many areas of web development, including security, restful interfaces, and interchangeable content types.
38
38
 
39
39
 
40
40
  Design Philosophy
41
41
  -----------------
42
- Scorched has a relatively simple design philosophy. The main objective is to keep Scorched lean and generic. Scorched refrains from expressing too much opinion. The general idea behind Scorched is to give developers all the tools to quickly put together small, medium and perhaps even large websites and applications.
42
+ Scorched has a relatively simple design philosophy. The main objective is to keep Scorched lean and generic. Scorched refrains from expressing any opinion about how you design and structure your application. The general idea is to give developers the constructs to quickly put together small, medium and even large websites and applications.
43
43
 
44
- There's little need for a framework to be opinionated if the opinions of the developer can be quickly and easily built into it on a per-application basis. To do this effectively, developers really need to understand Scorched, and the best way to lower facilitate that is to lower the learning curve by keeping the core design, logical, predictable, and concise.
44
+ There's little need for a framework to be opinionated if the opinions of the developer can be quickly and easily built into it on a per-application basis. To do this effectively, developers really need to understand Scorched, and the best way to facilitate that is to lower the learning curve by keeping the core design logical, predictable, and concise.
45
45
 
46
46
 
47
47
  Magicians Not Welcome
48
48
  ---------------------
49
- Scorched aims to be raw and transparent. Magic has no place, or need, in the world of Scorched. A thoughtful and simple design means there's no requirement for magic. Because of that, most developers should be able to master scorched in an evening, if that.
49
+ Scorched aims to be raw and transparent. Magic has no place. A thoughtful and simple design means there's no requirement for magic. Because of that, most developers should be able to master scorched in an evening.
50
50
 
51
- Part of what keeps Scorched lightweight, is that unlike other lightweight web frameworks that attempt to hide Rack in the background, Scorched makes no such attempts, very rarely providing functionality that overlaps with that already provided by Rack. In fact, familiarity is somewhat of a pre-requisite to mastering Scorched.
51
+ Part of what keeps Scorched lightweight, is that unlike other lightweight web frameworks that attempt to hide Rack in the background, Scorched makes no such attempts, very rarely providing functionality that overlaps with what's already provided by Rack. In fact, familiarity with Rack is somewhat of a pre-requisite to mastering Scorched.
52
52
 
53
53
 
54
54
  First Impressions
@@ -3,4 +3,4 @@ Preface
3
3
 
4
4
  _This is where I share with you all my infinite wisdom. It will come. In the mean time, know that the documentation is currently incomplete, and likely the victim of quite a few typos._
5
5
 
6
- _As an early adopter, feel free to use the Github issue tracker to ask questions and request assistance._
6
+ _As an early adopter, feel free to use the Github issue tracker to ask questions and request assistance. Such questions will be used to further refine the documentation._
@@ -6,9 +6,17 @@ Scorched uses Tilt to render templates in various supported formats. Because of
6
6
  ``render`` can take a file path or a string as the template. If a symbol is given, it assumes it's a file path, were as a string is assumed to be the template markup. ``render`` can also takes a set of options.
7
7
 
8
8
  * ``:dir`` - The directory containing the views. This can be absolute or relative to the current working directory.
9
- * ``:layout`` - The template to render _around_ the view. This results in a subsequent call to ``render``, where this value is sent as the first argument. Layout's inherit the settings of the main template being rendered.
9
+ * ``:layout`` - The template to render _around_ the view.
10
10
  * ``:engine`` - The template engine to use if it can't be derived from the file name. This is always required for string templates. Can be any string or symbol that Tilt recognises, e.g :erb, :haml, :sass, etc.
11
11
 
12
- Any unrecognised options are passed through to Tilt and the corresponding rendering engine.
12
+ Any unrecognised options are passed through to Tilt and the corresponding rendering engine. A common example being the ``:locals`` option, used to set local variables made available within the scope of the view.
13
13
 
14
- Finally, ``render`` takes an optional block to be _yielded_ within the view being rendered, if supported by the rendering engine.
14
+ Finally, ``render`` takes an optional block to be _yielded_ within the view being rendered, if supported by the rendering engine. Layout's use this feature.
15
+
16
+ Layouts
17
+ -------
18
+ When a layout is given, a subsequent call to ``render`` is made, with the rendered result of the main template given as the block to be yielded. The defined ``:layout`` is provided as the first argument on the sub-sequent call to ``render``, so the same rules apply. Layouts inherit the options of the main template being rendered.
19
+
20
+ Partials
21
+ --------
22
+ There are cases where a you may want a view to be composed of more than just a layout and a single view. The view may contain one or more sub-views, commonly referred to as partials. Scorched makes provisions for this by ignoring the default layout when ``render`` is called within a view, hence negating the requirement to explicitly override the layout.
@@ -42,4 +42,4 @@ An DRY way to serve multiple content-types:
42
42
  Authentication and Permissions
43
43
  ------------------------------
44
44
 
45
- _Example coming soon._
45
+ _Example coming soon I hope._
@@ -0,0 +1,24 @@
1
+ Code Reloading
2
+ ==============
3
+
4
+ The difficulties, or rather impossibilities, of doing in-process code reloading in Ruby have been well-documented. Scorched therefore makes no attempt to implement in form of such code reloading. There are many out-of-process reloading solutions. These all essentially reboot your application, reloading all dependancies. This provides an obvious incentive to keep your application boot times as fast as possible.
5
+
6
+ A sub-set of the most popular application reloaders are detailed below.
7
+
8
+ Rerun
9
+ -----
10
+ Rerun is a general purpose gem (``gem install rerun``) for watching files and rerunning some command when any of those files change. The following example uses rerun to watch for changes to ".rb" and ".ru" files anywhere in the current directory tree. If a change is made, any previous instance of ``rackup`` are shutdown and restarted.
11
+
12
+ rerun -p "**/*.{rb,ru}" rackup
13
+
14
+ Shotgun
15
+ -------
16
+ Unlike Rerun, Shotgun doesn't do any file watching. It instead reloads your application on every request. This sounds slow, but rerun uses an efficient technique of forking the application server and reloading your application. For applications that are quick to start, this method is generally preferred. Shotgun was used for example while developing http://scorchedrb.com.
17
+
18
+ shotgun
19
+
20
+ Phusion Passenger
21
+ -----------------
22
+ The popular Apache/Nginx module for hosting Rack applications, Phusion Passenger, can be configured to reload your application on every request much like Shotgun does. Passenger can be faster that Shogun, as you can let the underlying web server (Apache or Nginx) to take care of the static file serving, which avoids having to reload your application for every static file request.
23
+
24
+ To have Passenger automatically restart your application on every request, create a file named ``tmp/always_restart.txt`` in the root of your application directory. Passenger will automatically detect this file and behave as intended.
@@ -0,0 +1,6 @@
1
+ Running Unit Tests
2
+ ==================
3
+
4
+ If doing any development on Scorched, such as if you want to fork it or contribute patches to it, you will probably want to run the suite of tests that accompany it. The few dependancies required for running the Scorched unit tests are installed either when you install the Scorched gem, or by running ``bundle`` in the root of the Scorched source tree.
5
+
6
+ All unit tests have been written using RSpec. To run the tests, ``cd`` into the root of the Scorched source tree from a terminal, and run ``rspec``.
@@ -1,3 +1,5 @@
1
+ ENV['RACK_ENV'] ||= 'development'
2
+
1
3
  # Gems
2
4
  require 'rack'
3
5
  require 'rack/accept'
@@ -11,7 +11,8 @@ module Scorched
11
11
  config << {
12
12
  :strip_trailing_slash => :redirect, # :redirect => Strips and redirects URL ending in forward slash, :ignore => internally ignores trailing slash, false => does nothing.
13
13
  :static_dir => 'public', # The directory Scorched should serve static files from. Set to false if web server or anything else is serving static files.
14
- :logger => Logger.new(STDOUT)
14
+ :logger => nil,
15
+ :show_exceptions => false
15
16
  }
16
17
 
17
18
  render_defaults << {
@@ -20,6 +21,13 @@ module Scorched
20
21
  :engine => :erb
21
22
  }
22
23
 
24
+ if ENV['RACK_ENV'] == 'development'
25
+ config[:logger] = Logger.new(STDOUT)
26
+ config[:show_exceptions] = true
27
+ else
28
+ config[:static_dir] = false
29
+ end
30
+
23
31
  conditions << {
24
32
  charset: proc { |charsets|
25
33
  [*charsets].any? { |charset| request.env['rack-accept.request'].charset? charset }
@@ -53,10 +61,11 @@ module Scorched
53
61
  use Rack::Accept
54
62
  use Scorched::Static, this.config[:static_dir] if this.config[:static_dir]
55
63
  use Rack::Logger, this.config[:logger] if this.config[:logger]
64
+ use Rack::ShowExceptions if this.config[:show_exceptions]
56
65
  }
57
66
 
58
67
  class << self
59
-
68
+
60
69
  def mappings
61
70
  @mappings ||= []
62
71
  end
@@ -381,12 +390,46 @@ module Scorched
381
390
  # Example: absolute('/style.css') #=> /myapp/style.css
382
391
  def absolute(path = nil)
383
392
  return path if path && URI.parse(path).scheme
384
- if path
393
+ return_path = if path
385
394
  [request.script_name, path].join('/').gsub(%r{/+}, '/')
386
395
  else
387
396
  request.script_name
388
397
  end
398
+ return_path[0] == '/' ? return_path : return_path.insert(0, '/')
399
+ end
400
+
401
+ if ENV['RACK_ENV'] == 'development' &&
402
+ after do
403
+ if response.empty?
404
+ response.body = <<-HTML
405
+ <!DOCTYPE html>
406
+ <html>
407
+ <head>
408
+ <style type="text/css">
409
+ @import url(http://fonts.googleapis.com/css?family=Titillium+Web|Open+Sans:300italic,400italic,700italic,400,700,300);
410
+ html, body { height: 100%; width: 100%; margin: 0; font-family: 'Open Sans', 'Lucida Sans', 'Arial'; }
411
+ body { color: #333; display: table; }
412
+ #container { display: table-cell; vertical-align: middle; text-align: center; }
413
+ #container > * { display: inline-block; text-align: center; vertical-align: middle; }
414
+ #logo {
415
+ padding: 12px 24px 12px 120px; color: white; background: rgb(191, 64, 0);
416
+ font-family: 'Titillium Web', 'Lucida Sans', 'Arial'; font-size: 36pt; text-decoration: none;
417
+ }
418
+ h1 { margin-left: 18px; font-weight: 400; }
419
+ </style>
420
+ </head>
421
+ <body>
422
+ <div id="container">
423
+ <a id="logo" href="http://scorchedrb.com">Scorched</a>
424
+ <h1>404 Page Not Found</h1>
425
+ </div>
426
+ </body>
427
+ </html>
428
+ HTML
429
+ end
430
+ end
389
431
  end
432
+
390
433
 
391
434
  private
392
435
 
@@ -399,5 +442,11 @@ module Scorched
399
442
  end
400
443
  end
401
444
  end
445
+
446
+ def log(type, message)
447
+ config[:logger].progname ||= 'Scorched'
448
+ type = Logger.const_get(type.to_s.upcase)
449
+ config[:logger].add(type, message)
450
+ end
402
451
  end
403
452
  end
@@ -7,7 +7,7 @@ module Scorched
7
7
  [:[]=, :clear, :delete, :delete_if, :merge!, :replace, :shift, :store].include? m
8
8
  }
9
9
 
10
- alias_method :<<, :replace
10
+ alias_method :<<, :_merge!
11
11
 
12
12
  # sets parent Options object and returns self
13
13
  def parent!(parent)
@@ -17,7 +17,7 @@ module Scorched
17
17
 
18
18
  # Automatically wraps the assigned value in an array if it doesn't respond to ``each``.
19
19
  def body=(value)
20
- super(value.respond_to?(:each) ? value : [value])
20
+ super(value.respond_to?(:each) ? value : [value].compact)
21
21
  end
22
22
 
23
23
  def finish(*args, &block)
@@ -1,3 +1,3 @@
1
1
  module Scorched
2
- VERSION = '0.6'
2
+ VERSION = '0.7'
3
3
  end
@@ -12,7 +12,7 @@ Gem::Specification.new 'scorched', Scorched::VERSION do |s|
12
12
  s.rdoc_options = %w[--line-numbers --inline-source --title Scorched --encoding=UTF-8]
13
13
 
14
14
  s.add_dependency 'rack', '~> 1.4'
15
- s.add_dependency 'rack-accept', '~> 0.4.5'
15
+ s.add_dependency 'rack-accept', '~> 0.4'
16
16
  s.add_dependency 'tilt', '~> 1.3'
17
17
  s.add_development_dependency 'rack-test', '~> 0.6'
18
18
  s.add_development_dependency 'rspec', '~> 2.9'
@@ -206,6 +206,14 @@ module Scorched
206
206
  rt.get('/dog').status.should == 404
207
207
  rt.get('/').status.should == 200
208
208
  end
209
+
210
+ it "leaves body empty if nil is returned" do
211
+ app.get('/') { }
212
+ app.after do
213
+ response.body.should == []
214
+ end
215
+ rt.get('/')
216
+ end
209
217
  end
210
218
 
211
219
  describe "sub-controllers" do
@@ -459,8 +467,8 @@ module Scorched
459
467
 
460
468
  describe "configuration" do
461
469
  describe "strip_trailing_slash" do
462
- it "is set to redirect by default" do
463
- app.config[:strip_trailing_slash].should == :redirect
470
+ it "can be set to strip trailing slash and redirect" do
471
+ app.config[:strip_trailing_slash] = :redirect
464
472
  app.get('/test') { }
465
473
  response = rt.get('/test/')
466
474
  response.status.should == 307
@@ -486,8 +494,8 @@ module Scorched
486
494
  end
487
495
 
488
496
  describe "static_dir" do
489
- it "is set to serve static files from 'public' directory by default" do
490
- app.config[:static_dir].should == 'public'
497
+ it "can serve static file from the specific directory" do
498
+ app.config[:static_dir] = 'public'
491
499
  response = rt.get('/static.txt')
492
500
  response.status.should == 200
493
501
  response.body.should == 'My static file!'
@@ -500,218 +508,246 @@ module Scorched
500
508
  end
501
509
  end
502
510
 
503
- describe "sessions" do
504
- it "provides convenience method for accessing the Rack session" do
505
- rack_session = nil
506
- app.get('/') { rack_session = session }
507
- rt.get('/')
508
- rack_session.should be_nil
511
+ describe "show_exceptions" do
512
+ it "shows debug-friendly error page for unhandled exceptions" do
513
+ app.config[:show_exceptions] = true
514
+ app.get('/') { raise RuntimeError, "Kablamo!" }
515
+ response = rt.get('/')
516
+ response.status.should == 500
517
+ response.body.should include('Rack::ShowExceptions')
518
+ end
519
+
520
+ it "can be disabled" do
521
+ app.config[:show_exceptions] = false
522
+ app.get('/') { raise RuntimeError, "Kablamo!" }
523
+ expect {
524
+ response = rt.get('/')
525
+ }.to raise_error(RuntimeError)
526
+ end
527
+ end
528
+ end
529
+
530
+ describe "sessions" do
531
+ it "provides convenience method for accessing the Rack session" do
532
+ rack_session = nil
533
+ app.get('/') { rack_session = session }
534
+ rt.get('/')
535
+ rack_session.should be_nil
536
+ app.middleware << proc { use Rack::Session::Cookie, secret: 'test' }
537
+ rt.get('/')
538
+ rack_session.should be_a(Rack::Session::Abstract::SessionHash)
539
+ end
540
+
541
+ describe "flash" do
542
+ before(:each) do
509
543
  app.middleware << proc { use Rack::Session::Cookie, secret: 'test' }
510
- rt.get('/')
511
- rack_session.should be_a(Rack::Session::Abstract::SessionHash)
512
544
  end
513
545
 
514
- describe "flash" do
515
- before(:each) do
516
- app.middleware << proc { use Rack::Session::Cookie, secret: 'test' }
517
- end
546
+ it "keeps session variables that live for one page load" do
547
+ app.get('/set') { flash[:cat] = 'meow' }
548
+ app.get('/get') { flash[:cat] }
518
549
 
519
- it "keeps session variables that live for one page load" do
520
- app.get('/set') { flash[:cat] = 'meow' }
521
- app.get('/get') { flash[:cat] }
522
-
523
- rt.get('/set')
524
- rt.get('/get').body.should == 'meow'
525
- rt.get('/get').body.should == ''
526
- end
527
-
528
- it "always reads from the original request flash" do
529
- app.get('/') do
530
- flash[:counter] = flash[:counter] ? flash[:counter] + 1 : 0
531
- flash[:counter].to_s
532
- end
533
-
534
- rt.get('/').body.should == ''
535
- rt.get('/').body.should == '0'
536
- rt.get('/').body.should == '1'
550
+ rt.get('/set')
551
+ rt.get('/get').body.should == 'meow'
552
+ rt.get('/get').body.should == ''
553
+ end
554
+
555
+ it "always reads from the original request flash" do
556
+ app.get('/') do
557
+ flash[:counter] = flash[:counter] ? flash[:counter] + 1 : 0
558
+ flash[:counter].to_s
537
559
  end
538
560
 
539
- it "can only remove flash variables if the flash object is accessed" do
540
- app.get('/set') { flash[:cat] = 'meow' }
541
- app.get('/get') { flash[:cat] }
542
- app.get('/null') { }
543
-
544
- rt.get('/set')
545
- rt.get('/null')
546
- rt.get('/get').body.should == 'meow'
547
- rt.get('/get').body.should == ''
548
- end
561
+ rt.get('/').body.should == ''
562
+ rt.get('/').body.should == '0'
563
+ rt.get('/').body.should == '1'
564
+ end
565
+
566
+ it "can only remove flash variables if the flash object is accessed" do
567
+ app.get('/set') { flash[:cat] = 'meow' }
568
+ app.get('/get') { flash[:cat] }
569
+ app.get('/null') { }
549
570
 
550
- it "can keep multiple sets of flash session variables" do
551
- app.get('/set_animal') { flash(:animals)[:cat] = 'meow' }
552
- app.get('/get_animal') { flash(:animals)[:cat] }
553
- app.get('/set_name') { flash(:names)[:jeff] = 'male' }
554
- app.get('/get_name') { flash(:names)[:jeff] }
555
-
556
- rt.get('/set_animal')
557
- rt.get('/set_name')
558
- rt.get('/get_animal').body.should == 'meow'
559
- rt.get('/get_name').body.should == 'male'
560
- rt.get('/get_animal').body.should == ''
561
- rt.get('/get_name').body.should == ''
562
- end
571
+ rt.get('/set')
572
+ rt.get('/null')
573
+ rt.get('/get').body.should == 'meow'
574
+ rt.get('/get').body.should == ''
563
575
  end
564
- end
565
-
566
- describe "cookie helper" do
567
- it "sets, retrieves and deletes cookies" do
568
- app.get('/') { cookie :test }
569
- app.post('/') { cookie :test, 'hello' }
570
- app.post('/goodbye') { cookie :test, {value: 'goodbye', expires: Time.now() + 999999 } }
571
- app.delete('/') { cookie :test, nil }
572
- app.delete('/alt') { cookie :test, {value: nil} }
576
+
577
+ it "can keep multiple sets of flash session variables" do
578
+ app.get('/set_animal') { flash(:animals)[:cat] = 'meow' }
579
+ app.get('/get_animal') { flash(:animals)[:cat] }
580
+ app.get('/set_name') { flash(:names)[:jeff] = 'male' }
581
+ app.get('/get_name') { flash(:names)[:jeff] }
573
582
 
574
- rt.get('/').body.should == ''
575
- rt.post('/')
576
- rt.get('/').body.should == 'hello'
577
- rt.post('/goodbye')
578
- rt.get('/').body.should == 'goodbye'
579
- rt.delete('/')
580
- rt.get('/').body.should == ''
581
- rt.delete('/alt')
582
- rt.get('/').body.should == ''
583
+ rt.get('/set_animal')
584
+ rt.get('/set_name')
585
+ rt.get('/get_animal').body.should == 'meow'
586
+ rt.get('/get_name').body.should == 'male'
587
+ rt.get('/get_animal').body.should == ''
588
+ rt.get('/get_name').body.should == ''
583
589
  end
584
590
  end
585
-
586
- describe "rendering" do
587
- before(:each) do
588
- app.render_defaults.each { |k,v| app.render_defaults[k] = nil }
589
- end
591
+ end
592
+
593
+ describe "cookie helper" do
594
+ it "sets, retrieves and deletes cookies" do
595
+ app.get('/') { cookie :test }
596
+ app.post('/') { cookie :test, 'hello' }
597
+ app.post('/goodbye') { cookie :test, {value: 'goodbye', expires: Time.now() + 999999 } }
598
+ app.delete('/') { cookie :test, nil }
599
+ app.delete('/alt') { cookie :test, {value: nil} }
600
+
601
+ rt.get('/').body.should == ''
602
+ rt.post('/')
603
+ rt.get('/').body.should == 'hello'
604
+ rt.post('/goodbye')
605
+ rt.get('/').body.should == 'goodbye'
606
+ rt.delete('/')
607
+ rt.get('/').body.should == ''
608
+ rt.delete('/alt')
609
+ rt.get('/').body.should == ''
610
+ end
611
+ end
612
+
613
+ describe "rendering" do
614
+ before(:each) do
615
+ app.render_defaults.each { |k,v| app.render_defaults[k] = nil }
616
+ end
590
617
 
591
- it "can render a file, relative to the application root" do
592
- app.get('/') do
593
- render(:'views/main.erb').should == "3 for me"
594
- end
595
- rt.get('/')
618
+ it "can render a file, relative to the application root" do
619
+ app.get('/') do
620
+ render(:'views/main.erb').should == "3 for me"
596
621
  end
622
+ rt.get('/')
623
+ end
597
624
 
598
- it "can render a string" do
599
- app.get('/') do
600
- render('<%= 1 + 1 %> for you', engine: :erb).should == "2 for you"
601
- end
602
- rt.get('/')
625
+ it "can render a string" do
626
+ app.get('/') do
627
+ render('<%= 1 + 1 %> for you', engine: :erb).should == "2 for you"
603
628
  end
629
+ rt.get('/')
630
+ end
604
631
 
605
- it "takes an optional view directory, relative to the application root" do
606
- app.get('/') do
607
- render(:'main.erb', dir: 'views').should == "3 for me"
608
- end
609
- rt.get('/')
632
+ it "takes an optional view directory, relative to the application root" do
633
+ app.get('/') do
634
+ render(:'main.erb', dir: 'views').should == "3 for me"
610
635
  end
636
+ rt.get('/')
637
+ end
611
638
 
612
- it "takes an optional block to be yielded by the view" do
613
- app.get('/') do
614
- render(:'views/layout.erb'){ "in the middle" }.should == "(in the middle)"
615
- end
616
- rt.get('/')
639
+ it "takes an optional block to be yielded by the view" do
640
+ app.get('/') do
641
+ render(:'views/layout.erb'){ "in the middle" }.should == "(in the middle)"
617
642
  end
643
+ rt.get('/')
644
+ end
618
645
 
619
- it "renders the given layout" do
620
- app.get('/') do
621
- render(:'views/main.erb', layout: :'views/layout.erb').should == "(3 for me)"
622
- end
623
- rt.get('/')
646
+ it "renders the given layout" do
647
+ app.get('/') do
648
+ render(:'views/main.erb', layout: :'views/layout.erb').should == "(3 for me)"
624
649
  end
650
+ rt.get('/')
651
+ end
625
652
 
626
- it "merges options with view config" do
627
- app.get('/') do
628
- render(:'main.erb').should == "3 for me"
629
- end
630
- app.get('/full_path') do
631
- render(:'views/main.erb', {layout: :'views/layout.erb', dir: nil}).should == "(3 for me)"
632
- end
633
- app.render_defaults[:dir] = 'views'
634
- rt.get('/')
635
- rt.get('/full_path')
653
+ it "merges options with view config" do
654
+ app.get('/') do
655
+ render(:'main.erb').should == "3 for me"
656
+ end
657
+ app.get('/full_path') do
658
+ render(:'views/main.erb', {layout: :'views/layout.erb', dir: nil}).should == "(3 for me)"
636
659
  end
660
+ app.render_defaults[:dir] = 'views'
661
+ rt.get('/')
662
+ rt.get('/full_path')
663
+ end
637
664
 
638
- it "derived template engine overrides specified engine" do
639
- app.render_defaults[:dir] = 'views'
640
- app.render_defaults[:engine] = :erb
641
- app.get('/str') do
642
- render(:'other.str').should == "hello hello"
643
- end
644
- app.get('/erb_file') do
645
- render(:main).should == "3 for me"
646
- end
647
- app.get('/erb_string') do
648
- render('<%= 1 + 1 %> for you').should == "2 for you"
649
- end
650
- rt.get('/str')
651
- rt.get('/erb_file')
652
- rt.get('/erb_string')
665
+ it "derived template engine overrides specified engine" do
666
+ app.render_defaults[:dir] = 'views'
667
+ app.render_defaults[:engine] = :erb
668
+ app.get('/str') do
669
+ render(:'other.str').should == "hello hello"
670
+ end
671
+ app.get('/erb_file') do
672
+ render(:main).should == "3 for me"
673
+ end
674
+ app.get('/erb_string') do
675
+ render('<%= 1 + 1 %> for you').should == "2 for you"
653
676
  end
677
+ rt.get('/str')
678
+ rt.get('/erb_file')
679
+ rt.get('/erb_string')
680
+ end
654
681
 
655
- it "ignores default layout when called within a view" do
656
- app.render_defaults << {:dir => 'views', :layout => :layout, :engine => :erb}
657
- app.get('/') do
658
- render :composer
659
- end
660
- rt.get('/').body.should == '({1 for none})'
682
+ it "ignores default layout when called within a view" do
683
+ app.render_defaults << {:dir => 'views', :layout => :layout, :engine => :erb}
684
+ app.get('/') do
685
+ render :composer
661
686
  end
687
+ rt.get('/').body.should == '({1 for none})'
688
+ end
689
+ end
690
+
691
+ describe "url helpers" do
692
+ let(:my_app) do
693
+ Class.new(Scorched::Controller)
694
+ end
695
+
696
+ let(:root_app) do
697
+ Class.new(Scorched::Controller)
662
698
  end
663
699
 
664
- describe "url helpers" do
665
- let(:myapp) do
666
- Class.new(Scorched::Controller)
700
+ let(:app) do
701
+ this = self
702
+ builder = Rack::Builder.new
703
+ builder.map('/myapp') { run this.my_app }
704
+ builder.map('/') { run this.root_app }
705
+ builder.to_app
706
+ end
707
+
708
+ describe "url" do
709
+ it "returns the fully qualified URL" do
710
+ my_app.get('/') { url }
711
+ rt.get('https://scorchedrb.com:73/myapp?something=true').body.should ==
712
+ 'https://scorchedrb.com:73/myapp'
667
713
  end
668
714
 
669
- let(:app) do
670
- the_app = myapp
671
- builder = Rack::Builder.new
672
- builder.map('/myapp') { run the_app }
673
- builder.to_app
715
+ it "can append an optional path" do
716
+ my_app.get('/') { url('hello') }
717
+ rt.get('https://scorchedrb.com:73/myapp?something=true').body.should ==
718
+ 'https://scorchedrb.com:73/myapp/hello'
674
719
  end
675
720
 
676
- describe "url" do
677
- it "returns the fully qualified URL" do
678
- myapp.get('/') { url }
679
- rt.get('https://scorchedrb.com:73/myapp?something=true').body.should ==
680
- 'https://scorchedrb.com:73/myapp'
681
- end
682
-
683
- it "can append an optional path" do
684
- myapp.get('/') { url('hello') }
685
- rt.get('https://scorchedrb.com:73/myapp?something=true').body.should ==
686
- 'https://scorchedrb.com:73/myapp/hello'
687
- end
688
-
689
- it "returns the given URL if scheme detected" do
690
- test_url = 'http://google.com/blah'
691
- myapp.get('/') { url(test_url) }
692
- rt.get('/myapp').body.should == test_url
693
- end
721
+ it "returns the given URL if scheme detected" do
722
+ test_url = 'http://google.com/blah'
723
+ my_app.get('/') { url(test_url) }
724
+ rt.get('/myapp').body.should == test_url
725
+ end
726
+ end
727
+
728
+ describe "absolute" do
729
+ it "returns an absolute URL path" do
730
+ my_app.get('/absolute') { absolute }
731
+ rt.get('http://scorchedrb.com/myapp/absolute?something=true').body.should == '/myapp'
694
732
  end
695
733
 
696
- describe "absolute" do
697
- it "returns an absolute URL path" do
698
- myapp.get('/absolute') { absolute }
699
- rt.get('http://scorchedrb.com/myapp/absolute?something=true').body.should == '/myapp'
700
- end
701
-
702
- it "can append an optional path" do
703
- myapp.get('/absolute') { absolute('hello') }
704
- rt.get('http://scorchedrb.com/myapp/absolute?something=true').body.should == '/myapp/hello'
705
- end
706
-
707
- it "returns the given URL if scheme detected" do
708
- test_url = 'http://google.com/blah'
709
- myapp.get('/') { absolute(test_url) }
710
- rt.get('/myapp').body.should == test_url
711
- end
734
+ it "returns a forward slash if script name is the root of the URL path" do
735
+ root_app.get('/') { absolute }
736
+ rt.get('http://scorchedrb.com').body.should == '/'
737
+ end
738
+
739
+ it "can append an optional path" do
740
+ my_app.get('/absolute') { absolute('hello') }
741
+ rt.get('http://scorchedrb.com/myapp/absolute?something=true').body.should == '/myapp/hello'
742
+ end
743
+
744
+ it "returns the given URL if scheme detected" do
745
+ test_url = 'http://google.com/blah'
746
+ my_app.get('/') { absolute(test_url) }
747
+ rt.get('/myapp').body.should == test_url
712
748
  end
713
749
  end
714
-
715
750
  end
751
+
716
752
  end
717
753
  end
@@ -1,7 +1,8 @@
1
+ ENV['RACK_ENV'] = 'production'
2
+
1
3
  require 'rack/test'
2
4
  require_relative '../lib/scorched.rb'
3
5
 
4
-
5
6
  module Scorched
6
7
  class SimpleCounter
7
8
  def initialize(app)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scorched
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '0.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Wardrop
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-18 00:00:00.000000000 Z
11
+ date: 2013-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.5
33
+ version: '0.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: 0.4.5
40
+ version: '0.4'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: tilt
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -102,6 +102,8 @@ files:
102
102
  - docs/02_fundamentals/08_views.md
103
103
  - docs/02_fundamentals/09_sharing_request_state.md
104
104
  - docs/03_further_reading/be_creative.md
105
+ - docs/03_further_reading/code_reloading.md
106
+ - docs/03_further_reading/running_unit_tests.md
105
107
  - examples/file_upload.ru
106
108
  - examples/media_types.ru
107
109
  - lib/scorched.rb