Class: RSX::CompileCache
- Inherits:
-
Object
- Object
- RSX::CompileCache
- Defined in:
- lib/rsx/compile_cache.rb
Overview
Caches the Ruby produced from .rsx files on disk, keyed by a digest of the source. A warm cache turns loading a template into reading a .rb file, so booting a large application does no transformation work at all.
Instance Attribute Summary collapse
-
#directory ⇒ Object
readonly
Returns the value of attribute directory.
Instance Method Summary collapse
- #clear ⇒ Object
- #digest(source) ⇒ Object
- #enabled? ⇒ Boolean
-
#fetch(path, source) ⇒ Object
Returns the compiled Ruby for source, compiling only on a cache miss.
-
#initialize(directory) ⇒ CompileCache
constructor
A new instance of CompileCache.
- #path_for(source_path, key) ⇒ Object
- #read(source_path, key) ⇒ Object
- #write(source_path, key, ruby) ⇒ Object
Constructor Details
#initialize(directory) ⇒ CompileCache
Returns a new instance of CompileCache.
13 14 15 16 17 18 |
# File 'lib/rsx/compile_cache.rb', line 13 def initialize(directory) @directory = directory @enabled = !directory.nil? @memory = {} @lock = Mutex.new end |
Instance Attribute Details
#directory ⇒ Object (readonly)
Returns the value of attribute directory.
11 12 13 |
# File 'lib/rsx/compile_cache.rb', line 11 def directory @directory end |
Instance Method Details
#clear ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/rsx/compile_cache.rb', line 76 def clear @lock.synchronize { @memory.clear } return unless enabled? && File.directory?(@directory) Dir.glob(File.join(@directory, "*.rb")).each { |file| File.delete(file) } Dir.glob(File.join(@directory, "*.tmp")).each { |file| File.delete(file) } end |
#digest(source) ⇒ Object
24 25 26 |
# File 'lib/rsx/compile_cache.rb', line 24 def digest(source) Digest::SHA256.hexdigest("#{COMPILER_VERSION}\0#{source}")[0, 32] end |
#enabled? ⇒ Boolean
20 21 22 |
# File 'lib/rsx/compile_cache.rb', line 20 def enabled? @enabled end |
#fetch(path, source) ⇒ Object
Returns the compiled Ruby for source, compiling only on a cache miss.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/rsx/compile_cache.rb', line 29 def fetch(path, source) key = digest(source) cached = @lock.synchronize { @memory[key] } return cached if cached ruby = read(path, key) || begin compiled = yield write(path, key, compiled) compiled end @lock.synchronize { @memory[key] = ruby } ruby end |
#path_for(source_path, key) ⇒ Object
44 45 46 47 48 49 50 |
# File 'lib/rsx/compile_cache.rb', line 44 def path_for(source_path, key) return nil unless enabled? basename = File.basename(source_path.to_s, ".*") basename = "template" if basename.empty? File.join(@directory, "#{basename}-#{key}.rb") end |
#read(source_path, key) ⇒ Object
52 53 54 55 56 57 58 59 |
# File 'lib/rsx/compile_cache.rb', line 52 def read(source_path, key) target = path_for(source_path, key) return nil unless target && File.file?(target) File.read(target) rescue SystemCallError nil end |
#write(source_path, key, ruby) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/rsx/compile_cache.rb', line 61 def write(source_path, key, ruby) target = path_for(source_path, key) return ruby unless target FileUtils.mkdir_p(File.dirname(target)) temporary = "#{target}.#{Process.pid}.#{rand(1 << 24)}.tmp" File.binwrite(temporary, ruby) File.rename(temporary, target) ruby rescue SystemCallError # A read-only or missing cache directory must never break rendering. @enabled = false ruby end |