Skip to content

Commit c2da089

Browse files
author
jneen
committed
abandon guard, use a manual reloader for the dev server
1 parent 8636f5c commit c2da089

4 files changed

Lines changed: 55 additions & 5 deletions

File tree

Gemfile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ gem 'memory_profiler', require: false
1818

1919
group :development do
2020
gem 'pry'
21-
gem 'guard'
22-
gem 'guard-puma'
2321

2422
# Needed for a Rake task
2523
gem 'git'

config.ru

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
# frozen_string_literal: true
22

3-
require 'bundler'
4-
Bundler.require(:default, :development)
5-
63
require_relative 'spec/visual/app'
74

85
run VisualTestApp

spec/visual/app.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,23 @@
33

44
$VERBOSE = true
55

6+
require 'sinatra'
7+
require 'pry'
8+
69
# stdlib
710
require 'pathname'
811

12+
require_relative 'rouge_reloader'
13+
914
class VisualTestApp < Sinatra::Application
1015
BASE = Pathname.new(__dir__)
1116
SAMPLES = BASE.join('samples')
1217
ROOT = BASE.parent.parent
1318

19+
RougeReloader.install!(:Rouge, ROOT.to_s, 'lib/rouge.rb')
20+
21+
RELOADER = FeatureReloader.new(:Rouge, ROOT.join('lib').to_s, 'rouge.rb')
22+
1423
DEMOS = ROOT.join('lib/rouge/demos')
1524

1625
def query_string
@@ -58,6 +67,7 @@ def as_boolean(value)
5867
end
5968

6069
before do
70+
RELOADER.reload!
6171
Rouge::Lexer.enable_debug!
6272
Rouge::Formatter.enable_escape! if params[:escape]
6373

spec/visual/rouge_reloader.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# [jneen] this reloader is responsible for safely hot-loading Rouge in the dev server.
2+
# Previously, we were able to simply remove the Rouge constant and load lib/rouge.rb,
3+
# and all of Rouge would happily be reloaded. However, we have recently switched to
4+
# require_relative, which maintains its own global cache. Meaning that if we were to
5+
# remove the Rouge constant and load lib/rouge.rb, the line
6+
#
7+
# require_relative 'rouge/lexer'
8+
#
9+
# would be a no-op, and hence the constant Rouge::Lexer would not exist.
10+
#
11+
# This reloader clears a portion of that cache by mutating $LOADED_FEATURES.
12+
class FeatureReloader
13+
MUTEX = Mutex.new
14+
15+
def self.install!(const_name, root, path)
16+
@instance = new(const_name, root, path)
17+
@instance.install!
18+
end
19+
20+
def self.reload!
21+
@instance.reload!
22+
end
23+
24+
def initialize(const_name, root, path)
25+
@const_name = const_name
26+
@root = root
27+
@path = File.expand_path(path, root)
28+
@cache = {}
29+
end
30+
31+
def reload!
32+
STDERR.puts "========= reloading #{@const_name} ========="
33+
34+
MUTEX.synchronize do
35+
# remove the global constant
36+
Object.send(:remove_const, @const_name) if Object.const_defined?(@const_name)
37+
38+
# clear the cache
39+
$LOADED_FEATURES.reject! { |f| f.start_with?(@root) }
40+
41+
# load rouge.rb
42+
Kernel.load(@path)
43+
end
44+
end
45+
end

0 commit comments

Comments
 (0)