class JsDuck::Cache
Reads/writes parsed files in cache.
When writing to cache:
-
makes MD5 hash of <file name> + <file contents>
-
Dumps the the parsed data structure using Marshal into <md5>.dat
When reading from cache:
-
makes MD5 hash of <file name> + <file contents>
-
Reads the parsed data structure using Marshal from <md5>.dat
Additionally a manifest.txt file is saved into the cache directory, the contents of which is a string like the following:
Ruby: 1.9.3, JSDuck: 5.2.0
This file is consulted before all other cache operations. When the version numbers in there don't match with current Ruby and JSDuck versions, the whole cache gets invalidated - all cached files get deleted. This is to avoid problems with the Marshal file format changes between Ruby versions and parsed data structure changes between JSDuck versions.
After all files have been checked into cache, the files that weren't touched get deleted (using the cleanup
method). This ensures that the number of files in cache only grows when more files are added to the documentation.
Attributes
Public Class Methods
Factory method to produce a cache object. When caching is disabled, returns a NullObject which emulates a cache that's always empty.
# File lib/jsduck/cache.rb, line 43 def self.create(opts) # Check also for cache_dir, which will be nil when output_dir is :stdout if opts.cache && opts.cache_dir Cache.new(opts) else Util::NullObject.new( :read => nil, :write => nil, :previous_entry => nil, :cleanup => nil ) end end
# File lib/jsduck/cache.rb, line 62 def initialize(opts) @cache_dir = opts.cache_dir @manifest_file = @cache_dir + "/manifest.txt" @previous_entry = nil FileUtils.mkdir_p(@cache_dir) unless File.exists?(@cache_dir) # Invalidate the whole cache when it was generated with a # different Ruby and/or JSDuck version. invalidate_all! unless valid_manifest? end
Public Instance Methods
Given listing of used cache files (those that were either read or written during this jsduck run) removes rest of the files from cache directory that were unused.
# File lib/jsduck/cache.rb, line 98 def cleanup(used_cache_entries) used = Set.new(used_cache_entries) Dir[@cache_dir + "/*.dat"].each do |file| FileUtils.rm_rf(file) unless used.include?(file) end end
Given the name and contents of a source file, reads the already parsed data structure from cache. Returns nil when not found.
# File lib/jsduck/cache.rb, line 76 def read(file_name, file_contents) fname = cache_file_name(file_name, file_contents) if File.exists?(fname) @previous_entry = fname File.open(fname, "rb") {|file| Marshal::load(file) } else @previous_entry = nil nil end end
Writes parse data into cache under a name generated from the name and contents of a source file.
# File lib/jsduck/cache.rb, line 89 def write(file_name, file_contents, data) fname = cache_file_name(file_name, file_contents) @previous_entry = fname File.open(fname, "wb") {|file| Marshal::dump(data, file) } end
Private Instance Methods
# File lib/jsduck/cache.rb, line 108 def cache_file_name(file_name, file_contents) @cache_dir + "/" + md5(file_name + file_contents) + ".dat" end
# File lib/jsduck/cache.rb, line 131 def current_manifest "Ruby: #{RUBY_VERSION}, JSDuck: #{JsDuck::VERSION}\n" end
# File lib/jsduck/cache.rb, line 121 def invalidate_all! FileUtils.rm_rf(@cache_dir) FileUtils.mkdir(@cache_dir) save_manifest end
# File lib/jsduck/cache.rb, line 112 def md5(string) Digest::MD5.hexdigest(string) end
# File lib/jsduck/cache.rb, line 127 def save_manifest File.open(@manifest_file, "w") {|f| f.write(current_manifest) } end
# File lib/jsduck/cache.rb, line 116 def valid_manifest? manifest = File.exists?(@manifest_file) ? Util::IO.read(@manifest_file) : "" return manifest == current_manifest end