github.com/nycdavid/zeus@v0.0.0-20201208104106-9ba439429e03/rubygem/lib/zeus/rails.rb (about) 1 def find_rails_path(root_path) 2 paths = %w(spec/dummy test/dummy .) 3 paths.find { |path| File.exists?(File.expand_path(path, root_path)) } 4 end 5 6 ROOT_PATH = File.expand_path(Dir.pwd) 7 RAILS_PATH = find_rails_path(ROOT_PATH) 8 ENV_PATH = File.expand_path('config/environment', RAILS_PATH) 9 BOOT_PATH = File.expand_path('config/boot', RAILS_PATH) 10 APP_PATH = File.expand_path('config/application', RAILS_PATH) unless defined? APP_PATH 11 12 require 'zeus' 13 14 def gem_is_bundled?(gem) 15 gemfile_lock_contents = File.read(ROOT_PATH + "/Gemfile.lock") 16 gemfile_lock_contents.scan(/^\s*#{gem} \(([^=~><]+?)\)/).flatten.first 17 end 18 19 if version = gem_is_bundled?('method_source') 20 gem 'method_source', version 21 end 22 23 require 'zeus/m' 24 25 module Zeus 26 class Rails < Plan 27 def after_fork 28 reconnect_activerecord 29 restart_girl_friday 30 reconnect_redis 31 end 32 33 def _monkeypatch_rake 34 if version = gem_is_bundled?('rake') 35 gem 'rake', version 36 end 37 require 'rake/testtask' 38 Rake::TestTask.class_eval { 39 40 # Create the tasks defined by this task lib. 41 def define 42 desc "Run tests" + (@name==:test ? "" : " for #{@name}") 43 task @name do 44 # ruby "#{ruby_opts_string} #{run_code} #{file_list_string} #{option_list}" 45 rails_env = ENV['RAILS_ENV'] 46 rubyopt = ENV['RUBYOPT'] 47 ENV['RAILS_ENV'] = nil 48 ENV['RUBYOPT'] = nil # bundler sets this to require bundler :| 49 puts "zeus test #{file_list_string}" 50 ret = system "zeus test #{file_list_string}" 51 ENV['RAILS_ENV'] = rails_env 52 ENV['RUBYOPT'] = rubyopt 53 ret 54 end 55 self 56 end 57 58 alias_method :_original_define, :define 59 60 def self.inherited(klass) 61 return unless klass.name == "TestTaskWithoutDescription" 62 klass.class_eval { 63 def self.method_added(sym) 64 class_eval do 65 if !@rails_hack_reversed 66 @rails_hack_reversed = true 67 alias_method :define, :_original_define 68 def desc(*) 69 end 70 end 71 end 72 end 73 } 74 end 75 } 76 end 77 78 def boot 79 _monkeypatch_rake 80 $LOAD_PATH.unshift "./lib" 81 82 require BOOT_PATH 83 # config/application.rb normally requires 'rails/all'. 84 # Some 'alternative' ORMs such as Mongoid give instructions to switch this require 85 # out for a list of railties, not including ActiveRecord. 86 # We grep config/application.rb for all requires of rails/all or railties, and require them. 87 rails_components = File.read(APP_PATH + ".rb"). 88 scan(/^\s*require\s*['"](.*railtie.*|rails\/all)['"]/).flatten 89 90 rails_components = ["rails/all"] if rails_components == [] 91 rails_components.each do |component| 92 require component 93 end 94 end 95 96 def default_bundle 97 Bundler.require(:default) 98 Zeus::LoadTracking.add_feature('./Gemfile.lock') 99 end 100 101 def development_environment 102 Bundler.require(:development) 103 ::Rails.env = ENV['RAILS_ENV'] = "development" 104 require APP_PATH 105 ::Rails.application.require_environment! 106 end 107 108 def prerake 109 require 'rake' 110 end 111 112 def rake 113 Rake.application.run 114 end 115 116 def generate 117 load_rails_generators 118 119 if rails_5_1_or_higher? 120 run_rails_5_1_or_higher_command('generate') 121 else 122 require 'rails/commands/generate' 123 end 124 125 end 126 127 def destroy 128 load_rails_generators 129 if rails_5_1_or_higher? 130 run_rails_5_1_or_higher_command('destroy') 131 else 132 require 'rails/commands/destroy' 133 end 134 end 135 136 def runner 137 if rails_5_1_or_higher? 138 run_rails_5_1_or_higher_command('runner') 139 else 140 require 'rails/commands/runner' 141 end 142 end 143 144 def console 145 if rails_5_1_or_higher? 146 run_rails_5_1_or_higher_command('console') 147 else 148 require 'rails/commands/console' 149 if defined?(Pry) 150 # Adding Rails Console helpers to Pry. 151 if (3..4).include?(::Rails::VERSION::MAJOR) 152 require 'rails/console/app' 153 require 'rails/console/helpers' 154 TOPLEVEL_BINDING.eval('self').extend ::Rails::ConsoleMethods 155 end 156 157 Pry.start 158 else 159 ::Rails::Console.start(::Rails.application) 160 end 161 end 162 end 163 164 def dbconsole 165 if rails_5_1_or_higher? 166 run_rails_5_1_or_higher_command('dbconsole') 167 else 168 require 'rails/commands/dbconsole' 169 170 meth = ::Rails::DBConsole.method(:start) 171 172 # `Rails::DBConsole.start` has been changed to load faster in 173 # https://github.com/rails/rails/commit/346bb018499cde6699fcce6c68dd7e9be45c75e1 174 # 175 # This will work with both versions. 176 if meth.arity.zero? 177 ::Rails::DBConsole.start 178 else 179 ::Rails::DBConsole.start(::Rails.application) 180 end 181 end 182 end 183 184 def server 185 if rails_5_1_or_higher? 186 run_rails_5_1_or_higher_command('server') 187 else 188 require 'rails/commands/server' 189 server = ::Rails::Server.new 190 Dir.chdir(::Rails.application.root) 191 server.start 192 end 193 end 194 195 def test_environment 196 Bundler.require(:test) 197 198 ::Rails.env = ENV['RAILS_ENV'] = 'test' 199 require APP_PATH 200 201 $rails_rake_task = 'yup' # lie to skip eager loading 202 ::Rails.application.require_environment! 203 $rails_rake_task = nil 204 205 $LOAD_PATH.unshift ".", "./lib", "./test", "./spec" 206 end 207 208 def test_helper 209 if ENV['RAILS_TEST_HELPER'] 210 require ENV['RAILS_TEST_HELPER'] 211 else 212 if File.exists?(ROOT_PATH + "/spec/rails_helper.rb") 213 # RSpec >= 3.0+ 214 require 'rails_helper' 215 elsif File.exists?(ROOT_PATH + "/spec/spec_helper.rb") 216 # RSpec < 3.0 217 require 'spec_helper' 218 elsif File.exists?(ROOT_PATH + "/test/minitest_helper.rb") 219 require 'minitest_helper' 220 else 221 require 'test_helper' 222 end 223 end 224 end 225 226 def test(argv=ARGV) 227 # if there are two test frameworks and one of them is RSpec, 228 # then "zeus test/rspec/testrb" without arguments runs the 229 # RSpec suite by default. 230 if using_rspec?(argv) 231 ARGV.replace(argv) 232 # if no directory is given, run the default spec directory 233 argv << "spec" if argv.empty? 234 if RSpec::Core::Runner.respond_to?(:invoke) 235 RSpec::Core::Runner.invoke 236 else 237 RSpec::Core::Runner.run(argv) 238 end 239 else 240 require 'minitest/autorun' if using_minitest? 241 # Minitest and old Test::Unit 242 Zeus::M.run(argv) 243 end 244 end 245 246 private 247 248 def using_rspec?(argv) 249 defined?(RSpec) && (argv.empty? || spec_file?(argv)) 250 end 251 252 def using_minitest? 253 defined?(:MiniTest) || defined?(:Minitest) 254 end 255 256 SPEC_DIR_REGEXP = %r"(^|/)spec" 257 SPEC_FILE_REGEXP = /.+_spec\.rb$/ 258 259 def spec_file?(argv) 260 argv.any? do |arg| 261 arg.match(Regexp.union(SPEC_DIR_REGEXP, SPEC_FILE_REGEXP)) 262 end 263 end 264 265 def restart_girl_friday 266 return unless defined?(GirlFriday::WorkQueue) 267 # The Actor is run in a thread, and threads don't persist post-fork. 268 # We just need to restart each one in the newly-forked process. 269 ObjectSpace.each_object(GirlFriday::WorkQueue) do |obj| 270 obj.send(:start) 271 end 272 end 273 274 def reconnect_activerecord 275 return unless defined?(ActiveRecord::Base) 276 begin 277 ActiveRecord::Base.clear_all_connections! 278 ActiveRecord::Base.establish_connection 279 if ActiveRecord::Base.respond_to?(:shared_connection) 280 ActiveRecord::Base.shared_connection = ActiveRecord::Base.retrieve_connection 281 end 282 rescue ActiveRecord::AdapterNotSpecified 283 end 284 end 285 286 def reconnect_redis 287 return unless defined?(Redis::Client) 288 ObjectSpace.each_object(Redis::Client) do |client| 289 client.connect rescue nil 290 end 291 end 292 293 def load_rails_generators 294 require 'rails/generators' 295 ::Rails.application.load_generators 296 rescue LoadError # Rails 3.0 doesn't require this block to be run, but 3.2+ does 297 end 298 299 def run_rails_5_1_or_higher_command(command) 300 require 'rails/command' 301 ::Rails::Command.invoke(command, ARGV) 302 end 303 304 def rails_5_1_or_higher? 305 (::Rails::VERSION::MAJOR == 5 && ::Rails::VERSION::MINOR >= 1) || 306 ::Rails::VERSION::MAJOR > 5 307 end 308 end 309 end 310 311 Zeus.plan ||= Zeus::Rails.new