guard-sass 0.3.4 → 0.4.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
@@ -33,15 +33,11 @@ guard-sass can be adapted to all kind of projects. Please read the
33
33
 
34
34
  In a Ruby project you want to configure your input and output directories.
35
35
 
36
- ```ruby
37
- guard 'sass', :input => 'sass', :output => 'styles'
38
- ```
36
+ guard 'sass', :input => 'sass', :output => 'styles'
39
37
 
40
38
  If your output directory is the same as the input directory, you can simply skip it:
41
39
 
42
- ```ruby
43
- guard 'sass', :input => 'styles'
44
- ```
40
+ guard 'sass', :input => 'styles'
45
41
 
46
42
  ### Rails app with the asset pipeline
47
43
 
@@ -51,65 +47,57 @@ still like to have feedback on the validation of your stylesheets (preferably
51
47
  with a Growl notification) directly after you save a change, then you can still
52
48
  use this Guard and simply skip generation of the output file:
53
49
 
54
- ```ruby
55
- guard 'sass', :input => 'app/assets/stylesheets', :noop => true
56
- ```
50
+ guard 'sass', :input => 'app/assets/stylesheets', :noop => true
57
51
 
58
52
  This gives you (almost) immediate feedback on whether the changes made are valid,
59
53
  and is much faster than making a subsequent request to your Rails application.
60
54
  If you just want to be notified when an error occurs you can hide the success
61
55
  compilation message:
62
56
 
63
- ```ruby
64
- guard 'sass',
65
- :input => 'app/assets/stylesheets',
66
- :noop => true,
67
- :hide_success => true
68
- ```
57
+ guard 'sass',
58
+ :input => 'app/assets/stylesheets',
59
+ :noop => true,
60
+ :hide_success => true
69
61
 
70
62
  ### Rails app without the asset pipeline
71
63
 
72
64
  Without the asset pipeline you just define an input and output directory as in
73
65
  a normal Ruby project:
74
66
 
75
- ```ruby
76
- guard 'sass', :input => 'app/stylesheets', :output => 'public/stylesheets'
77
- ```
67
+ guard 'sass', :input => 'app/stylesheets', :output => 'public/stylesheets'
78
68
 
79
69
  ## Options
80
70
 
81
71
  The following options can be passed to guard-sass:
82
72
 
83
- ```ruby
84
- :input => 'sass' # Relative path to the input directory.
85
- # A suffix `/(.+\.s[ac]ss)` will be added to this option.
86
- # default: nil
87
-
88
- :output => 'css' # Relative path to the output directory.
89
- # default: 'css' or the :input option when supplied
90
-
91
- :notification => false # Whether to display success and error notifications.
92
- # default: true
93
-
94
- :hide_success => true # Disable successful compilation messages.
95
- # default: false
96
-
97
- :shallow => true # Do not create nested output directories.
98
- # default: false
99
-
100
- :style => :nested # Controls the output style. Accepted options are :nested,
101
- # :compact, :compressed and :expanded
102
- # default: :nested
103
-
104
- :load_paths => ['sass/partials'] # Paths for sass to find imported sass files from.
105
- # default: all directories under current
106
-
107
- :noop => true # No operation: Do not write output file
108
- # default: false
109
-
110
- :debug_info_ => true # File and line number info for FireSass.
111
- # default: false
112
- ```
73
+ :input => 'sass' # Relative path to the input directory.
74
+ # A suffix `/(.+\.s[ac]ss)` will be added to this option.
75
+ # default: nil
76
+
77
+ :output => 'css' # Relative path to the output directory.
78
+ # default: 'css' or the :input option when supplied
79
+
80
+ :notification => false # Whether to display success and error notifications.
81
+ # default: true
82
+
83
+ :hide_success => true # Disable successful compilation messages.
84
+ # default: false
85
+
86
+ :shallow => true # Do not create nested output directories.
87
+ # default: false
88
+
89
+ :style => :nested # Controls the output style. Accepted options are :nested,
90
+ # :compact, :compressed and :expanded
91
+ # default: :nested
92
+
93
+ :load_paths => ['sass/partials'] # Paths for sass to find imported sass files from.
94
+ # default: all directories under current
95
+
96
+ :noop => true # No operation: Do not write output file
97
+ # default: false
98
+
99
+ :debug_info_ => true # File and line number info for FireSass.
100
+ # default: false
113
101
 
114
102
  ### Output short notation
115
103
 
@@ -117,23 +105,19 @@ guard-sass also has a short notation like [guard-coffeescript][gcs], this lets
117
105
  you define an input folder (with an optional output folder) automatically creating
118
106
  the required watcher.
119
107
 
120
- ```ruby
121
- guard 'sass', :input => 'sass', :output => 'styles'
122
- # or
123
- guard 'sass', :input => 'stylesheets'
124
- ```
108
+ guard 'sass', :input => 'sass', :output => 'styles'
109
+ # or
110
+ guard 'sass', :input => 'stylesheets'
125
111
 
126
112
  These are equivalent to
127
113
 
128
- ```ruby
129
- guard 'sass', :output => 'styles' do
130
- watch %r{^sass/(.+\.s[ac]ss)$}
131
- end
132
-
133
- guard 'sass' do
134
- watch %r{^stylesheets/(.+\.s[ac]ss)$}
135
- end
136
- ```
114
+ guard 'sass', :output => 'styles' do
115
+ watch %r{^sass/(.+\.s[ac]ss)$}
116
+ end
117
+
118
+ guard 'sass' do
119
+ watch %r{^stylesheets/(.+\.s[ac]ss)$}
120
+ end
137
121
 
138
122
  ### Nested directories
139
123
 
@@ -145,27 +129,19 @@ output directory. The detection is based on the match of the watch regular expre
145
129
 
146
130
  A file
147
131
 
148
- ```
149
- /app/stylesheets/form/button.sass
150
- ```
132
+ /app/stylesheets/form/button.sass
151
133
 
152
134
  that has been detected by the watch
153
135
 
154
- ```ruby
155
- watch(%r{^app/stylesheets/(.+\.s[ac]ss)$})
156
- ```
136
+ watch(%r{^app/stylesheets/(.+\.s[ac]ss)$})
157
137
 
158
138
  with an output directory of
159
139
 
160
- ```ruby
161
- :output => 'public/stylesheets'
162
- ```
140
+ :output => 'public/stylesheets'
163
141
 
164
142
  will be compiled to
165
143
 
166
- ```
167
- public/stylesheets/form/button.css
168
- ```
144
+ public/stylesheets/form/button.css
169
145
 
170
146
  Note the parenthesis around `.+\.s[ac]ss`. This enables guard-sass to place
171
147
  the full path that was matched inside the parenthesis into the proper output directory.
@@ -0,0 +1,49 @@
1
+ module Guard
2
+ class Sass
3
+
4
+ # The formatter handles providing output to the user.
5
+ class Formatter
6
+
7
+ # @param opts [Hash]
8
+ # @option opts [Boolean] :notification
9
+ # Whether to show notifications
10
+ # @option otps [Boolean] :success
11
+ # Whether to print success messages
12
+ def initialize(opts={})
13
+ @notification = opts.fetch(:notification, true)
14
+ @success = opts.fetch(:show_success, true)
15
+ end
16
+
17
+ # Show a success message and notification if successes are being shown.
18
+ #
19
+ # @param msg [String]
20
+ # @param opts [Hash]
21
+ def success(msg, opts={})
22
+ if @success
23
+ ::Guard::UI.info(msg, opts)
24
+ notify(opts[:notification], :image => :success)
25
+ end
26
+ end
27
+
28
+ # Show an error message and notification.
29
+ #
30
+ # @param msg [String]
31
+ # @param opts [Hash]
32
+ def error(msg, opts={})
33
+ ::Guard::UI.error(msg, opts)
34
+ notify(opts[:notification], :image => :failed)
35
+ end
36
+
37
+ # Show a system notification, if notifications are enabled.
38
+ #
39
+ # @param msg [String]
40
+ # @param opts [Hash] See http://rubydoc.info/github/guard/guard/master/Guard/Notifier.notify
41
+ def notify(msg, opts={})
42
+ if @notification
43
+ ::Guard::Notifier.notify(msg, ({:title => "Guard::Sass"}).merge(opts))
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,110 @@
1
+ require 'sass'
2
+
3
+ module Guard
4
+ class Sass
5
+
6
+ class Runner
7
+
8
+ attr_reader :options
9
+
10
+ # @param watchers [Array<Guard::Watcher>]
11
+ # @param options [Hash] See Guard::Sass::DEFAULTS for available options
12
+ def initialize(watchers, options={})
13
+ @watchers = watchers
14
+ @options = options
15
+ @formatter = Formatter.new(
16
+ :notification => options[:notification],
17
+ :show_success => !options[:hide_success]
18
+ )
19
+ end
20
+
21
+ # @param files [Array<String>]
22
+ # @return [Array<Array,Boolean>]
23
+ def run(files)
24
+ changed_files, errors = compile_files(files)
25
+ [changed_files, errors.empty?]
26
+ end
27
+
28
+ private
29
+
30
+ # @param files [Array<String>] Files to compile
31
+ # @return [Array<Array,Array>] The files which have been changed and an array
32
+ # of any error messages if any errors occurred.
33
+ def compile_files(files)
34
+ errors = []
35
+ changed_files = []
36
+
37
+ # Assume partials have been checked for previously, so no partials are included here
38
+ files.each do |file|
39
+ begin
40
+ css_file = write_file(compile(file), get_output_dir(file), file)
41
+
42
+ message = options[:noop] ? "verified #{file}" : "compiled #{file} to #{css_file}"
43
+ @formatter.success "-> #{message}", :notification => message
44
+
45
+ changed_files << css_file
46
+
47
+ rescue ::Sass::SyntaxError => e
48
+ message = (options[:noop] ? 'validation' : 'rebuild') + " of #{file} failed"
49
+ errors << message
50
+ @formatter.error "Sass > #{e.sass_backtrace_str(file)}", :notification => message
51
+ end
52
+ end
53
+
54
+ [changed_files.compact, errors]
55
+ end
56
+
57
+ # @param file [String] Path to sass/scss file to compile
58
+ # @return [String] Compiled css.
59
+ def compile(file)
60
+ content = IO.read(file)
61
+
62
+ sass_options = {
63
+ :syntax => file[-4..-1].to_sym,
64
+ :load_paths => options[:load_paths],
65
+ :style => options[:style],
66
+ :debug_info => options[:debug_info]
67
+ }
68
+
69
+ ::Sass::Engine.new(content, sass_options).render
70
+ end
71
+
72
+ # @param file [String]
73
+ # @return [String] Directory to write +file+ to
74
+ def get_output_dir(file)
75
+ folder = options[:output]
76
+
77
+ unless options[:shallow]
78
+ @watchers.product([file]).each do |watcher, file|
79
+ if matches = file.match(watcher.pattern)
80
+ if matches[1]
81
+ folder = File.join(options[:output], File.dirname(matches[1])).gsub(/\/\.$/, '')
82
+ break
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ folder
89
+ end
90
+
91
+ # Write file contents, creating directories where required.
92
+ #
93
+ # @param content [String] Contents of the file
94
+ # @param dir [String] Directory to write to
95
+ # @param file [String] Name of the file
96
+ # @return [String] Path of file written
97
+ def write_file(content, dir, file)
98
+ path = File.join(dir, File.basename(file.split('.')[0])) << '.css'
99
+
100
+ unless options[:noop]
101
+ FileUtils.mkdir_p(dir)
102
+ File.open(path, 'w') {|f| f.write(content) }
103
+ end
104
+
105
+ path
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  class SassVersion
3
- VERSION = '0.3.4'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
data/lib/guard/sass.rb CHANGED
@@ -2,79 +2,52 @@ require 'guard'
2
2
  require 'guard/guard'
3
3
  require 'guard/watcher'
4
4
 
5
- require 'sass'
6
-
7
5
  module Guard
8
6
  class Sass < Guard
7
+
8
+ autoload :Runner, 'guard/sass/runner'
9
+ autoload :Formatter, 'guard/sass/formatter'
9
10
 
10
11
  DEFAULTS = {
11
- :output => 'css', # Output directory
12
- :notification => true, # Enable notifications?
13
- :shallow => false, # Output nested directories?
14
- :style => :nested, # Nested output
15
- :debug_info => false, # File and line number info for FireSass
16
- :noop => false, # Do no write output file
17
- :hide_success => false, # Do not show success message
12
+ :output => 'css',
13
+ :style => :nested,
14
+ :notification => true,
15
+ :shallow => false,
16
+ :debug_info => false,
17
+ :noop => false,
18
+ :hide_success => false,
18
19
  :load_paths => Dir.glob('**/**').find_all {|i| File.directory?(i) }
19
20
  }
20
21
 
21
- def initialize(watchers = [], options = {})
22
+ # @param watchers [Array<Guard::Watcher>]
23
+ # @param options [Hash]
24
+ # @option options [String] :input
25
+ # The input directory
26
+ # @option options [String] :output
27
+ # The output directory
28
+ # @option options [Array<String>] :load_paths
29
+ # List of directories you can @import from
30
+ # @option options [Boolean] :notification
31
+ # Whether to show notifications
32
+ # @option options [Boolean] :shallow
33
+ # Whether to output nested directories
34
+ # @option options [Boolean] :debug_info
35
+ # Whether to output file and line number info for FireSass
36
+ # @option options [Boolean] :noop
37
+ # Whether to run in "asset pipe" mode, no ouput, just validation
38
+ # @option options [Boolean] :hide_success
39
+ # Whether to hide all success messages
40
+ # @option options [Symbol] :style
41
+ # See http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#output_style
42
+ def initialize(watchers=[], options={})
22
43
  if options[:input]
23
44
  options[:output] = options[:input] unless options.has_key?(:output)
24
45
  watchers << ::Guard::Watcher.new(%r{^#{options.delete(:input)}/(.+\.s[ac]ss)$})
25
46
  end
26
-
27
- super(watchers, DEFAULTS.merge(options))
28
- end
29
-
30
-
31
- # Builds the sass or scss. Determines engine to use by extension
32
- # of path given.
33
- #
34
- # @param file [String] path to file to build
35
- # @return [String] the output css
36
- #
37
- def build_sass(file)
38
- content = File.new(file).read
39
- # sass or scss?
40
- type = file[-4..-1].to_sym
41
- sass_options = {
42
- :syntax => type,
43
- :load_paths => options[:load_paths],
44
- :style => options[:style].to_sym,
45
- :debug_info => options[:debug_info],
46
- }
47
47
 
48
- ::Sass::Engine.new(content, sass_options).render
49
- end
50
-
51
- # Get the file path to output the css based on the file being
52
- # built.
53
- #
54
- # @param file [String] path to file being built
55
- # @return [String] path to file where output should be written
56
- #
57
- def get_output(file)
58
- folder = File.join ::Guard.listener.directory, options[:output]
59
-
60
- unless options[:shallow]
61
- watchers.product([file]).each do |watcher, file|
62
- if matches = file.match(watcher.pattern)
63
- if matches[1]
64
- folder = File.join(options[:output], File.dirname(matches[1])).gsub(/\/\.$/, '')
65
- break
66
- end
67
- end
68
- end
69
- end
70
-
71
- FileUtils.mkdir_p folder
72
- r = File.join folder, File.basename(file).split('.')[0]
73
- r << '.css'
74
- end
75
-
76
- def ignored?(path)
77
- File.basename(path)[0,1] == "_"
48
+ options = DEFAULTS.merge(options)
49
+ @runner = Runner.new(watchers, options)
50
+ super(watchers, options)
78
51
  end
79
52
 
80
53
  # ================
@@ -82,46 +55,35 @@ module Guard
82
55
  # ================
83
56
 
84
57
  # Build all files being watched
58
+ #
59
+ # @return [Boolean] No errors?
85
60
  def run_all
86
- run_on_change(Watcher.match_files(self, Dir.glob(File.join('**', '[^_]*.*'))))
61
+ run_on_change(Watcher.match_files(self, Dir.glob(File.join('**', '*.*'))))
87
62
  end
88
63
 
89
- # Build the files given
90
- def run_on_change(paths)
91
- partials = paths.select { |f| ignored?(f) }
64
+ # Build the files given. If a 'partial' file is found (begins with '_') calls
65
+ # {#run_all} as we don't know which other files need to use it.
66
+ #
67
+ # @param paths [Array<String>]
68
+ # @return [Boolean] No errors?
69
+ def run_on_change(paths)
70
+ partials = paths.select {|f| File.basename(f)[0,1] == "_" }
92
71
  return run_all unless partials.empty?
93
-
94
- changed_files = paths.reject{ |f| ignored?(f) }.map do |file|
95
- css_file = get_output(file)
96
- begin
97
- contents = build_sass(file)
98
- if contents
99
- message = options[:noop] ? "verified #{file}" : "compiled #{file} to #{css_file}"
100
-
101
- File.open(css_file, 'w') {|f| f.write(contents) } unless options[:noop]
102
- ::Guard::UI.info "-> #{message}", :reset => true
103
- if options[:notification] && !options[:hide_success]
104
- ::Guard::Notifier.notify(message, :title => "Guard::Sass", :image => :success)
105
- end
106
- end
107
- css_file
108
- rescue ::Sass::SyntaxError => e
109
- ::Guard::UI.error "Sass > #{e.sass_backtrace_str(file)}"
110
- ::Guard::Notifier.notify(
111
- (options[:noop] ? 'validation' : 'rebuild') + " failed > #{e.sass_backtrace_str(file)}",
112
- :title => "Guard::Sass",
113
- :image => :error
114
- ) if options[:notification]
115
- nil
116
- end
117
- end.compact
72
+
73
+ changed_files, success = @runner.run(paths)
74
+
118
75
  notify changed_files
76
+ success
119
77
  end
120
-
78
+
79
+ # Notify other guards about files that have been changed so that other guards can
80
+ # work on the changed files.
81
+ #
82
+ # @param changed_files [Array<String>]
121
83
  def notify(changed_files)
122
- ::Guard.guards.reject{ |guard| guard == self }.each do |guard|
84
+ ::Guard.guards.each do |guard|
123
85
  paths = Watcher.match_files(guard, changed_files)
124
- guard.run_on_change paths unless paths.empty?
86
+ guard.run_on_change(paths) unless paths.empty?
125
87
  end
126
88
  end
127
89
 
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.3.4
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-26 00:00:00.000000000Z
12
+ date: 2011-10-01 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: guard
16
- requirement: &2160420520 !ruby/object:Gem::Requirement
16
+ requirement: &2156617400 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.4.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2160420520
24
+ version_requirements: *2156617400
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sass
27
- requirement: &2160419700 !ruby/object:Gem::Requirement
27
+ requirement: &2156616940 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '3.1'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2160419700
35
+ version_requirements: *2156616940
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &2160418160 !ruby/object:Gem::Requirement
38
+ requirement: &2156616480 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.2
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2160418160
46
+ version_requirements: *2156616480
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &2160417240 !ruby/object:Gem::Requirement
49
+ requirement: &2156616020 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>'
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 2.0.0.rc
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2160417240
57
+ version_requirements: *2156616020
58
58
  description: Guard::Sass automatically rebuilds sass (like sass --watch)
59
59
  email:
60
60
  - m@hawx.me
@@ -62,6 +62,8 @@ executables: []
62
62
  extensions: []
63
63
  extra_rdoc_files: []
64
64
  files:
65
+ - lib/guard/sass/formatter.rb
66
+ - lib/guard/sass/runner.rb
65
67
  - lib/guard/sass/templates/Guardfile
66
68
  - lib/guard/sass/version.rb
67
69
  - lib/guard/sass.rb