diff --git a/lib/application_checker.rb b/lib/application_checker.rb index c0e5e8b..21dce00 100644 --- a/lib/application_checker.rb +++ b/lib/application_checker.rb @@ -5,22 +5,22 @@ module Rails class ApplicationChecker def initialize @issues = [] - + raise NotInRailsAppError unless in_rails_app? end - + def in_rails_app? File.exist?("config/environment.rb") end - + # Run all the check methods def run # Ruby 1.8 returns method names as strings whereas 1.9 uses symbols the_methods = (self.public_methods - Object.methods) - [:run, :initialize, "run", "initialize"] - + the_methods.each {|m| send m } end - + # Check for deprecated ActiveRecord calls def check_ar_methods files = [] @@ -28,10 +28,10 @@ module Rails lines = grep_for(v, "app/") files += extract_filenames(lines) || [] end - + unless files.empty? alert( - "Soon-to-be-deprecated ActiveRecord calls", + "Soon-to-be-deprecated ActiveRecord calls", "Methods such as find(:all), find(:first), finds with conditions, and the :joins option will soon be deprecated.", "http://m.onkey.org/2010/1/22/active-record-query-interface", files @@ -40,33 +40,33 @@ module Rails lines = grep_for("named_scope", "app/models/") files = extract_filenames(lines) - + if files alert( - "named_scope is now just scope", + "named_scope is now just scope", "The named_scope method has been renamed to just scope.", "http://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914", files ) end end - + # Check for deprecated router syntax def check_routes lines = ["map\\.", "ActionController::Routing::Routes", "\\.resources"].map do |v| grep_for(v, "config/routes.rb").empty? ? nil : true end.compact - + unless lines.empty? alert( - "Old router API", + "Old router API", "The router API has totally changed.", "http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/", "config/routes.rb" ) end end - + # Check for deprecated test_help require def check_test_help files = [] @@ -77,121 +77,121 @@ module Rails lines = grep_for("\"test_help\"", "test/") files += extract_filenames(lines) || [] - + files.uniq! - + unless files.empty? alert( - "Deprecated test_help path", + "Deprecated test_help path", "You now must require 'rails/test_help' not just 'test_help'.", "http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices", files ) end end - + # Check for old (pre-application.rb) environment.rb file def check_environment unless File.exist?("config/application.rb") alert( - "New file needed: config/application.rb", + "New file needed: config/application.rb", "You need to add a config/application.rb.", "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", "config/application.rb" ) end - + lines = grep_for("config.", "config/environment.rb") - + unless lines.empty? alert( - "Old environment.rb", + "Old environment.rb", "environment.rb doesn't do what it used to; you'll need to move some of that into application.rb.", "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", "config/environment.rb" ) end end - + # Check for deprecated constants def check_deprecated_constants files = [] ["RAILS_ENV", "RAILS_ROOT", "RAILS_DEFAULT_LOGGER"].each do |v| lines = grep_for(v, "app/") files += extract_filenames(lines) || [] - + lines = grep_for(v, "lib/") files += extract_filenames(lines) || [] end - + unless files.empty? alert( - "Deprecated constant(s)", + "Deprecated constant(s)", "Constants like RAILS_ENV, RAILS_ROOT, and RAILS_DEFAULT_LOGGER are now deprecated.", "http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/", files.uniq ) end end - + # Check for old-style config.gem calls def check_gems lines = grep_for("config.gem ", "config/*.rb") files = extract_filenames(lines) - + if files alert( - "Old gem bundling (config.gems)", + "Old gem bundling (config.gems)", "The old way of bundling is gone now. You need a Gemfile for bundler.", "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", files ) end end - + # Checks for old mailer syntax in both mailer classes and those # classes utilizing the mailers def check_mailers lines = grep_for("deliver_", "app/models/ #{base_path}app/controllers/ #{base_path}app/observers/") files = extract_filenames(lines) - + if files alert( - "Deprecated ActionMailer API", + "Deprecated ActionMailer API", "You're using the old ActionMailer API to send e-mails in a controller, model, or observer.", "http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3", files ) end - + files = [] ["recipients ", "attachment ", "subject ", "from "].each do |v| lines = grep_for(v, "app/models/") files += extract_filenames(lines) || [] end - + unless files.empty? alert( - "Old ActionMailer class API", + "Old ActionMailer class API", "You're using the old API in a mailer class.", "http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3", files ) end end - + # Checks for old-style generators def check_generators generators = Dir.glob(base_path + "vendor/plugins/**/generators/**/") - + unless generators.empty? files = generators.map do |g| grep_for("def manifest", g).empty? ? g : nil end.compact - + if !files.empty? alert( - "Old Rails generator API", + "Old Rails generator API", "A plugin in the app is using the old generator API (a new one may be available at http://github.com/trydionel/rails3-generators).", "http://blog.plataformatec.com.br/2010/01/discovering-rails-3-generators/", files @@ -199,43 +199,43 @@ module Rails end end end - + # Checks a list of known broken plugins and gems def check_plugins # This list is off the wiki; will need to be updated often, esp. since RSpec is working on it bad_plugins = ["rspec", "rspec-rails", "hoptoad", "authlogic", "nifty-generators", "restful_authentication", "searchlogic", "cucumber", "cucumber-rails", "devise", "inherited_resources"] - - bad_plugins = bad_plugins.map do |p| + + bad_plugins = bad_plugins.map do |p| p if File.exist?("#{base_path}vendor/plugins/#{p}") || !Dir.glob("#{base_path}vendor/gems/#{p}-*").empty? end.compact unless bad_plugins.empty? alert( - "Known broken plugins", + "Known broken plugins", "At least one plugin in your app is broken (according to the wiki). Most of project maintainers are rapidly working towards compatability, but do be aware you may encounter issues.", "http://wiki.rubyonrails.org/rails/version3/plugins_and_gems", bad_plugins ) end end - + # Checks for old-style ERb helpers def check_old_helpers lines = grep_for("<% .* do.*%>", "app/views/**/*") files = extract_filenames(lines) - + if files alert( - "Deprecated ERb helper calls", + "Deprecated ERb helper calls", "Block helpers that use concat (e.g., form_for) should use <%= instead of <%. The current form will continue to work for now, but you will get deprecation warnings since this form will go away in the future.", "http://weblog.rubyonrails.org/", files ) end end - + # Checks for old-style AJAX helpers def check_old_ajax_helpers files = [] @@ -244,17 +244,17 @@ module Rails inner_files = extract_filenames(lines) files += inner_files unless inner_files.nil? end - - if files + + unless files.empty? alert( - "Deprecated AJAX helper calls", + "Deprecated AJAX helper calls", "AJAX javascript helpers have been switched to be unobtrusive and use :remote => true instead of having a seperate function to handle remote requests.", "http://www.themodestrubyist.com/2010/02/24/rails-3-ujs-and-csrf-meta-tags/", files ) end end - + # Checks for old cookie secret settings def check_old_cookie_secret lines = grep_for("ActionController::Base.cookie_verifier_secret = ", "config/**/*") @@ -262,7 +262,7 @@ module Rails if files alert( - "Deprecated cookie secret setting", + "Deprecated cookie secret setting", "Previously, cookie secret was set directly on ActionController::Base; it's now config.secret_token.", "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", files @@ -276,29 +276,29 @@ module Rails if files alert( - "Deprecated session secret setting", + "Deprecated session secret setting", "Previously, session secret was set directly on ActionController::Base; it's now config.secret_token.", "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", files ) end end - + # Checks for old session settings def check_old_session_setting lines = grep_for("ActionController::Base.session_store", "config/**/*") files = extract_filenames(lines) - + if files alert( - "Old session store setting", + "Old session store setting", "Previously, session store was set directly on ActionController::Base; it's now config.session_store :whatever.", "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", files ) end end - + private # Find a string in a set of files; calls +find_with_grep+ and +find_with_rak+ # depending on platform. @@ -313,18 +313,18 @@ module Rails else find_with_rak(text, base_path + where, double_quote) end - + # ignore comments lines.gsub! /^\s*#.+$/m, "" - + lines end - + # Sets a base path for finding files; mostly for testing def base_path Dir.pwd + "/" end - + # Use the grep utility to find a string in a set of files def find_with_grep(text, where, double_quote) value = "" @@ -334,14 +334,14 @@ module Rails else "grep -r --exclude=\*.svn\* '#{text}' #{where}" end - + Open3.popen3(command) do |stdin, stdout, stderr| value = stdout.read end - + value end - + # Use the rak gem to grep the files (not yet implemented) def find_with_rak(text, where, double_quote) value = "" @@ -349,10 +349,10 @@ module Rails Open3.popen3("rak --nogroup -l '#{Regexp.escape(text)}' #{where}") do |stdin, stdout, stderr| value = stdout.read end - + value end - + # Extract the filenames from the grep output def extract_filenames(output) if @probably_has_grep @@ -361,25 +361,25 @@ module Rails extract_filenames_from_rak(output) end end - + def extract_filenames_from_grep(output) return nil if output.empty? - - fnames = output.split("\n").map do |fn| + + fnames = output.split("\n").map do |fn| if m = fn.match(/^(.+?):/) m[1] end end.compact - + fnames.uniq end - + def extract_filenames_from_rak(output) return nil if output.empty? - + output.split("\n").uniq end - + # Terminal colors, borrowed from Thor CLEAR = "\e[0m" BOLD = "\e[1m" @@ -387,7 +387,7 @@ module Rails YELLOW = "\e[33m" CYAN = "\e[36m" WHITE = "\e[37m" - + # Show an upgrade alert to the user def alert(title, text, more_info_url, culprits) if Config::CONFIG['host_os'].downcase =~ /mswin|windows|mingw/ @@ -396,7 +396,7 @@ module Rails color_alert(title, text, more_info_url, culprits) end end - + # Show an upgrade alert to the user. If we're on Windows, we can't # use terminal colors, hence this method. def basic_alert(title, text, more_info_url, culprits) @@ -410,7 +410,7 @@ module Rails end puts end - + # Show a colorful alert to the user def color_alert(title, text, more_info_url, culprits) puts "#{RED}#{BOLD}#{title}#{CLEAR}" diff --git a/test/application_checker_test.rb b/test/application_checker_test.rb index 085a0f2..40031d5 100644 --- a/test/application_checker_test.rb +++ b/test/application_checker_test.rb @@ -16,19 +16,19 @@ module Rails module Upgrading class ApplicationChecker attr_reader :alerts - + def base_path BASE_ROOT + "/" end - + def in_rails_app? true end - + def initialize @alerts = {} end - + def alert(title, text, more_info_url, culprits) @alerts[title] = [text, more_info_url, culprits] end @@ -40,125 +40,125 @@ class ApplicationCheckerTest < ActiveSupport::TestCase def setup @checker = Rails::Upgrading::ApplicationChecker.new @old_dir = Dir.pwd - + Dir.chdir(BASE_ROOT) end - + def test_check_ar_methods_in_controller make_file("app/controllers", "post_controller.rb", "Post.find(:all)") @checker.check_ar_methods assert @checker.alerts.has_key?("Soon-to-be-deprecated ActiveRecord calls") end - + def test_check_ar_methods_in_models make_file("app/models", "post.rb", "Post.find(:all)") @checker.check_ar_methods assert @checker.alerts.has_key?("Soon-to-be-deprecated ActiveRecord calls") end - + def test_named_scope_left_over make_file("app/models", "post.rb", "named_scope :failure") @checker.check_ar_methods assert @checker.alerts.has_key?("named_scope is now just scope") end - + def test_check_routes make_file("config/", "routes.rb", " map.connect 'fail'") @checker.check_routes assert @checker.alerts.has_key?("Old router API") end - + def test_check_for_old_test_help make_file("test/", "test_helper.rb", " require 'test_help'") @checker.check_test_help assert @checker.alerts.has_key?("Deprecated test_help path") end - + def test_check_for_old_test_help_with_double_quotes make_file("test/", "test_helper.rb", " require \"test_help\"") @checker.check_test_help assert @checker.alerts.has_key?("Deprecated test_help path") end - + def test_check_for_old_test_help_doesnt_see_test_helper make_file("test/", "test_helper.rb", " require 'test_helper'") @checker.check_test_help assert !@checker.alerts.has_key?("Deprecated test_help path") end - + def test_check_lack_of_app_dot_rb @checker.check_environment assert @checker.alerts.has_key?("New file needed: config/application.rb") end - + def test_check_environment_syntax make_file("config/", "environment.rb", "config.frameworks = []") @checker.check_environment - - assert @checker.alerts.has_key?("Old environment.rb") + + assert @checker.alerts.has_key?("Old environment.rb") end - + def test_check_gems make_file("config/", "environment.rb", "config.gem 'rails'") @checker.check_gems - + assert @checker.alerts.has_key?("Old gem bundling (config.gems)") end - + def test_check_mailer_syntax make_file("app/models/", "notifications.rb", "def signup\nrecipients @users\n end") @checker.check_mailers assert @checker.alerts.has_key?("Old ActionMailer class API") end - + def test_check_mailer_api make_file("app/controllers/", "thing_controller.rb", "def signup\n Notifications.deliver_signup\n end") @checker.check_mailers - + assert @checker.alerts.has_key?("Deprecated ActionMailer API") end - + def test_check_generators make_file("vendor/plugins/thing/generators/thing/", "thing_generator.rb", "def manifest\n m.whatever\n end") @checker.check_generators - - assert @checker.alerts.has_key?("Old Rails generator API") + + assert @checker.alerts.has_key?("Old Rails generator API") end - + def test_check_plugins make_file("vendor/plugins/rspec-rails/", "whatever.rb", "def rspec; end") @checker.check_plugins - + assert @checker.alerts.has_key?("Known broken plugins") end - + def test_ignoring_comments make_file("config/", "routes.rb", "# map.connect 'fail'") @checker.check_routes assert !@checker.alerts.has_key?("Old router API") end - + def test_check_deprecated_constants_in_app_code make_file("app/controllers/", "thing_controller.rb", "class ThingController; THING = RAILS_ENV; end;") @checker.check_deprecated_constants - + assert @checker.alerts.has_key?("Deprecated constant(s)") end - + def test_check_deprecated_constants_in_lib make_file("lib/", "extra_thing.rb", "class ExtraThing; THING = RAILS_ENV; end;") @checker.check_deprecated_constants - + assert @checker.alerts.has_key?("Deprecated constant(s)") end @@ -175,34 +175,47 @@ class ApplicationCheckerTest < ActiveSupport::TestCase assert @checker.alerts.has_key?("Deprecated session secret setting") end - + def test_check_deprecated_session_settings make_file("config/initializers/", "more_settings.rb", "ActionController::Base.session_store = :cookie\nthings.awesome(:whatever)") @checker.check_old_session_setting - + assert @checker.alerts.has_key?("Old session store setting") end - + def test_check_helpers make_file("app/views/users/", "test.html.erb", "blah blah blah<% form_for(:thing) do |f| %> <%= f.whatever %> <% end %>") @checker.check_old_helpers - + assert @checker.alerts.has_key?("Deprecated ERb helper calls") end - + + def test_check_old_ajax_helpers + make_file("app/views/sections", "section.js", "<%= link_to_remote 'section-', :update => 'sections', :url => {:action => :destroy, :controller => 'sections', :id => @section.id } %>") + @checker.check_old_ajax_helpers + + assert @checker.alerts.has_key?("Deprecated AJAX helper calls") + end + + def test_check_old_ajax_helpers_empty + @checker.check_old_ajax_helpers + + assert ! @checker.alerts.has_key?("Deprecated AJAX helper calls") + end + def teardown clear_files - + Dir.chdir(@old_dir) end - + def make_file(where, name=nil, contents=nil) FileUtils.mkdir_p "#{BASE_ROOT}/#{where}" File.open("#{BASE_ROOT}/#{where}/#{name}", "w+") do |f| f.write(contents) end if name end - + def clear_files FileUtils.rm_rf(Dir.glob("#{BASE_ROOT}/*")) end