railties 6.1.7.9 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -468
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.rdoc +16 -16
  5. data/README.rdoc +0 -1
  6. data/lib/rails/app_updater.rb +2 -4
  7. data/lib/rails/application/bootstrap.rb +17 -5
  8. data/lib/rails/application/configuration.rb +52 -31
  9. data/lib/rails/application/default_middleware_stack.rb +6 -3
  10. data/lib/rails/application/finisher.rb +43 -85
  11. data/lib/rails/application/routes_reloader.rb +8 -0
  12. data/lib/rails/application.rb +24 -50
  13. data/lib/rails/application_controller.rb +2 -2
  14. data/lib/rails/autoloaders/inflector.rb +21 -0
  15. data/lib/rails/autoloaders.rb +12 -16
  16. data/lib/rails/code_statistics.rb +2 -2
  17. data/lib/rails/code_statistics_calculator.rb +10 -1
  18. data/lib/rails/command/base.rb +26 -12
  19. data/lib/rails/command/behavior.rb +1 -1
  20. data/lib/rails/command/environment_argument.rb +1 -1
  21. data/lib/rails/command.rb +8 -5
  22. data/lib/rails/commands/credentials/USAGE +4 -2
  23. data/lib/rails/commands/credentials/credentials_command/diffing.rb +26 -16
  24. data/lib/rails/commands/credentials/credentials_command.rb +6 -2
  25. data/lib/rails/commands/dbconsole/dbconsole_command.rb +16 -15
  26. data/lib/rails/commands/help/USAGE +3 -2
  27. data/lib/rails/commands/runner/runner_command.rb +3 -2
  28. data/lib/rails/commands/server/server_command.rb +2 -5
  29. data/lib/rails/configuration.rb +18 -23
  30. data/lib/rails/engine/configuration.rb +2 -2
  31. data/lib/rails/engine.rb +23 -27
  32. data/lib/rails/gem_version.rb +4 -4
  33. data/lib/rails/generators/actions/create_migration.rb +2 -4
  34. data/lib/rails/generators/actions.rb +35 -13
  35. data/lib/rails/generators/app_base.rb +66 -102
  36. data/lib/rails/generators/app_name.rb +1 -1
  37. data/lib/rails/generators/base.rb +9 -13
  38. data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +2 -0
  39. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +8 -4
  40. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +5 -27
  41. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +7 -3
  42. data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +20 -0
  43. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +7 -16
  44. data/lib/rails/generators/erb.rb +1 -1
  45. data/lib/rails/generators/generated_attribute.rb +40 -4
  46. data/lib/rails/generators/migration.rb +2 -6
  47. data/lib/rails/generators/model_helpers.rb +1 -1
  48. data/lib/rails/generators/named_base.rb +1 -1
  49. data/lib/rails/generators/rails/app/app_generator.rb +44 -88
  50. data/lib/rails/generators/rails/app/templates/Gemfile.tt +41 -52
  51. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +2 -2
  52. data/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb.tt +2 -2
  53. data/lib/rails/generators/rails/app/templates/app/models/application_record.rb.tt +1 -1
  54. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +3 -10
  55. data/lib/rails/generators/rails/app/templates/bin/rails.tt +1 -4
  56. data/lib/rails/generators/rails/app/templates/bin/rake.tt +0 -3
  57. data/lib/rails/generators/rails/app/templates/bin/setup.tt +9 -14
  58. data/lib/rails/generators/rails/app/templates/config/boot.rb.tt +1 -1
  59. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +2 -2
  60. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +3 -3
  61. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +3 -3
  62. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +2 -2
  63. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  64. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +2 -2
  65. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +3 -3
  66. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  67. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +5 -5
  68. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +2 -11
  69. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +9 -15
  70. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +2 -7
  71. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -5
  72. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +0 -5
  73. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +2 -2
  74. data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb.tt +4 -4
  75. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +85 -0
  76. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +3 -3
  77. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +1 -1
  78. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -0
  79. data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +5 -5
  80. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +2 -2
  81. data/lib/rails/generators/rails/app/templates/gitattributes.tt +0 -5
  82. data/lib/rails/generators/rails/app/templates/gitignore.tt +0 -1
  83. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +1 -1
  84. data/lib/rails/generators/rails/controller/controller_generator.rb +1 -2
  85. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +0 -4
  86. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  87. data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +1 -1
  88. data/lib/rails/generators/rails/plugin/plugin_generator.rb +40 -15
  89. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +4 -2
  90. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +9 -9
  91. data/lib/rails/generators/rails/plugin/templates/README.md.tt +1 -1
  92. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +2 -2
  93. data/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +1 -1
  94. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +0 -3
  95. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +4 -4
  96. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -5
  97. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +2 -2
  98. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb.tt +1 -1
  99. data/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt +2 -2
  100. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +3 -3
  101. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +0 -19
  102. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +1 -5
  103. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +6 -10
  104. data/lib/rails/generators/resource_helpers.rb +2 -2
  105. data/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt +1 -1
  106. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +2 -2
  107. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +3 -3
  108. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +5 -5
  109. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  110. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +3 -3
  111. data/lib/rails/generators/testing/behaviour.rb +1 -2
  112. data/lib/rails/generators.rb +9 -22
  113. data/lib/rails/info.rb +1 -1
  114. data/lib/rails/info_controller.rb +1 -3
  115. data/lib/rails/initializable.rb +1 -1
  116. data/lib/rails/mailers_controller.rb +2 -4
  117. data/lib/rails/rack/logger.rb +0 -1
  118. data/lib/rails/railtie/configuration.rb +1 -2
  119. data/lib/rails/railtie.rb +9 -9
  120. data/lib/rails/ruby_version_check.rb +3 -3
  121. data/lib/rails/secrets.rb +8 -10
  122. data/lib/rails/tasks/framework.rake +2 -8
  123. data/lib/rails/tasks/statistics.rake +3 -1
  124. data/lib/rails/tasks/tmp.rake +8 -1
  125. data/lib/rails/tasks/yarn.rake +5 -1
  126. data/lib/rails/tasks/zeitwerk.rake +2 -10
  127. data/lib/rails/templates/layouts/application.html.erb +15 -0
  128. data/lib/rails/templates/rails/mailers/email.html.erb +12 -10
  129. data/lib/rails/templates/rails/welcome/index.html.erb +3 -0
  130. data/lib/rails/test_unit/railtie.rb +0 -4
  131. data/lib/rails/test_unit/runner.rb +7 -5
  132. data/lib/rails/test_unit/testing.rake +4 -9
  133. data/lib/rails.rb +1 -0
  134. metadata +34 -36
  135. data/lib/rails/command/spellchecker.rb +0 -57
  136. data/lib/rails/generators/css/assets/assets_generator.rb +0 -15
  137. data/lib/rails/generators/css/assets/templates/stylesheet.css +0 -4
  138. data/lib/rails/generators/css/scaffold/scaffold_generator.rb +0 -18
  139. data/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js +0 -6
  140. data/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js +0 -5
  141. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +0 -23
  142. data/lib/rails/generators/rails/app/templates/bin/spring.tt +0 -13
  143. data/lib/rails/generators/rails/app/templates/bin/yarn.tt +0 -16
  144. data/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb.tt +0 -8
  145. data/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb.tt +0 -5
  146. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt +0 -67
  147. data/lib/rails/generators/rails/app/templates/config/spring.rb.tt +0 -6
  148. data/lib/rails/generators/rails/app/templates/package.json.tt +0 -11
  149. data/lib/rails/generators/rails/assets/USAGE +0 -16
  150. data/lib/rails/generators/rails/assets/assets_generator.rb +0 -26
  151. data/lib/rails/generators/rails/assets/templates/stylesheet.css +0 -4
  152. data/lib/rails/generators/rails/scaffold/templates/scaffold.css +0 -80
@@ -6,10 +6,11 @@ The most common rails commands are:
6
6
  test:system Run system tests
7
7
  dbconsole Start a console for the database specified in config/database.yml
8
8
  (short-cut alias: "db")
9
- <% unless engine? %>
9
+ <% unless engine? -%>
10
10
  new Create a new Rails application. "rails new my_app" creates a
11
11
  new application called MyApp in "./my_app"
12
- <% end %>
12
+ plugin new Create a new Rails railtie or engine
13
+ <% end -%>
13
14
 
14
15
  All commands can be run with -h (or --help) for more information.
15
16
  In addition to those commands, there are:
@@ -38,8 +38,9 @@ module Rails
38
38
  if code_or_file == "-"
39
39
  eval($stdin.read, TOPLEVEL_BINDING, "stdin")
40
40
  elsif File.exist?(code_or_file)
41
- $0 = code_or_file
42
- Kernel.load code_or_file
41
+ expanded_file_path = File.expand_path code_or_file
42
+ $0 = expanded_file_path
43
+ Kernel.load expanded_file_path
43
44
  else
44
45
  begin
45
46
  eval(code_or_file, TOPLEVEL_BINDING, __FILE__, __LINE__)
@@ -4,7 +4,6 @@ require "fileutils"
4
4
  require "action_dispatch"
5
5
  require "rails"
6
6
  require "active_support/core_ext/string/filters"
7
- require "active_support/core_ext/symbol/starts_ends_with"
8
7
  require "rails/dev_caching"
9
8
  require "rails/command/environment_argument"
10
9
 
@@ -263,11 +262,9 @@ module Rails
263
262
  Run `bin/rails server --help` for more options.
264
263
  MSG
265
264
  else
266
- suggestion = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS)
267
- suggestion_msg = "Maybe you meant #{suggestion.inspect}?" if suggestion
268
-
265
+ error = CorrectableError.new("Could not find server '#{server}'.", server, RACK_SERVERS)
269
266
  <<~MSG
270
- Could not find server "#{server}". #{suggestion_msg}
267
+ #{error.message}
271
268
  Run `bin/rails server --help` for more options.
272
269
  MSG
273
270
  end
@@ -49,48 +49,43 @@ module Rails
49
49
  @delete_operations = delete_operations
50
50
  end
51
51
 
52
- def insert_before(*args, &block)
53
- @operations << -> middleware { middleware.insert_before(*args, &block) }
52
+ def insert_before(...)
53
+ @operations << -> middleware { middleware.insert_before(...) }
54
54
  end
55
- ruby2_keywords(:insert_before) if respond_to?(:ruby2_keywords, true)
56
55
 
57
56
  alias :insert :insert_before
58
57
 
59
- def insert_after(*args, &block)
60
- @operations << -> middleware { middleware.insert_after(*args, &block) }
58
+ def insert_after(...)
59
+ @operations << -> middleware { middleware.insert_after(...) }
61
60
  end
62
- ruby2_keywords(:insert_after) if respond_to?(:ruby2_keywords, true)
63
61
 
64
- def swap(*args, &block)
65
- @operations << -> middleware { middleware.swap(*args, &block) }
62
+ def swap(...)
63
+ @operations << -> middleware { middleware.swap(...) }
66
64
  end
67
- ruby2_keywords(:swap) if respond_to?(:ruby2_keywords, true)
68
65
 
69
- def use(*args, &block)
70
- @operations << -> middleware { middleware.use(*args, &block) }
66
+ def use(...)
67
+ @operations << -> middleware { middleware.use(...) }
71
68
  end
72
- ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
73
69
 
74
- def delete(*args, &block)
75
- @delete_operations << -> middleware { middleware.delete(*args, &block) }
70
+ def delete(...)
71
+ @delete_operations << -> middleware { middleware.delete(...) }
76
72
  end
77
73
 
78
- def move_before(*args, &block)
79
- @delete_operations << -> middleware { middleware.move_before(*args, &block) }
74
+ def move_before(...)
75
+ @delete_operations << -> middleware { middleware.move_before(...) }
80
76
  end
81
77
 
82
78
  alias :move :move_before
83
79
 
84
- def move_after(*args, &block)
85
- @delete_operations << -> middleware { middleware.move_after(*args, &block) }
80
+ def move_after(...)
81
+ @delete_operations << -> middleware { middleware.move_after(...) }
86
82
  end
87
83
 
88
- def unshift(*args, &block)
89
- @operations << -> middleware { middleware.unshift(*args, &block) }
84
+ def unshift(...)
85
+ @operations << -> middleware { middleware.unshift(...) }
90
86
  end
91
- ruby2_keywords(:unshift) if respond_to?(:ruby2_keywords, true)
92
87
 
93
- def merge_into(other) #:nodoc:
88
+ def merge_into(other) # :nodoc:
94
89
  (@operations + @delete_operations).each do |operation|
95
90
  operation.call(other)
96
91
  end
@@ -106,7 +101,7 @@ module Rails
106
101
  attr_reader :operations, :delete_operations
107
102
  end
108
103
 
109
- class Generators #:nodoc:
104
+ class Generators # :nodoc:
110
105
  attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging, :api_only
111
106
  attr_reader :hidden_namespaces, :after_generate_callbacks
112
107
 
@@ -55,9 +55,9 @@ module Rails
55
55
  paths.add "lib/tasks", glob: "**/*.rake"
56
56
 
57
57
  paths.add "config"
58
- paths.add "config/environments", glob: "#{Rails.env}.rb"
58
+ paths.add "config/environments", glob: -"#{Rails.env}.rb"
59
59
  paths.add "config/initializers", glob: "**/*.rb"
60
- paths.add "config/locales", glob: "*.{rb,yml}"
60
+ paths.add "config/locales", glob: "**/*.{rb,yml}"
61
61
  paths.add "config/routes.rb"
62
62
  paths.add "config/routes", glob: "**/*.rb"
63
63
 
data/lib/rails/engine.rb CHANGED
@@ -33,7 +33,7 @@ module Rails
33
33
  # Then ensure that this file is loaded at the top of your <tt>config/application.rb</tt>
34
34
  # (or in your +Gemfile+) and it will automatically load models, controllers and helpers
35
35
  # inside +app+, load routes at <tt>config/routes.rb</tt>, load locales at
36
- # <tt>config/locales/*</tt>, and load tasks at <tt>lib/tasks/*</tt>.
36
+ # <tt>config/locales/**/*</tt>, and load tasks at <tt>lib/tasks/**/*</tt>.
37
37
  #
38
38
  # == Configuration
39
39
  #
@@ -482,17 +482,8 @@ module Rails
482
482
  end
483
483
 
484
484
  def eager_load!
485
- # Already done by Zeitwerk::Loader.eager_load_all. We need this guard to
486
- # easily provide a compatible API for both zeitwerk and classic modes.
487
- return if Rails.autoloaders.zeitwerk_enabled?
488
-
489
- config.eager_load_paths.each do |load_path|
490
- # Starts after load_path plus a slash, ends before ".rb".
491
- relname_range = (load_path.to_s.length + 1)...-3
492
- Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
493
- require_dependency file[relname_range]
494
- end
495
- end
485
+ # Already done by Zeitwerk::Loader.eager_load_all. By now, we leave the
486
+ # method as a no-op for backwards compatibility.
496
487
  end
497
488
 
498
489
  def railties
@@ -579,17 +570,14 @@ module Rails
579
570
  $LOAD_PATH.uniq!
580
571
  end
581
572
 
582
- # Set the paths from which Rails will automatically load source files,
583
- # and the load_once paths.
584
- #
585
- # This needs to be an initializer, since it needs to run once
586
- # per engine and get the engine as a block parameter.
587
- initializer :set_autoload_paths, before: :bootstrap_hook do
588
- ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
573
+ initializer :set_autoload_once_paths, before: :setup_once_autoloader do
574
+ config.autoload_once_paths.freeze
589
575
  ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths)
576
+ end
590
577
 
578
+ initializer :set_autoload_paths, before: :setup_main_autoloader do
591
579
  config.autoload_paths.freeze
592
- config.autoload_once_paths.freeze
580
+ ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
593
581
  end
594
582
 
595
583
  initializer :set_eager_load_paths, before: :bootstrap_hook do
@@ -665,12 +653,12 @@ module Rails
665
653
  end
666
654
  end
667
655
 
668
- def routes? #:nodoc:
656
+ def routes? # :nodoc:
669
657
  @routes
670
658
  end
671
659
 
672
660
  protected
673
- def run_tasks_blocks(*) #:nodoc:
661
+ def run_tasks_blocks(*) # :nodoc:
674
662
  super
675
663
  paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
676
664
  end
@@ -686,7 +674,7 @@ module Rails
686
674
  paths["db/migrate"].existent.any?
687
675
  end
688
676
 
689
- def self.find_root_with_flag(flag, root_path, default = nil) #:nodoc:
677
+ def self.find_root_with_flag(flag, root_path, default = nil) # :nodoc:
690
678
  while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
691
679
  parent = File.dirname(root_path)
692
680
  root_path = parent != root_path && parent
@@ -703,17 +691,25 @@ module Rails
703
691
  end
704
692
 
705
693
  def _all_autoload_once_paths
706
- config.autoload_once_paths
694
+ config.autoload_once_paths.uniq
707
695
  end
708
696
 
709
697
  def _all_autoload_paths
710
- @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
698
+ @_all_autoload_paths ||= begin
699
+ autoload_paths = config.autoload_paths
700
+ autoload_paths += config.eager_load_paths
701
+ autoload_paths -= config.autoload_once_paths
702
+ autoload_paths.uniq
703
+ end
711
704
  end
712
705
 
713
706
  def _all_load_paths(add_autoload_paths_to_load_path)
714
707
  @_all_load_paths ||= begin
715
- load_paths = config.paths.load_paths
716
- load_paths += _all_autoload_paths if add_autoload_paths_to_load_path
708
+ load_paths = config.paths.load_paths
709
+ if add_autoload_paths_to_load_path
710
+ load_paths += _all_autoload_paths
711
+ load_paths += _all_autoload_once_paths
712
+ end
717
713
  load_paths.uniq
718
714
  end
719
715
  end
@@ -7,10 +7,10 @@ module Rails
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 7
13
- PRE = "9"
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "alpha1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -6,7 +6,7 @@ require "thor/actions"
6
6
  module Rails
7
7
  module Generators
8
8
  module Actions
9
- class CreateMigration < Thor::Actions::CreateFile #:nodoc:
9
+ class CreateMigration < Thor::Actions::CreateFile # :nodoc:
10
10
  def migration_dir
11
11
  File.dirname(@destination)
12
12
  end
@@ -39,10 +39,8 @@ module Rails
39
39
  end
40
40
 
41
41
  def existing_migration
42
- @existing_migration ||= begin
43
- @base.class.migration_exists?(migration_dir, migration_file_name) ||
42
+ @existing_migration ||= @base.class.migration_exists?(migration_dir, migration_file_name) ||
44
43
  File.exist?(@destination) && @destination
45
- end
46
44
  end
47
45
  alias :exists? :existing_migration
48
46
 
@@ -18,6 +18,7 @@ module Rails
18
18
  # gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/"
19
19
  # gem "rails", "3.0", git: "https://github.com/rails/rails"
20
20
  # gem "RedCloth", ">= 4.1.0", "< 4.2.0"
21
+ # gem "rspec", comment: "Put this comment above the gem declaration"
21
22
  def gem(*args)
22
23
  options = args.extract_options!
23
24
  name, *versions = args
@@ -26,6 +27,9 @@ module Rails
26
27
  # otherwise use name (version).
27
28
  parts, message = [ quote(name) ], name.dup
28
29
 
30
+ # Output a comment above the gem declaration.
31
+ comment = options.delete(:comment)
32
+
29
33
  if versions = versions.any? ? versions : options.delete(:version)
30
34
  _versions = Array(versions)
31
35
  _versions.each do |version|
@@ -40,9 +44,17 @@ module Rails
40
44
  parts << quote(options) unless options.empty?
41
45
 
42
46
  in_root do
43
- str = "gem #{parts.join(", ")}"
44
- str = indentation + str
45
- append_file_with_newline "Gemfile", str, verbose: false
47
+ str = []
48
+ if comment
49
+ comment.each_line do |comment_line|
50
+ str << indentation
51
+ str << "# #{comment_line}"
52
+ end
53
+ str << "\n"
54
+ end
55
+ str << indentation
56
+ str << "gem #{parts.join(", ")}"
57
+ append_file_with_newline "Gemfile", str.join, verbose: false
46
58
  end
47
59
  end
48
60
 
@@ -268,14 +280,25 @@ module Rails
268
280
  # route "root 'admin#index'", namespace: :admin
269
281
  def route(routing_code, namespace: nil)
270
282
  routing_code = Array(namespace).reverse.reduce(routing_code) do |code, ns|
271
- "namespace :#{ns} do\n#{indent(code, 2)}\nend"
283
+ "namespace :#{ns} do\n#{optimize_indentation(code, 2)}end"
272
284
  end
273
285
 
274
286
  log :route, routing_code
275
- sentinel = /\.routes\.draw do\s*\n/m
287
+
288
+ after_pattern = Array(namespace).each_with_index.reverse_each.reduce(nil) do |pattern, (ns, i)|
289
+ margin = "\\#{i + 1}[ ]{2}"
290
+ "(?:(?:^[ ]*\n|^#{margin}.*\n)*?^(#{margin})namespace :#{ns} do\n#{pattern})?"
291
+ end.then do |pattern|
292
+ /^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
293
+ end
276
294
 
277
295
  in_root do
278
- inject_into_file "config/routes.rb", optimize_indentation(routing_code, 2), after: sentinel, verbose: false, force: false
296
+ if existing = match_file("config/routes.rb", after_pattern)
297
+ base_indent, *, prev_indent = existing.captures.compact.map(&:length)
298
+ routing_code = optimize_indentation(routing_code, base_indent + 2).lines.grep_v(/^[ ]{,#{prev_indent}}\S/).join
299
+ end
300
+
301
+ inject_into_file "config/routes.rb", routing_code, after: after_pattern, verbose: false, force: false
279
302
  end
280
303
  end
281
304
 
@@ -323,8 +346,7 @@ module Rails
323
346
  end
324
347
  end
325
348
 
326
- # Surround string with single quotes if there is no quotes.
327
- # Otherwise fall back to double quotes
349
+ # Always returns value in double quotes.
328
350
  def quote(value) # :doc:
329
351
  if value.respond_to? :each_pair
330
352
  return value.map do |k, v|
@@ -333,11 +355,7 @@ module Rails
333
355
  end
334
356
  return value.inspect unless value.is_a? String
335
357
 
336
- if value.include?("'")
337
- value.inspect
338
- else
339
- "'#{value}'"
340
- end
358
+ "\"#{value.tr("'", '"')}\""
341
359
  end
342
360
 
343
361
  # Returns optimized string with indentation
@@ -365,6 +383,10 @@ module Rails
365
383
  match.end_with?("\n") ? "" : "\n#{str}\n"
366
384
  end
367
385
  end
386
+
387
+ def match_file(path, pattern)
388
+ File.read(path).match(pattern) if File.exist?(path)
389
+ end
368
390
  end
369
391
  end
370
392
  end