Class: Rack::Unreloader

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/unreloader.rb,
lib/rack/unreloader/reloader.rb

Overview

Reloading application that unloads constants before reloading the relevant files, calling the new rack app if it gets reloaded.

Defined Under Namespace

Classes: Reloader

Constant Summary collapse

F =

Reference to ::File as File would return Rack::File by default.

::File

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}, &block) ⇒ Unreloader

Setup the reloader. Options:

:cooldown

The number of seconds to wait between checks for changed files. Defaults to 1. Set to nil/false to not check for changed files.

:reload

Set to false to not setup a reloader, and just have require work directly. Should be set to false in production mode.

:logger

A Logger instance which will log information related to reloading.

:subclasses

A string or array of strings of class names that should be unloaded. Any classes that are not subclasses of these classes will not be unloaded. This also handles modules, but module names given must match exactly, since modules don't have superclasses.


53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rack/unreloader.rb', line 53

def initialize(opts={}, &block)
  @app_block = block
  if opts.fetch(:reload, true)
    @cooldown = opts.fetch(:cooldown, 1)
    @last = Time.at(0)
    Kernel.require 'rack/unreloader/reloader'
    @reloader = Reloader.new(opts)
    reload!
  else
    @reloader = @cooldown = false
  end
end

Instance Attribute Details

#reloaderObject (readonly)

The Rack::Unreloader::Reloader instead related to this instance, if one.


40
41
42
# File 'lib/rack/unreloader.rb', line 40

def reloader
  @reloader
end

Class Method Details

.expand_directory_paths(paths) ⇒ Object

Given the list of paths, find all matching files, or matching ruby files in subdirecories if given a directory, and return an array of expanded paths.


13
14
15
16
17
# File 'lib/rack/unreloader.rb', line 13

def self.expand_directory_paths(paths)
  expand_paths(paths).
    map{|f| F.directory?(f) ? ruby_files(f) : f}.
    flatten
end

.expand_paths(paths) ⇒ Object

Given the path glob or array of path globs, find all matching files or directories, and return an array of expanded paths.


21
22
23
24
25
26
27
28
# File 'lib/rack/unreloader.rb', line 21

def self.expand_paths(paths)
  Array(paths).
    flatten.
    map{|path| Dir.glob(path).sort_by{|filename| filename.count('/')}}.
    flatten.
    map{|path| F.expand_path(path)}.
    uniq
end

.ruby_files(dir) ⇒ Object

The .rb files in the given directory or any subdirectory.


31
32
33
34
35
36
37
# File 'lib/rack/unreloader.rb', line 31

def self.ruby_files(dir)
  files = []
  Find.find(dir) do |f|
    files << f if f =~ /\.rb\z/
  end
  files.sort
end

Instance Method Details

#call(env) ⇒ Object

If the cooldown time has been passed, reload any application files that have changed. Call the app with the environment.


68
69
70
71
72
73
74
# File 'lib/rack/unreloader.rb', line 68

def call(env)
  if @cooldown && Time.now > @last + @cooldown
    Thread.respond_to?(:exclusive) ? Thread.exclusive{reload!} : reload!
    @last = Time.now
  end
  @app_block.call.call(env)
end

#record_dependency(dependency, *files) ⇒ Object

Records that each path in files depends on dependency. If there is a modification to dependency, all related files will be reloaded after dependency is reloaded. Both dependency and each entry in files can be an array of path globs.


89
90
91
92
93
94
95
96
# File 'lib/rack/unreloader.rb', line 89

def record_dependency(dependency, *files)
  if @reloader
    files = Unreloader.expand_paths(files)
    Unreloader.expand_paths(dependency).each do |path|
      @reloader.record_dependency(path, files)
    end
  end
end

#record_split_class(main_file, *files) ⇒ Object

Record that a class is split into multiple files. main_file should be the main file for the class, which should require all of the other files. files should be a list of all other files that make up the class.


101
102
103
104
105
106
107
108
109
# File 'lib/rack/unreloader.rb', line 101

def record_split_class(main_file, *files)
  if @reloader
    files = Unreloader.expand_paths(files)
    files.each do |file|
      record_dependency(file, main_file)
    end
    @reloader.skip_reload(files)
  end
end

#reload!Object

Reload the application, checking for changed files and reloading them.


112
113
114
# File 'lib/rack/unreloader.rb', line 112

def reload!
  @reloader.reload! if @reloader
end

#require(paths, &block) ⇒ Object

Add a file glob or array of file globs to monitor for changes.


77
78
79
80
81
82
83
# File 'lib/rack/unreloader.rb', line 77

def require(paths, &block)
  if @reloader
    @reloader.require_dependencies(paths, &block)
  else
    Unreloader.expand_directory_paths(paths).each{|f| super(f)}
  end
end