class Slinky::ManifestFile
Attributes
Public Class Methods
# File lib/slinky/manifest.rb, line 502 def initialize source, build_path, manifest, parent = nil, options = {:devel => false} @parent = parent @source = Pathname.new(source).cleanpath.to_s @last_built = Time.at(0) @cfile = Compilers.cfile_for_file(@source) @directives = find_directives @build_path = build_path @manifest = manifest @devel = true if options[:devel] end
Public Instance Methods
Builds the file by handling and compiling it and then copying it to the build path
# File lib/slinky/manifest.rb, line 755 def build return nil unless should_build if !File.exists? @build_path FileUtils.mkdir_p(@build_path) end to = build_to path = process to if path != to FileUtils.cp(path.to_s, to.to_s) @last_built = Time.now end to end
Path to which the file will be built
# File lib/slinky/manifest.rb, line 749 def build_to Pathname.new(@build_path) + output_path.basename end
Takes a path and compiles the file if necessary. @return Pathname the path of the compiled file, or the original
path if compiling is not necessary
# File lib/slinky/manifest.rb, line 668 def compile path, to = nil if @cfile cfile = @cfile.clone cfile.source = path cfile.print_name = @source cfile.output_path = to if to cfile.file do |cpath, _, _, _| path = cpath end end path ? Pathname.new(path) : nil end
Gets the list of manifest files that this one depends on according to its directive list and the dependencies config option.
Throws a FileNotFoundError
if a dependency doesn't exist in the tree.
# File lib/slinky/manifest.rb, line 526 def dependencies SlinkyError.batch_errors do (@directives[:slinky_require].to_a + @manifest.config.dependencies["/" + relative_source_path.to_s].to_a).map{|rf| required = parent.find_by_path(rf, true).flatten if required.empty? error = "Could not find file #{rf} required by /#{relative_source_path}" SlinkyError.raise FileNotFoundError, error end required }.flatten end end
The list of paths to files external to the manifest that this file depends on
# File lib/slinky/manifest.rb, line 688 def external_dependencies (@directives[:slinky_depends_external] || []).map{|ed| Dir.glob(File.join(@manifest.dir, ed)) }.flatten end
# File lib/slinky/manifest.rb, line 694 def external_dependencies_updated? return false if external_dependencies.empty? external_dependencies.map{|x| File.mtime(x)}.max > (@updated || Time.at(0)) end
Looks through the file for directives @return {Symbol => [String]} the directives in the file
# File lib/slinky/manifest.rb, line 617 def find_directives _, _, ext = @source.match(EXTENSION_REGEX).to_a directives = {} # check if this file might include directives if @cfile || DIRECTIVE_FILES.include?(ext) # make sure the file isn't too big to scan stat = File::Stat.new(@source) if stat.size < 1024*1024 File.open(@source) {|f| matches = f.read.scan(BUILD_DIRECTIVES).to_a matches.each{|slice| key, value = slice.compact directives[key.to_sym] ||= [] directives[key.to_sym] << value[1..-2] if value } } rescue nil end end @directives = directives end
If there are any build directives for this file, the file is read and the directives are handled appropriately and a new file is written to a temp location.
@return String the path of the de-directivefied file
# File lib/slinky/manifest.rb, line 644 def handle_directives path, to = nil if path && @directives.size > 0 out = File.read(path) out.gsub!(DEPENDS_DIRECTIVE, "") out.gsub!(EXTERNAL_DEPENDS_DIRECTIVE, "") out.gsub!(REQUIRE_DIRECTIVE, "") out.gsub!(SCRIPTS_DIRECTIVE){ @manifest.scripts_string } out.gsub!(STYLES_DIRECTIVE){ @manifest.styles_string } out.gsub!(PRODUCT_DIRECTIVE){ @manifest.product_string($2[1..-2]) } to = to || Tempfile.new("slinky").path + ".cache" File.open(to, "w+"){|f| f.write(out) } to else path end end
Predicate which determines whether the file is the supplied path or lies on supplied tree
# File lib/slinky/manifest.rb, line 584 def in_tree? path full_path = @manifest.dir + "/" + path abs_path = Pathname.new(full_path).expand_path.to_s dir = Pathname.new(@source).dirname.expand_path.to_s dir.start_with?(abs_path) || abs_path == @source end
# File lib/slinky/manifest.rb, line 775 def inspect to_s end
# File lib/slinky/manifest.rb, line 515 def invalidate @last_built = Time.at(0) @last_md5 = nil end
Predicate which determines whether the supplied name is the same as the file's name, taking into account compiled file extensions. For example, if mf refers to “/tmp/test/hello.sass”, `mf.matches? “hello.sass”` and `mf.matches? “hello.css”` should both return true.
@param String a filename @param Bool match_glob if true, matches according to glob rules @return Bool True if the filename matches, false otherwise
# File lib/slinky/manifest.rb, line 549 def matches? s, match_glob = false name = Pathname.new(@source).basename.to_s output = output_path.basename.to_s # check for stars that are not escaped a = [""] last = "" s.each_char {|c| if c != "*" || last == "\\" a[-1] << c else a << "" end last = c } if match_glob && a.size > 1 r2 = a.reduce{|a, x| /#{a}.*#{x}/} name.match(r2) || output.match(r2) else name == s || output == s end end
Predicate which determines whether the file matches (see `ManifestFile#matches?`) the full path relative to the manifest root.
# File lib/slinky/manifest.rb, line 575 def matches_path? s, match_glob = false p = Pathname.new(s) dir = Pathname.new("/" + relative_source_path.to_s).dirname matches?(p.basename.to_s, match_glob) && dir == p.dirname end
Gets the md5 hash of the source file
# File lib/slinky/manifest.rb, line 682 def md5 Digest::MD5.hexdigest(File.read(@source)) rescue nil end
Returns the path to which this file should be output. This is equal to the source path unless the file needs to be compiled, in which case the extension returned is the output extension
@return Pathname the output path
# File lib/slinky/manifest.rb, line 596 def output_path if @cfile ext = /\.[^.]*$/ Pathname.new(@source.gsub(ext, ".#{@cfile.output_ext}")) else Pathname.new(@source) end end
Gets manifest file ready for serving or building by handling the directives and compiling the file if neccesary. @param String path to which the file should be compiled
@return String the path of the processed file, ready for serving
# File lib/slinky/manifest.rb, line 705 def process to = nil, should_compile = true return if @processing # prevent infinite recursion start_time = Time.now hash = md5 if hash != @last_md5 find_directives end SlinkyError.batch_errors do depends = @directives[:slinky_depends].map{|f| ps = if f.start_with?("/") @manifest.find_by_pattern(f) else parent.find_by_path(f, true) end unless ps.size > 0 SlinkyError.raise DependencyError, "File #{f} depended on by #{@source} not found" end ps }.flatten.compact if @directives[:slinky_depends] depends ||= [] @processing = true # process each file on which we're dependent, watching out for # infinite loops depends.each{|f| f.process } @processing = false # get hash of source file if @last_path && hash == @last_md5 && depends.all?{|f| f.updated < start_time} && !external_dependencies_updated? @last_path else @last_md5 = hash @updated = Time.now # mangle file appropriately f = should_compile ? (compile @source) : @source @last_path = handle_directives(f, to) end end end
Returns the output path relative to the manifest directory
# File lib/slinky/manifest.rb, line 611 def relative_output_path output_path.relative_path_from(Pathname.new(@manifest.dir)) end
returns the source path relative to the manifest directory
# File lib/slinky/manifest.rb, line 606 def relative_source_path Pathname.new(@source).relative_path_from(Pathname.new(@manifest.dir)) end
# File lib/slinky/manifest.rb, line 771 def should_build @manifest.files_for_all_products.include?(self) || ![".js", ".css"].include?(output_path.extname) end
# File lib/slinky/manifest.rb, line 779 def to_s "<Slinky::ManifestFile '#{@source}'>" end