class MiniAsset::Base attr_reader :error def initialize source, opts={} @source = source @opts = opts raise 'Bad source: %s' % source unless File.exist?(local_file) end def run! what puts what.yellow stdin, stdout, stderr, wait_thread = Open3.popen3(what) error = stderr.gets while line = stderr.gets do error += line end # node-sass prints to stderror on complete error = nil if error && error.index('Rendering Complete, saving .css file...') if error File.unlink(cache_file) if File.exists?(cache_file) @error = error end end def production? !!@opts[:production] end def create file, opts=nil MiniAsset.create file, opts || @opts end def content File.read local_file end def ext @source.split('.').last.to_sym end def asset_join_string "\n" end def local_file 'app/assets/%s' % @source end def production_file file = MiniAsset.manifest['files'][@source] || raise('Production file not found') 'public%s' % file end def cache_file 'tmp/assets/%s' % @source.gsub('/', '-') end def base_dir list = @source.split('/') list.pop 'app/assets/' + list.join('/') end def resolve_file files files = files.sub(/^\.\//,'') files += '/*' unless files.include?('*') path = '%s/%s' % [base_dir, files] @files += Dir[path].sort.map{ |f| f.split('app/assets/', 2).last } end def files return @files if @files @files = [] for line in content.split($/) test = line.split(/^[\/\/#]=\s*req\w*\s+/) resolve_file test[1] if test[1] end @files.push @source @files end def path_for_comment '/* Source: %s */' % @source end def do_compile? return true unless File.exists?(cache_file) return true if File.mtime(cache_file).to_i <= File.mtime(local_file).to_i false end # compiles all the files, allways for production def compile args=[] data = [] for file in files asset = create file, production: true data.push asset.path_for_comment data.push asset.compiled_data end data = data.join(asset_join_string) pfile = update_manifest(data) unless File.exists? pfile File.write(pfile, data) minify! end if args.include?('gzip') gzip! else gzip_file = '%s.gz' % pfile File.unlink gzip_file if File.exists?(gzip_file) end fix_created_times! pfile end # compiles single current file def compiled_data content end def minify! true end def gzip! f = production_file run! "gzip -f -c -1 '%{f}' > '%{f}.gz'" % { f: f } unless File.exists?('%s.gz' % f) end def fix_created_times! touch_file = 'public/touch.ref' `touch '#{touch_file}'` unless File.exists?(touch_file) # touch and fix reference `touch -r '#{touch_file}' #{production_file}` `touch -r '#{touch_file}' #{production_file}.gz` if File.exists?("#{production_file}.gz") end def update_manifest data digest = Digest::SHA1.hexdigest(data.to_s) json = MiniAsset.manifest pfile = cache_file.sub('tmp/assets/', 'public/assets/') pfile = pfile.sub(/\.(\w+)/, "-#{digest}.\\1") json['files'][@source] = pfile.sub('public/', '/') MiniAsset.manifest json pfile end end