File: project_stats.rb

package info (click to toggle)
ruby-compass 1.0.3~dfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 8,184 kB
  • ctags: 1,789
  • sloc: ruby: 12,904; makefile: 100; perl: 43; xml: 14; sh: 4
file content (178 lines) | stat: -rw-r--r-- 6,347 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
require 'compass/commands/project_base'
require 'compass/commands/update_project'

module Compass
  module Commands
    module StatsOptionsParser
      def set_options(opts)
        opts.banner = %Q{
          Usage: compass stats [path/to/project] [options]

          Description:
            Compile project at the path specified (or the current
            directory if not specified) and then compute statistics
            for the sass and css files in the project.

          Options:
        }.strip.split("\n").map{|l| l.gsub(/^ {0,10}/,'')}.join("\n")

        super
      end
    end
    class ProjectStats < UpdateProject

      register :stats

      def initialize(working_path, options)
        super
        assert_project_directory_exists!
      end

      def perform
        super
        require 'compass/stats'
        compiler = new_compiler_instance
        sass_files = sorted_sass_files(compiler)
        total_label = "Total (#{sass_files.size} files):"
        rows       = [[           :-,           :-,           :-,            :-,            :-,          :-,              :-,               :-,             :- ],
                      [   'Filename',      'Rules', 'Properties', 'Mixins Defs', 'Mixins Used',  'Filesize', 'CSS Selectors', 'CSS Properties', 'CSS Filesize' ],
                      [           :-,           :-,           :-,            :-,            :-,          :-,              :-,               :-,             :- ]]
        maximums   =  [ total_label.length,      5,           10,            14,            11,          13,              13,               14,             14 ]
        alignments =  [        :left,       :right,       :right,        :right,        :right,      :right,          :right,           :right,         :right ]
        delimiters =  [ ['| ', ' |'],  [' ', ' |'],  [' ', ' |'],   [' ', ' |'],   [' ', ' |'], [' ', ' |'],     [' ', ' |'],      [' ', ' |'],    [' ', ' |'] ]
        formatters =  [          nil,          nil,          nil,           nil,           nil,         :kb,             nil,             nil,             :kb ]
        totals     =  [ total_label,             0,            0,             0,             0,           0,               0,                0,              0 ]

        columns = rows.first.size

        sass_files.each do |sass_file|
          css_file = compiler.corresponding_css_file(sass_file) unless sass_file[0..0] == '_'
          row = filename_columns(sass_file)
          row += sass_columns(sass_file)
          row += css_columns(css_file)
          row.each_with_index do |c, i|
            maximums[i] = [maximums[i].to_i, c.size].max
            totals[i] = totals[i] + c.to_i if i > 0
          end
          rows << row
        end
        rows << [:-] * columns
        rows << totals.map{|t| t.to_s}
        rows << [:-] * columns
        rows.each do |row|
          row.each_with_index do |col, i|
            print pad(col, maximums[i], :align => alignments[i], :left => delimiters[i].first, :right => delimiters[i].last, :formatter => formatters[i])
          end
          print "\n"
        end
        if @missing_css_parser
          puts "\nInstall #{@missing_css_parser} to enable stats on your css files:\n\n\tgem install #{@missing_css_parser}"
        end
      end

      def pad(c, max, options = {})
        options[:align] ||= :left
        if c == :-
          filler = '-'
          c = ''
        else
          filler = ' '
        end
        c = send(:"format_#{options[:formatter]}", c) if options[:formatter]
        spaces = max - c.size
        filled = filler * [spaces,0].max
        "#{options[:left]}#{filled if options[:align] == :right}#{c}#{filled if options[:align] == :left}#{options[:right]}"
      end

      def format_kb(v)
        return v unless v =~ /^\d+$/
        v = Integer(v)
        if v < 1024
          "#{v} B"
        else
          v = v / 1024.0
          "#{v.ceil} KB"
        end
      end

      def sorted_sass_files(compiler)
        sass_files = compiler.sass_files
        sass_files.map! do |s| 
          filename = Compass.deprojectize(s, File.join(Compass.configuration.project_path, Compass.configuration.sass_dir))
          [s, File.dirname(filename), File.basename(filename)]
        end
        sass_files = sass_files.sort_by do |s,d,f|
          File.join(d, f[0] == ?_ ? f[1..-1] : f)
        end
        sass_files.map!{|s,d,f| s}
      end

      def filename_columns(sass_file)
        filename = Compass.deprojectize(sass_file, working_path)
        [filename]
      end

      def sass_columns(sass_file)
        sf = Compass::Stats::SassFile.new(sass_file)
        sf.analyze!
        %w(rule_count prop_count mixin_def_count mixin_count file_size).map do |t|
          sf.send(t).to_s
        end
      end

      def css_columns(css_file)
        if File.exists?(css_file)
          cf = Compass::Stats::CssFile.new(css_file)
          cf.analyze!
          %w(selector_count prop_count file_size).map do |t|
            cf.send(t).to_s
          end
        else
          return [ '--', '--' , '--']
        end
      rescue LoadError => e
        @missing_css_parser = e.message =~ /iconv/ ? "iconv" : "css_parser"
        return [ 'DISABLED', 'DISABLED', 'DISABLED' ]
      end

      class << self

        def option_parser(arguments)
          parser = Compass::Exec::CommandOptionParser.new(arguments)
          parser.extend(Compass::Exec::GlobalOptionsParser)
          parser.extend(Compass::Exec::ProjectOptionsParser)
          parser.extend(StatsOptionsParser)
        end

        def usage
          option_parser([]).to_s
        end

        def description(command)
          "Report statistics about your stylesheets"
        end

        def primary; false; end

        def parse!(arguments)
          parser = option_parser(arguments)
          parser.parse!
          parse_arguments!(parser, arguments)
          parser.options
        end

        def parse_arguments!(parser, arguments)
          if arguments.size == 1
            parser.options[:project_name] = arguments.shift
          elsif arguments.size == 0
            # default to the current directory.
          else
            raise Compass::Error, "Too many arguments were specified."
          end
        end

      end

    end
  end
end