guard-sass 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -15,7 +15,7 @@ Install the gem with:
15
15
 
16
16
  Add it to your Gemfile:
17
17
 
18
- gem 'guard-sass'
18
+ gem 'guard-sass', :require => false
19
19
 
20
20
  And finally add a basic setup to your Guardfile with:
21
21
 
@@ -92,8 +92,24 @@ The following options can be passed to guard-sass:
92
92
  :all_on_start => true # Compiles all sass files on start
93
93
  # default: false
94
94
 
95
- :extension => '' # Extension used for written files.
96
- # default: '.css'
95
+ :compass => true # Enable Compass support with default Rails 3.1-compatible
96
+ # options. You can overwrite any of these options by passing
97
+ # a hash.
98
+
99
+ :compass => {
100
+ :images_dir => "app/assets/images",
101
+ :images_path => File.join(Dir.pwd, "app/assets/images"),
102
+ :http_images_path => "/assets",
103
+ :http_images_dir => "/assets",
104
+ :http_fonts_path => "/assets",
105
+ :http_fonts_dir => "/assets"
106
+ }
107
+
108
+ :smart_partials => true # Causes guard-sass to do dependency resolution and only
109
+ # recompile the files that need it when you update partials.
110
+ # If not on, then guard-sass will update all files when a
111
+ # partial is changed.
112
+ # default: false
97
113
 
98
114
  :hide_success => true # Disable successful compilation messages.
99
115
  # default: false
@@ -1,6 +1,6 @@
1
1
  module Guard
2
2
  class Sass
3
-
3
+
4
4
  # The formatter handles providing output to the user.
5
5
  class Formatter
6
6
 
@@ -10,35 +10,39 @@ module Guard
10
10
  def initialize(opts={})
11
11
  @hide_success = opts.fetch(:hide_success, false)
12
12
  end
13
-
13
+
14
14
  # Show a success message and notification if successes are being shown.
15
15
  #
16
16
  # @param msg [String]
17
17
  # @param opts [Hash]
18
18
  def success(msg, opts={})
19
19
  unless @hide_success
20
- ::Guard::UI.info(msg, opts)
20
+ benchmark = nil
21
+ if time = opts.delete(:time)
22
+ benchmark = "[\e[33m%2.2fs\e[0m] " % time
23
+ end
24
+ ::Guard::UI.info("\t\e[1;37mSass\e[0m %s%s" % [benchmark, msg], opts)
21
25
  notify(opts[:notification], :image => :success)
22
26
  end
23
27
  end
24
-
28
+
25
29
  # Show an error message and notification.
26
30
  #
27
31
  # @param msg [String]
28
32
  # @param opts [Hash]
29
33
  def error(msg, opts={})
30
- ::Guard::UI.error(msg, opts)
31
- notify(opts[:notification], :image => :failed)
34
+ ::Guard::UI.error("[Sass] #{msg}", opts)
35
+ notify(opts[:notification], :image => :failed)
32
36
  end
33
-
37
+
34
38
  # Show a system notification.
35
- #
39
+ #
36
40
  # @param msg [String]
37
41
  # @param opts [Hash] See http://rubydoc.info/github/guard/guard/master/Guard/Notifier.notify
38
42
  def notify(msg, opts={})
39
43
  ::Guard::Notifier.notify(msg, ({:title => "Guard::Sass"}).merge(opts))
40
44
  end
41
-
45
+
42
46
  end
43
47
  end
44
48
  end
@@ -1,4 +1,5 @@
1
1
  require 'sass'
2
+ require 'benchmark'
2
3
 
3
4
  module Guard
4
5
  class Sass
@@ -32,11 +33,33 @@ module Guard
32
33
  changed_files = []
33
34
 
34
35
  # Assume partials have been checked for previously, so no partials are included here
36
+ rinput = (options[:input] || "").reverse
37
+ routput = (options[:output] || "").reverse
38
+
39
+ input = options[:input] || ''
40
+ output = options[:output] || ''
41
+
42
+ max_length = files.map do |file|
43
+ file.sub(/^#{input}/, '').gsub(/^\//, '').length
44
+ end.max || 0
45
+
35
46
  files.each do |file|
36
47
  begin
37
- css_file = write_file(compile(file), get_output_dir(file), file)
38
- message = options[:noop] ? "verified #{file}" : "compiled #{file} to #{css_file}"
39
- @formatter.success "-> #{message}", :notification => message
48
+ css_file = nil
49
+ time = Benchmark.realtime do
50
+ css_file = write_file(compile(file), get_output_dir(file), file)
51
+ end
52
+
53
+ short_file = file.sub(/^#{input}/, '').gsub(/^\//, '')
54
+ short_css_file = css_file.sub(/^#{output}/, '').gsub(/^\//, '')
55
+
56
+ message = if options[:noop]
57
+ "verified #{file} (#{time})"
58
+ else
59
+ "%s -> %s" % [short_file.ljust(max_length), short_css_file]
60
+ end
61
+
62
+ @formatter.success "#{message}", :notification => message, :time => time
40
63
  changed_files << css_file
41
64
 
42
65
  rescue ::Sass::SyntaxError => e
@@ -61,7 +84,6 @@ module Guard
61
84
  :debug_info => options[:debug_info],
62
85
  :line_numbers => options[:line_numbers]
63
86
  }
64
-
65
87
  ::Sass::Engine.new(content, sass_options).render
66
88
  end
67
89
 
@@ -91,7 +113,8 @@ module Guard
91
113
  # @param file [String] Name of the file
92
114
  # @return [String] Path of file written
93
115
  def write_file(content, dir, file)
94
- path = File.join(dir, File.basename(file, '.*')) << options[:extension]
116
+ filename = File.basename(file).gsub(/(\.s?[ac]ss)+/, '.css')
117
+ path = File.join(dir, filename)
95
118
 
96
119
  unless options[:noop]
97
120
  FileUtils.mkdir_p(dir)
@@ -100,7 +123,6 @@ module Guard
100
123
 
101
124
  path
102
125
  end
103
-
104
126
  end
105
127
  end
106
128
  end
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  class SassVersion
3
- VERSION = '0.7.1'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
data/lib/guard/sass.rb CHANGED
@@ -46,16 +46,41 @@ module Guard
46
46
  if options[:input]
47
47
  load_paths << options[:input]
48
48
  options[:output] = options[:input] unless options.has_key?(:output)
49
- watchers << ::Guard::Watcher.new(%r{^#{ options.delete(:input) }/(.+\.s[ac]ss)$})
49
+ watchers << ::Guard::Watcher.new(%r{^#{ options[:input] }/(.+\.s[ac]ss)$})
50
50
  end
51
-
52
51
  options = DEFAULTS.merge(options)
52
+
53
+ if compass = options.delete(:compass)
54
+ require 'compass'
55
+ compass = {} unless compass.is_a?(Hash)
56
+
57
+ Compass.add_project_configuration
58
+ Compass.configuration.project_path ||= Dir.pwd
59
+ Compass.configuration.images_dir = compass[:images_dir] || "app/assets/images"
60
+ Compass.configuration.images_path = compass[:images_path] || File.join(Dir.pwd, "app/assets/images")
61
+ Compass.configuration.http_images_path = compass[:http_images_path] || "/assets"
62
+ Compass.configuration.http_images_dir = compass[:http_images_dir] || "/assets"
63
+
64
+ Compass.configuration.http_fonts_path = compass[:http_fonts_path] || "/assets"
65
+ Compass.configuration.http_fonts_dir = compass[:http_fonts_dir] || "/assets"
66
+
67
+ Compass.configuration.asset_cache_buster = Proc.new {|*| {:query => Time.now.to_i} }
68
+ options[:load_paths] ||= []
69
+ options[:load_paths] << Compass.configuration.sass_load_paths
70
+ end
71
+
53
72
  options[:load_paths] += load_paths
73
+ options[:load_paths].flatten!
54
74
 
55
75
  @runner = Runner.new(watchers, options)
56
76
  super(watchers, options)
57
77
  end
58
78
 
79
+ # @return [Array<String>] Paths of all sass/scss files
80
+ def files
81
+ Watcher.match_files self, Dir['**/*.s[ac]ss']
82
+ end
83
+
59
84
  # If option set to run all on start, run all when started.
60
85
  #
61
86
  # @raise [:task_has_failed]
@@ -67,17 +92,66 @@ module Guard
67
92
  #
68
93
  # @raise [:task_has_failed]
69
94
  def run_all
70
- files = Dir.glob('**/*.s[ac]ss').reject {|f| partial?(f) }
71
- run_on_changes Watcher.match_files(self, files)
95
+ run_on_changes files.reject {|f| partial?(f) }
96
+ end
97
+
98
+ def resolve_partials_to_owners(paths, depth = 0)
99
+ # If we get more than 10 levels of includes deep, we're probably in an
100
+ # import loop.
101
+ return run_all if depth > 10
102
+
103
+ # Get all files that might have imports
104
+ root = options[:input]
105
+ root += '/' unless root.end_with?('/')
106
+
107
+ partials = paths.find_all {|f| partial?(f) }
108
+ paths -= partials
109
+ sub_paths = partials.map {|p|
110
+ # Remove root, need relative paths
111
+ p.sub(/^#{root}/, '')
112
+ }.map {|p|
113
+ # Make version without underscores
114
+ [p, p.gsub(/(\/|^)_/, '\\1')]
115
+ }.map {|ps|
116
+ # For each of those, make a version with extensions
117
+ ps.map {|p|
118
+ [p, p.gsub(/\.s[ac]ss$/, '')]
119
+ }
120
+ }.flatten
121
+
122
+ # Search through all eligible files and find those we need to recompile
123
+ joined_paths = sub_paths.map {|p| Regexp.escape(p) }.join('|')
124
+ matcher = /@import.*(:?#{joined_paths})/
125
+ importing = files.find_all {|file| open(file, 'r').read.match(matcher) }
126
+ paths += importing
127
+
128
+ # If any of the matched files were partials, then go ahead and walk up the
129
+ # import tree
130
+ if paths.any? {|f| partial?(f) }
131
+ paths = resolve_partials_to_owners(paths, depth + 1)
132
+ end
133
+
134
+ # Return our resolved set of paths to recompile
135
+ paths
136
+ end
137
+
138
+ def run_with_partials(paths)
139
+ if options[:smart_partials]
140
+ paths = resolve_partials_to_owners(paths)
141
+ run_on_changes Watcher.match_files(self, paths) unless paths.nil?
142
+ else
143
+ run_all
144
+ end
72
145
  end
73
146
 
74
- # Build the files given. If a 'partial' file is found (begins with '_') calls
75
- # {#run_all} as we don't know which other files need to use it.
147
+ # Builds the files given. If a 'partial' file is found (name begins with
148
+ # '_'), calls {#run_with_partials} so that files which include it are
149
+ # rebuilt.
76
150
  #
77
151
  # @param paths [Array<String>]
78
152
  # @raise [:task_has_failed]
79
153
  def run_on_changes(paths)
80
- return run_all if paths.any? {|f| partial?(f) }
154
+ return run_with_partials(paths) if paths.any? {|f| partial?(f) }
81
155
 
82
156
  changed_files, success = @runner.run(paths)
83
157
  notify changed_files
@@ -102,8 +176,9 @@ module Guard
102
176
  end
103
177
  end
104
178
 
179
+ # @return Whether +path+ is a partial
105
180
  def partial?(path)
106
- File.basename(path)[0,1] == "_"
181
+ File.basename(path).start_with? '_'
107
182
  end
108
183
 
109
184
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guard-sass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-06 00:00:00.000000000 Z
12
+ date: 2012-07-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: guard
@@ -114,3 +114,4 @@ signing_key:
114
114
  specification_version: 3
115
115
  summary: Guard gem for Sass
116
116
  test_files: []
117
+ has_rdoc: