guard-sass 0.7.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: