railties 3.0.0.rc → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/CHANGELOG +80 -75
  2. data/README.rdoc +1 -1
  3. data/guides/assets/stylesheets/main.css +14 -14
  4. data/guides/rails_guides.rb +20 -1
  5. data/guides/rails_guides/generator.rb +7 -7
  6. data/guides/source/2_3_release_notes.textile +5 -5
  7. data/guides/source/3_0_release_notes.textile +4 -3
  8. data/guides/source/action_controller_overview.textile +32 -17
  9. data/guides/source/action_view_overview.textile +44 -44
  10. data/guides/source/active_record_basics.textile +2 -2
  11. data/guides/source/active_record_querying.textile +7 -7
  12. data/guides/source/active_record_validations_callbacks.textile +20 -20
  13. data/guides/source/active_support_core_extensions.textile +370 -198
  14. data/guides/source/ajax_on_rails.textile +17 -17
  15. data/guides/source/api_documentation_guidelines.textile +3 -3
  16. data/guides/source/association_basics.textile +2 -2
  17. data/guides/source/caching_with_rails.textile +5 -5
  18. data/guides/source/command_line.textile +8 -8
  19. data/guides/source/configuring.textile +6 -6
  20. data/guides/source/contributing_to_rails.textile +14 -11
  21. data/guides/source/debugging_rails_applications.textile +8 -6
  22. data/guides/source/form_helpers.textile +1 -1
  23. data/guides/source/generators.textile +34 -30
  24. data/guides/source/getting_started.textile +13 -13
  25. data/guides/source/i18n.textile +12 -1
  26. data/guides/source/index.html.erb +4 -0
  27. data/guides/source/initialization.textile +67 -72
  28. data/guides/source/layout.html.erb +1 -0
  29. data/guides/source/layouts_and_rendering.textile +9 -9
  30. data/guides/source/nested_model_forms.textile +7 -7
  31. data/guides/source/plugins.textile +1 -1
  32. data/guides/source/rails_application_templates.textile +2 -2
  33. data/guides/source/routing.textile +27 -5
  34. data/guides/source/security.textile +6 -6
  35. data/guides/w3c_validator.rb +9 -9
  36. data/lib/rails/application.rb +1 -0
  37. data/lib/rails/application/configuration.rb +1 -1
  38. data/lib/rails/code_statistics.rb +4 -4
  39. data/lib/rails/commands.rb +1 -1
  40. data/lib/rails/commands/dbconsole.rb +1 -1
  41. data/lib/rails/commands/plugin.rb +1 -1
  42. data/lib/rails/commands/runner.rb +1 -1
  43. data/lib/rails/deprecation.rb +31 -52
  44. data/lib/rails/engine.rb +1 -1
  45. data/lib/rails/engine/configuration.rb +28 -1
  46. data/lib/rails/generators.rb +2 -2
  47. data/lib/rails/generators/actions.rb +3 -3
  48. data/lib/rails/generators/active_model.rb +3 -3
  49. data/lib/rails/generators/base.rb +1 -1
  50. data/lib/rails/generators/rails/app/app_generator.rb +9 -3
  51. data/lib/rails/generators/rails/app/templates/Gemfile +2 -2
  52. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +4 -13
  53. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +1 -1
  54. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +4 -0
  55. data/lib/rails/generators/rails/app/templates/config/routes.rb +4 -4
  56. data/lib/rails/generators/rails/app/templates/public/index.html +0 -23
  57. data/lib/rails/generators/rails/app/templates/public/javascripts/effects.js +1 -1
  58. data/lib/rails/generators/rails/generator/USAGE +3 -2
  59. data/lib/rails/generators/rails/migration/USAGE +4 -4
  60. data/lib/rails/generators/rails/plugin/USAGE +1 -1
  61. data/lib/rails/generators/rails/resource/resource_generator.rb +2 -2
  62. data/lib/rails/generators/test_case.rb +1 -1
  63. data/lib/rails/info_controller.rb +1 -1
  64. data/lib/rails/plugin.rb +1 -1
  65. data/lib/rails/rack/log_tailer.rb +2 -5
  66. data/lib/rails/railtie.rb +22 -22
  67. data/lib/rails/script_rails_loader.rb +2 -2
  68. data/lib/rails/tasks/documentation.rake +5 -5
  69. data/lib/rails/tasks/framework.rake +1 -1
  70. data/lib/rails/tasks/routes.rake +23 -9
  71. data/lib/rails/test_unit/testing.rake +3 -2
  72. data/lib/rails/version.rb +1 -1
  73. metadata +10 -10
@@ -62,6 +62,7 @@
62
62
  </dl>
63
63
  <dl class="R">
64
64
  <dt>Digging Deeper</dt>
65
+ <dd><a href="active_support_core_extensions.html">Active Support Core Extensions</a></dd>
65
66
  <dd><a href="i18n.html">Rails Internationalization API</a></dd>
66
67
  <dd><a href="action_mailer_basics.html">Action Mailer Basics</a></dd>
67
68
  <dd><a href="testing.html">Testing Rails Applications</a></dd>
@@ -143,7 +143,7 @@ def update
143
143
  end
144
144
  </ruby>
145
145
 
146
- If the call to +update_attributes+ fails, calling the +update+ action in this controller will render the +edit.html.erb+ template belonging to the same controller.
146
+ If the call to +update_attributes+ fails, calling the +update+ action in this controller will render the +edit.html.erb+ template belonging to the same controller.
147
147
 
148
148
  If you prefer, you can use a symbol instead of a string to specify the action to render:
149
149
 
@@ -200,7 +200,7 @@ render "/u/apps/warehouse_app/current/app/views/products/show"
200
200
  Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the +:file+ option (which was required on Rails 2.2 and earlier):
201
201
 
202
202
  <ruby>
203
- render :file =>
203
+ render :file =>
204
204
  "/u/apps/warehouse_app/current/app/views/products/show"
205
205
  </ruby>
206
206
 
@@ -240,7 +240,7 @@ h5. Using +render+ with +:inline+
240
240
  The +render+ method can do without a view completely, if you're willing to use the +:inline+ option to supply ERB as part of the method call. This is perfectly valid:
241
241
 
242
242
  <ruby>
243
- render :inline =>
243
+ render :inline =>
244
244
  "<% products.each do |p| %><p><%= p.name %><p><% end %>"
245
245
  </ruby>
246
246
 
@@ -249,7 +249,7 @@ WARNING: There is seldom any good reason to use this option. Mixing ERB into you
249
249
  By default, inline rendering uses ERb. You can force it to use Builder instead with the +:type+ option:
250
250
 
251
251
  <ruby>
252
- render :inline =>
252
+ render :inline =>
253
253
  "xml.p {'Horrid coding practice!'}", :type => :builder
254
254
  </ruby>
255
255
 
@@ -676,7 +676,7 @@ h5. Linking to Feeds with +auto_discovery_link_tag+
676
676
  The +auto_discovery_link_tag+ helper builds HTML that most browsers and newsreaders can use to detect the presences of RSS or ATOM feeds. It takes the type of the link (+:rss+ or +:atom+), a hash of options that are passed through to url_for, and a hash of options for the tag:
677
677
 
678
678
  <erb>
679
- <%= auto_discovery_link_tag(:rss, {:action => "feed"},
679
+ <%= auto_discovery_link_tag(:rss, {:action => "feed"},
680
680
  {:title => "RSS Feed"}) %>
681
681
  </erb>
682
682
 
@@ -739,7 +739,7 @@ If you're loading multiple javascript files, you can create a better user experi
739
739
  By default, the combined file will be delivered as +javascripts/all.js+. You can specify a location for the cached asset file instead:
740
740
 
741
741
  <erb>
742
- <%= javascript_include_tag "main", "columns",
742
+ <%= javascript_include_tag "main", "columns",
743
743
  :cache => 'cache/main/display' %>
744
744
  </erb>
745
745
 
@@ -798,7 +798,7 @@ If you're loading multiple CSS files, you can create a better user experience by
798
798
  By default, the combined file will be delivered as +stylesheets/all.css+. You can specify a location for the cached asset file instead:
799
799
 
800
800
  <erb>
801
- <%= stylesheet_link_tag "main", "columns",
801
+ <%= stylesheet_link_tag "main", "columns",
802
802
  :cache => 'cache/main/display' %>
803
803
  </erb>
804
804
 
@@ -1085,7 +1085,7 @@ Partials are very useful in rendering collections. When you pass a collection to
1085
1085
  <p>Product Name: <%= product.name %></p>
1086
1086
  </erb>
1087
1087
 
1088
- When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered.
1088
+ When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered.
1089
1089
 
1090
1090
  In Rails 3.0 there is also a shorthand for this, assuming +@posts+ is a collection of +post+ instances, you can simply do in the +index.html.erb+:
1091
1091
 
@@ -1132,7 +1132,7 @@ With this change, you can access an instance of the +@products+ collection as th
1132
1132
  You can also pass in arbitrary local variables to any partial you are rendering with the +:locals => {}+ option:
1133
1133
 
1134
1134
  <erb>
1135
- <%= render :partial => 'products', :collection => @products,
1135
+ <%= render :partial => 'products', :collection => @products,
1136
1136
  :as => :item, :locals => {:title => "Products Page"} %>
1137
1137
  </erb>
1138
1138
 
@@ -63,7 +63,7 @@ class Person
63
63
  def address
64
64
  Address.new
65
65
  end
66
-
66
+
67
67
  def address_attributes=(attributes)
68
68
  # ...
69
69
  end
@@ -77,7 +77,7 @@ class Person
77
77
  def projects
78
78
  [Project.new, Project.new]
79
79
  end
80
-
80
+
81
81
  def projects_attributes=(attributes)
82
82
  # ...
83
83
  end
@@ -101,7 +101,7 @@ class PeopleController < ActionController:Base
101
101
  @person.built_address
102
102
  2.times { @person.projects.build }
103
103
  end
104
-
104
+
105
105
  def create
106
106
  @person = Person.new(params[:person])
107
107
  if @person.save
@@ -142,7 +142,7 @@ Now add a nested form for the +address+ association:
142
142
  <erb>
143
143
  <%= form_for @person do |f| %>
144
144
  <%= f.text_field :name %>
145
-
145
+
146
146
  <%= f.fields_for :address do |af| %>
147
147
  <%= f.text_field :street %>
148
148
  <% end %>
@@ -154,7 +154,7 @@ This generates:
154
154
  <html>
155
155
  <form action="/people" class="new_person" id="new_person" method="post">
156
156
  <input id="person_name" name="person[name]" size="30" type="text" />
157
-
157
+
158
158
  <input id="person_address_attributes_street" name="person[address_attributes][street]" size="30" type="text" />
159
159
  </form>
160
160
  </html>
@@ -183,7 +183,7 @@ The form code for an association collection is pretty similar to that of a singl
183
183
  <erb>
184
184
  <%= form_for @person do |f| %>
185
185
  <%= f.text_field :name %>
186
-
186
+
187
187
  <%= f.fields_for :projects do |pf| %>
188
188
  <%= f.text_field :name %>
189
189
  <% end %>
@@ -195,7 +195,7 @@ Which generates:
195
195
  <html>
196
196
  <form action="/people" class="new_person" id="new_person" method="post">
197
197
  <input id="person_name" name="person[name]" size="30" type="text" />
198
-
198
+
199
199
  <input id="person_projects_attributes_0_name" name="person[projects_attributes][0][name]" size="30" type="text" />
200
200
  <input id="person_projects_attributes_1_name" name="person[projects_attributes][1][name]" size="30" type="text" />
201
201
  </form>
@@ -323,7 +323,7 @@ Finally, create the +core_ext.rb+ file and add the +to_squawk+ method:
323
323
 
324
324
  <ruby>
325
325
  # vendor/plugins/yaffle/lib/yaffle/core_ext.rb
326
-
326
+
327
327
  String.class_eval do
328
328
  def to_squawk
329
329
  "squawk! #{self}".strip
@@ -79,7 +79,7 @@ plugin 'authentication', :git => 'git://github.com/foor/bar.git'
79
79
  You can even install plugins as git submodules :
80
80
 
81
81
  <ruby>
82
- plugin 'authentication', :git => 'git://github.com/foor/bar.git',
82
+ plugin 'authentication', :git => 'git://github.com/foor/bar.git',
83
83
  :submodule => true
84
84
  </ruby>
85
85
 
@@ -103,7 +103,7 @@ class Object
103
103
  def not_nil?
104
104
  !nil?
105
105
  end
106
-
106
+
107
107
  def not_blank?
108
108
  !blank?
109
109
  end
@@ -313,7 +313,7 @@ To add a member route, just add a +member+ block into the resource block:
313
313
  <ruby>
314
314
  resources :photos do
315
315
  member do
316
- get :preview
316
+ get 'preview'
317
317
  end
318
318
  end
319
319
  </ruby>
@@ -324,7 +324,7 @@ Within the block of member routes, each route name specifies the HTTP verb that
324
324
 
325
325
  <ruby>
326
326
  resources :photos do
327
- get :preview, :on => :member
327
+ get 'preview', :on => :member
328
328
  end
329
329
  </ruby>
330
330
 
@@ -335,7 +335,7 @@ To add a route to the collection:
335
335
  <ruby>
336
336
  resources :photos do
337
337
  collection do
338
- get :search
338
+ get 'search'
339
339
  end
340
340
  end
341
341
  </ruby>
@@ -346,7 +346,7 @@ Just as with member routes, you can pass +:on+ to a route:
346
346
 
347
347
  <ruby>
348
348
  resources :photos do
349
- get :search, :on => :collection
349
+ get 'search', :on => :collection
350
350
  end
351
351
  </ruby>
352
352
 
@@ -501,7 +501,7 @@ class BlacklistConstraint
501
501
  end
502
502
 
503
503
  TwitterClone::Application.routes.draw do
504
- match "*path" => "blacklist#index",
504
+ match "*path" => "blacklist#index",
505
505
  :constraints => BlacklistConstraint.new
506
506
  end
507
507
  </ruby>
@@ -516,6 +516,22 @@ match 'photos/*other' => 'photos#unknown'
516
516
 
517
517
  This route would match +photos/12+ or +/photos/long/path/to/12+, setting +params[:other]+ to +"12"+ or +"long/path/to/12"+.
518
518
 
519
+ Wildcard segments do not need to be last in a route. For example
520
+
521
+ <ruby>
522
+ match 'books/*section/:title' => 'books#show'
523
+ </ruby>
524
+
525
+ would match +books/some/section/last-words-a-memoir+ with +params[:section]+ equals +"some/section"+, and +params[:title]+ equals +"last-words-a-memoir"+.
526
+
527
+ Techincally a route can have even more than one wildard segment indeed, the matcher assigns segments to parameters in an intuitive way. For instance
528
+
529
+ <ruby>
530
+ match '*a/foo/*b' => 'test#index'
531
+ </ruby>
532
+
533
+ would match +zoo/woo/foo/bar/baz+ with +params[:a]+ equals +"zoo/woo"+, and +params[:b]+ equals +"bar/baz"+.
534
+
519
535
  h4. Redirection
520
536
 
521
537
  You can redirect any path to another path using the +redirect+ helper in your router:
@@ -762,6 +778,12 @@ formatted_users GET /users.:format {:controller=>"users", :action=>"index"}
762
778
  POST /users.:format {:controller=>"users", :action=>"create"}
763
779
  </pre>
764
780
 
781
+ You may restrict the listing to the routes that map to a particular controller setting the +CONTROLLER+ environment variable:
782
+
783
+ <shell>
784
+ $ CONTROLLER=users rake routes
785
+ </shell>
786
+
765
787
  TIP: You'll find that the output from +rake routes+ is much more readable if you widen your terminal window until the output lines don't wrap.
766
788
 
767
789
  h4. Testing Routes
@@ -371,7 +371,7 @@ The mass-assignment feature may become a problem, as it allows an attacker to se
371
371
 
372
372
  <ruby>
373
373
  def signup
374
- params[:user] #=> {:name => “ow3ned”, :admin => true}
374
+ params[:user] # => {:name => “ow3ned”, :admin => true}
375
375
  @user = User.new(params[:user])
376
376
  end
377
377
  </ruby>
@@ -385,7 +385,7 @@ Mass-assignment saves you much work, because you don't have to set each value in
385
385
  This will set the following parameters in the controller:
386
386
 
387
387
  <ruby>
388
- params[:user] #=> {:name => “ow3ned”, :admin => true}
388
+ params[:user] # => {:name => “ow3ned”, :admin => true}
389
389
  </ruby>
390
390
 
391
391
  So if you create a new user using mass-assignment, it may be too easy to become an administrator.
@@ -401,7 +401,7 @@ Note that this vulnerability is not restricted to database columns. Any setter
401
401
 
402
402
  class Child < ActiveRecord::Base
403
403
  belongs_to :person
404
- end
404
+ end
405
405
  </ruby>
406
406
 
407
407
  As a result, the vulnerability is extended beyond simply exposing column assignment, allowing attackers the ability to create entirely new records in referenced tables (children in this case).
@@ -423,11 +423,11 @@ attr_accessible :name
423
423
  If you want to set a protected attribute, you will to have to assign it individually:
424
424
 
425
425
  <ruby>
426
- params[:user] #=> {:name => "ow3ned", :admin => true}
426
+ params[:user] # => {:name => "ow3ned", :admin => true}
427
427
  @user = User.new(params[:user])
428
- @user.admin #=> false # not mass-assigned
428
+ @user.admin # => false # not mass-assigned
429
429
  @user.admin = true
430
- @user.admin #=> true
430
+ @user.admin # => true
431
431
  </ruby>
432
432
 
433
433
  A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer:
@@ -21,7 +21,7 @@
21
21
  #
22
22
  # Separate many using commas:
23
23
  #
24
- # # validates only
24
+ # # validates only
25
25
  # ONLY=assoc,migrations rake validate_guides
26
26
  #
27
27
  # ---------------------------------------------------------------------------
@@ -32,13 +32,13 @@ include W3CValidators
32
32
 
33
33
  module RailsGuides
34
34
  class Validator
35
-
35
+
36
36
  def validate
37
37
  validator = MarkupValidator.new
38
38
  STDOUT.sync = true
39
39
  errors_on_guides = {}
40
40
 
41
- guides_to_validate.each do |f|
41
+ guides_to_validate.each do |f|
42
42
  results = validator.validate_file(f)
43
43
 
44
44
  if results.validity
@@ -48,10 +48,10 @@ module RailsGuides
48
48
  errors_on_guides[f] = results.errors
49
49
  end
50
50
  end
51
-
51
+
52
52
  show_results(errors_on_guides)
53
53
  end
54
-
54
+
55
55
  private
56
56
  def guides_to_validate
57
57
  guides = Dir["./guides/output/*.html"]
@@ -65,13 +65,13 @@ module RailsGuides
65
65
  prefixes.any? {|p| guide.start_with?("./guides/output/#{p}")}
66
66
  end
67
67
  end
68
-
68
+
69
69
  def show_results(error_list)
70
70
  if error_list.size == 0
71
71
  puts "\n\nAll checked guides validate OK!"
72
72
  else
73
73
  error_summary = error_detail = ""
74
-
74
+
75
75
  error_list.each_pair do |name, errors|
76
76
  error_summary += "\n #{name}"
77
77
  error_detail += "\n\n #{name} has #{errors.size} validation error(s):\n"
@@ -79,12 +79,12 @@ module RailsGuides
79
79
  error_detail += "\n "+error.to_s.gsub("\n", "")
80
80
  end
81
81
  end
82
-
82
+
83
83
  puts "\n\nThere are #{error_list.size} guides with validation errors:\n" + error_summary
84
84
  puts "\nHere are the detailed errors for each guide:" + error_detail
85
85
  end
86
86
  end
87
-
87
+
88
88
  end
89
89
  end
90
90
 
@@ -205,6 +205,7 @@ module Rails
205
205
  middleware.use ::ActionDispatch::ParamsParser
206
206
  middleware.use ::Rack::MethodOverride
207
207
  middleware.use ::ActionDispatch::Head
208
+ middleware.use ::ActionDispatch::BestStandardsSupport, config.action_dispatch.best_standards_support if config.action_dispatch.best_standards_support
208
209
  end
209
210
  end
210
211
 
@@ -16,9 +16,9 @@ module Rails
16
16
 
17
17
  def initialize(*)
18
18
  super
19
+ self.encoding = "utf-8"
19
20
  @allow_concurrency = false
20
21
  @consider_all_requests_local = false
21
- @encoding = "utf-8"
22
22
  @filter_parameters = []
23
23
  @dependency_loading = true
24
24
  @serve_static_assets = true
@@ -12,7 +12,7 @@ class CodeStatistics #:nodoc:
12
12
  print_header
13
13
  @pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
14
14
  print_splitter
15
-
15
+
16
16
  if @total
17
17
  print_line("Total", @total)
18
18
  print_splitter
@@ -29,7 +29,7 @@ class CodeStatistics #:nodoc:
29
29
  def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
30
30
  stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
31
31
 
32
- Dir.foreach(directory) do |file_name|
32
+ Dir.foreach(directory) do |file_name|
33
33
  if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
34
34
  newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
35
35
  stats.each { |k, v| stats[k] += newstats[k] }
@@ -85,10 +85,10 @@ class CodeStatistics #:nodoc:
85
85
  start = if TEST_TYPES.include? name
86
86
  "| #{name.ljust(20)} "
87
87
  else
88
- "| #{name.ljust(20)} "
88
+ "| #{name.ljust(20)} "
89
89
  end
90
90
 
91
- puts start +
91
+ puts start +
92
92
  "| #{statistics["lines"].to_s.rjust(5)} " +
93
93
  "| #{statistics["codelines"].to_s.rjust(5)} " +
94
94
  "| #{statistics["classes"].to_s.rjust(7)} " +
@@ -70,4 +70,4 @@ In addition to those, there are:
70
70
 
71
71
  All commands can be run with -h for more information.
72
72
  EOT
73
- end
73
+ end
@@ -42,7 +42,7 @@ module Rails
42
42
 
43
43
  def find_cmd(*commands)
44
44
  dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
45
- commands += commands.map{|cmd| "#{cmd}.exe"} if Config::CONFIG['host_os'] =~ /mswin|mingw/
45
+ commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
46
46
 
47
47
  full_path_command = nil
48
48
  found = commands.detect do |cmd|
@@ -375,7 +375,7 @@ module Commands
375
375
  "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
376
376
  o.on( "-e", "--export",
377
377
  "Use svn export to grab the plugin.",
378
- "Exports the plugin, allowing you to check it into your local repository. Does not enable updates, or add an svn:externals entry.") { |v| @method = :export }
378
+ "Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry.") { |v| @method = :export }
379
379
  o.on( "-q", "--quiet",
380
380
  "Suppresses the output from installation.",
381
381
  "Ignored if -v is passed (rails plugin -v install ...)") { |v| @options[:quiet] = true }
@@ -19,7 +19,7 @@ ARGV.clone.options do |opts|
19
19
  opts.on("-h", "--help",
20
20
  "Show this help message.") { $stderr.puts opts; exit }
21
21
 
22
- if Config::CONFIG['host_os'] !~ /mswin|mingw/
22
+ if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/
23
23
  opts.separator ""
24
24
  opts.separator "You can also use runner as a shebang line for your scripts like this:"
25
25
  opts.separator "-------------------------------------------------------------"