guard-sass 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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