Class: Compressor

Inherits:
Object
  • Object
show all
Includes:
SqweezeUtils
Defined in:
lib/compressor.rb

Overview

Pseudo-abstract class inherited by all the other classes performing asset-compression operations

Constant Summary

Constants included from SqweezeUtils

SqweezeUtils::EMBED_MIME_TYPES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SqweezeUtils

#ansi_bold, #ansi_green, #ansi_nocolour, #ansi_red, #ansi_yellow, #byteweight, #compression_percentage, #encoded_contents, #find_file_in_targetdir, #mime_type, #notify, #remap_filepath, #write_file

Constructor Details

#initialize(input_file_extensions) ⇒ Compressor

Sets the file extensions that a compressor accepts

*Note*: As this class cannot be instanciated directly, this method is only used by subclasses.


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/compressor.rb', line 9

def initialize(input_file_extensions)

   # Behave as a pseudo abstract class
   raise "Cannot instantiate #{self.class} directly" if self.class == Compressor
   
   @cm=ConfManager.instance
   @input_file_extensions=input_file_extensions
  

   # Get the project file list from the configuration manager
   @input_files=@cm.files

   # The commands used by this compressor,
   # listed in order of priority  
   
   @commands={}

   # Set the default shell command to use for this compressor.
   # issue: what's the point of calling this default command and not just default..
   @default_command=nil
   
   # whether or not concatenating the input files (it is the case of css and javascripts)      
   @concatenate_input=false
   
   # Store the overall byte weight of the assets, before compressions
   @byteweight_before = collect_filepaths.inject(0){|sum,f| sum+File.size(f)}
   
   #set later, after compression
   @byteweight_after = 0
end

Instance Attribute Details

#byteweight_afterObject (readonly)

something here



41
42
43
# File 'lib/compressor.rb', line 41

def byteweight_after
  @byteweight_after
end

#byteweight_beforeObject (readonly)

something here



41
42
43
# File 'lib/compressor.rb', line 41

def byteweight_before
  @byteweight_before
end

#input_file_extensionsObject (readonly)

something here



41
42
43
# File 'lib/compressor.rb', line 41

def input_file_extensions
  @input_file_extensions
end

Instance Method Details

#collect_filepathsObject

Collects the paths of files having the compressor extension name.



68
69
70
71
# File 'lib/compressor.rb', line 68

def collect_filepaths
  exp_str = filextension2regexpstr  
  @cm.files.select{|path| path =~ Regexp.new(exp_str,true)  }
end

#compressObject

Iterates over the list of file paths matching the compressor extension/s and applies the process method to each of them.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/compressor.rb', line 92

def compress
  files=@input_files=collect_filepaths
  
  # This will consist of only an entry (the concatenated file body)
  # when compressing javascript or css files 

  files=[concatenate_files] if @concatenate_input
  cmd= (@commands.empty?)? nil : @commands[ @default_command ]

  files.each do |path|
    output_path=process(path,cmd)
    size_check(path,output_path) unless %w(.css .js).include?( File.extname(output_path))   
  end
  
  # summarise compression stats
  print_summary  unless ['.css','.js' ].include?(@input_file_extensions)
end

#concatenate_filesObject

Concatenates several files into a single string (used in both CSS and JS compression).



127
128
129
# File 'lib/compressor.rb', line 127

def concatenate_files
  @input_files.collect{|f|File.open(f,'r').read}.join("\n")
end

#filextension2regexpstr(ext = @input_file_extensions) ⇒ Object

Turns a string or an array of strings containing several file extension names into regular expressions.



58
59
60
61
62
63
64
# File 'lib/compressor.rb', line 58

def filextension2regexpstr(ext=@input_file_extensions)
   if @input_file_extensions.is_a?(Array) and @input_file_extensions.size > 1
      "(#{@input_file_extensions.collect{|ext|"\.#{ext}"}.join('|')})$"
     else
      "\.#{@input_file_extensions}$"      
  end
end


131
132
133
134
135
# File 'lib/compressor.rb', line 131

def print_summary    
     notify("Compressed #{ansi_bold(@input_files.size)} #{@input_file_extensions.first.upcase} files".ljust(60) +
           "#{ansi_green(compression_percentage(@byteweight_before,@byteweight_after)+'%')} (was #{ansi_bold(@byteweight_before)}, is #{ansi_bold(@byteweight_after)} bytes now) \n", 
           :info) unless @byteweight_before == 0
end

#process(inputpath, cmd = nil) ⇒ Object

Applies a system command to a list of file paths.

This method is overridden by both CssCompressor and JsCompressor, as these two classes do not rely on command line executable but use ruby bindings to YUI and Google Closure.



78
79
80
81
82
83
84
85
86
87
# File 'lib/compressor.rb', line 78

def process(inputpath,cmd=nil)      
   output_path =@cm.get_target_path(inputpath)    
   
   cl= cmd.gsub('%executable%', @cm.get_conf(:bin_paths)[@default_command]).
               gsub('%input%',inputpath).
               gsub('%output%', output_path)
   system(cl)
   notify("run command #{cl}, pid=#{$?.pid} exitstatus=#{$?.exitstatus}", :debug)  
   output_path
end

#set_command(libname, command) ⇒ Object

Sets the system command to be invoked by the compressor.

This raises a runtime error if the third party command cannot be found in the file system.



49
50
51
52
53
54
# File 'lib/compressor.rb', line 49

def set_command(libname,command)
  
  raise "missing library #{libname}" unless  @cm.get_conf(:bin_paths).keys.include?(libname)
  @default_command=libname if @commands.empty?
  @commands[libname]=command
end

#size_check(input_path, output_path) ⇒ Object

Makes sure that the byteweight of a compressed file is not larger that the original one.



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/compressor.rb', line 112

def size_check(input_path,output_path)
  before_size, after_size = byteweight(input_path), byteweight(output_path)
    # if the compressed file is bigger than the original one, copy the original in the target dir
  if after_size < before_size 
        notify("compressed #{input_path} to the #{ compression_percentage(before_size,after_size)}% of its original size  (from: #{before_size} to #{after_size} bytes ) ", :debug)
        @byteweight_after+=after_size
    else
        notify("output(#{after_size}) >= input(#{before_size}), keeping the original file #{input_path}",:debug)  
        FileUtils.cp(input_path,output_path)
        @byteweight_after+=before_size
    end
end