Class: Merb::BootLoader::LoadClasses

Inherits:
Merb::BootLoader show all
Defined in:
lib/merb-core/bootloader.rb

Overview

Load all classes inside the load paths.

This is used in conjunction with Merb::BootLoader::ReloadClasses to track files that need to be reloaded, and which constants need to be removed in order to reload a file.

This also adds the model, controller, and lib directories to the load path, so they can be required in order to avoid load-order issues.

Constant Summary collapse

LOADED_CLASSES =
{}
MTIMES =
{}

Class Method Summary collapse

Methods inherited from Merb::BootLoader

after, after_app_loads, before, before_app_loads, default_framework, inherited, move_klass

Class Method Details

.load_classes_with_requirements(klasses) ⇒ Object

“Better loading” of classes. If a class fails to load due to a NameError it will be added to the failed_classs stack.

Parameters

klasses<Array>

Classes to load.



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/merb-core/bootloader.rb', line 338

def load_classes_with_requirements(klasses)
  klasses.uniq!
  
  while klasses.size > 0
    # note size to make sure things are loading
    size_at_start = klasses.size
    
    #list of failed classes
    failed_classes = []
    
    klasses.each do |klass|
      klasses.delete(klass)
      begin
        load_file klass
      rescue NameError => ne
        failed_classes.push(klass)
      end
    end
    
    # keep list of classes unique
    failed_classes.each { |k| klasses.push(k) unless klasses.include?(k) }
    
    #stop processing if nothing loads or if everything has loaded
    if klasses.size == size_at_start && klasses.size != 0
      raise LoadError, "Could not load #{failed_classes.inspect}."
    end
    break if(klasses.size == size_at_start || klasses.size == 0)
  end
end

.load_file(file) ⇒ Object

Parameters

file<String>

The file to load.



326
327
328
329
330
331
# File 'lib/merb-core/bootloader.rb', line 326

def load_file(file)
  klasses = ObjectSpace.classes.dup
  load file
  LOADED_CLASSES[file] = ObjectSpace.classes - klasses
  MTIMES[file] = File.mtime(file)
end

.reload(file) ⇒ Object

Parameters

file<String>

The file to reload.



370
371
372
373
374
375
376
377
# File 'lib/merb-core/bootloader.rb', line 370

def reload(file)
  Merb.klass_hashes.each {|x| x.protect_keys!}
  if klasses = LOADED_CLASSES.delete(file)
    klasses.each { |klass| remove_constant(klass) unless klass.to_s =~ /Router/ }
  end
  load_file file
  Merb.klass_hashes.each {|x| x.unprotect_keys!}      
end

.remove_constant(const) ⇒ Object

Parameters

const<Class>

The class to remove.



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/merb-core/bootloader.rb', line 381

def remove_constant(const)
  # This is to support superclasses (like AbstractController) that track
  # their subclasses in a class variable. Classes that wish to use this
  # functionality are required to alias it to _subclasses_list. Plugins
  # for ORMs and other libraries should keep this in mind.
  superklass = const
  until (superklass = superklass.superclass).nil?
    if superklass.respond_to?(:_subclasses_list)
      superklass.send(:_subclasses_list).delete(klass)
      superklass.send(:_subclasses_list).delete(klass.to_s)          
    end
  end
  
  parts = const.to_s.split("::")
  base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
  object = parts[-1].to_s
  begin
    base.send(:remove_const, object)
    Merb.logger.debug("Removed constant #{object} from #{base}")
  rescue NameError
    Merb.logger.debug("Failed to remove constant #{object} from #{base}")
  end
end

.runObject

Load all classes inside the load paths.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/merb-core/bootloader.rb', line 298

def run
  orphaned_classes = []
  # Add models, controllers, and lib to the load path
  $LOAD_PATH.unshift Merb.dir_for(:model)      
  $LOAD_PATH.unshift Merb.dir_for(:controller)
  $LOAD_PATH.unshift Merb.dir_for(:lib)        

  load_file Merb.dir_for(:application) if File.file?(Merb.dir_for(:application))

  # Require all the files in the registered load paths
  Merb.load_paths.each do |name, path|
    next unless path.last && name != :application
    Dir[path.first / path.last].each do |file|
      
      begin
        load_file file
      rescue NameError => ne
        orphaned_classes.unshift(file)
      end
    end
  end
  Merb::Controller.send :include, Merb::GlobalHelpers
  
  load_classes_with_requirements(orphaned_classes)
end