haml-edge 3.1.73 → 3.1.74

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,220 +2,122 @@
2
2
  # so that we can load it independently in Rails 3,
3
3
  # where the full plugin stuff is lazy-loaded.
4
4
 
5
- require 'sass/callbacks'
6
-
7
5
  module Sass
8
6
  module Plugin
9
- include Sass::Callbacks
10
- extend self
11
-
12
- # Register a callback to be run before stylesheets are mass-updated.
13
- # This is run whenever \{#update\_stylesheets} is called,
14
- # unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
15
- # is enabled.
16
- #
17
- # @yield [individual_files]
18
- # @yieldparam individual_files [<(String, String)>]
19
- # Individual files to be updated, in addition to the directories
20
- # specified in the options.
21
- # The first element of each pair is the source file,
22
- # the second is the target CSS file.
23
- define_callback :updating_stylesheets
24
-
25
- # Register a callback to be run before a single stylesheet is updated.
26
- # The callback is only run if the stylesheet is guaranteed to be updated;
27
- # if the CSS file is fresh, this won't be run.
28
- #
29
- # Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
30
- # is enabled, this callback won't be run
31
- # when an exception CSS file is being written.
32
- # To run an action for those files, use \{#on\_compilation\_error}.
33
- #
34
- # @yield [template, css]
35
- # @yieldparam template [String]
36
- # The location of the Sass/SCSS file being updated.
37
- # @yieldparam css [String]
38
- # The location of the CSS file being generated.
39
- define_callback :updating_stylesheet
40
-
41
- # Register a callback to be run when Sass decides not to update a stylesheet.
42
- # In particular, the callback is run when Sass finds that
43
- # the template file and none of its dependencies
44
- # have been modified since the last compilation.
45
- #
46
- # Note that this is **not** run when the
47
- # \{file:SASS_REFERENCE.md#never-update_option `:never_update` option} is set,
48
- # nor when Sass decides not to compile a partial.
49
- #
50
- # @yield [template, css]
51
- # @yieldparam template [String]
52
- # The location of the Sass/SCSS file not being updated.
53
- # @yieldparam css [String]
54
- # The location of the CSS file not being generated.
55
- define_callback :not_updating_stylesheet
56
-
57
- # Register a callback to be run when there's an error
58
- # compiling a Sass file.
59
- # This could include not only errors in the Sass document,
60
- # but also errors accessing the file at all.
61
- #
62
- # @yield [error, template, css]
63
- # @yieldparam error [Exception] The exception that was raised.
64
- # @yieldparam template [String]
65
- # The location of the Sass/SCSS file being updated.
66
- # @yieldparam css [String]
67
- # The location of the CSS file being generated.
68
- define_callback :compilation_error
69
-
70
- # Register a callback to be run when Sass creates a directory
71
- # into which to put CSS files.
72
- #
73
- # Note that even if multiple levels of directories need to be created,
74
- # the callback may only be run once.
75
- # For example, if "foo/" exists and "foo/bar/baz/" needs to be created,
76
- # this may only be run for "foo/bar/baz/".
77
- # This is not a guarantee, however;
78
- # it may also be run for "foo/bar/".
79
- #
80
- # @yield [dirname]
81
- # @yieldparam dirname [String]
82
- # The location of the directory that was created.
83
- define_callback :creating_directory
84
-
85
- # Register a callback to be run when Sass detects
86
- # that a template has been modified.
87
- # This is only run when using \{#watch}.
88
- #
89
- # @yield [template]
90
- # @yieldparam template [String]
91
- # The location of the template that was modified.
92
- define_callback :template_modified
93
-
94
- # Register a callback to be run when Sass detects
95
- # that a new template has been created.
96
- # This is only run when using \{#watch}.
97
- #
98
- # @yield [template]
99
- # @yieldparam template [String]
100
- # The location of the template that was created.
101
- define_callback :template_created
102
-
103
- # Register a callback to be run when Sass detects
104
- # that a template has been deleted.
105
- # This is only run when using \{#watch}.
106
- #
107
- # @yield [template]
108
- # @yieldparam template [String]
109
- # The location of the template that was deleted.
110
- define_callback :template_deleted
111
-
112
- # Register a callback to be run when Sass deletes a CSS file.
113
- # This happens when the corresponding Sass/SCSS file has been deleted.
114
- #
115
- # @yield [filename]
116
- # @yieldparam filename [String]
117
- # The location of the CSS file that was deleted.
118
- define_callback :deleting_css
119
-
120
- @options = {:full_exception => true}
121
-
122
- # An options hash.
123
- # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
124
- #
125
- # @return [{Symbol => Object}]
126
- attr_reader :options
127
-
128
- # Sets the options hash.
129
- # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
130
- #
131
- # @param value [{Symbol => Object}] The options hash
132
- def options=(value)
133
- @options.merge!(value)
134
- end
135
-
136
- # Non-destructively modifies \{#options} so that default values are properly set.
137
- #
138
- # @param additional_options [{Symbol => Object}] An options hash with which to merge \{#options}
139
- # @return [{Symbol => Object}] The modified options hash
140
- def engine_options(additional_options = {})
141
- opts = options.dup.merge(additional_options)
142
- opts[:load_paths] = load_paths(opts)
143
- opts
144
- end
145
-
146
- # Adds a new template-location/css-location mapping.
147
- # This means that Sass/SCSS files in `template_location`
148
- # will be compiled to CSS files in `css_location`.
149
- #
150
- # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
151
- # since the option can be in multiple formats.
152
- #
153
- # Note that this method will change `options[:template_location]`
154
- # to be in the Array format.
155
- # This means that even if `options[:template_location]`
156
- # had previously been a Hash or a String,
157
- # it will now be an Array.
158
- #
159
- # @param template_location [String] The location where Sass/SCSS files will be.
160
- # @param css_location [String] The location where compiled CSS files will go.
161
- def add_template_location(template_location, css_location = options[:css_location])
162
- normalize_template_location!
163
- template_location_array << [template_location, css_location]
164
- end
165
-
166
- # Removes a template-location/css-location mapping.
167
- # This means that Sass/SCSS files in `template_location`
168
- # will no longer be compiled to CSS files in `css_location`.
169
- #
170
- # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
171
- # since the option can be in multiple formats.
172
- #
173
- # Note that this method will change `options[:template_location]`
174
- # to be in the Array format.
175
- # This means that even if `options[:template_location]`
176
- # had previously been a Hash or a String,
177
- # it will now be an Array.
178
- #
179
- # @param template_location [String]
180
- # The location where Sass/SCSS files were,
181
- # which is now going to be ignored.
182
- # @param css_location [String]
183
- # The location where compiled CSS files went, but will no longer go.
184
- # @return [Boolean]
185
- # Non-`nil` if the given mapping already existed and was removed,
186
- # or `nil` if nothing was changed.
187
- def remove_template_location(template_location, css_location = options[:css_location])
188
- normalize_template_location!
189
- template_location_array.delete([template_location, css_location])
190
- end
191
-
192
- # Returns the template locations configured for Sass
193
- # as an array of `[template_location, css_location]` pairs.
194
- # See the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
195
- # for details.
196
- #
197
- # @return [Array<(String, String)>]
198
- # An array of `[template_location, css_location]` pairs.
199
- def template_location_array
200
- old_template_location = options[:template_location]
201
- normalize_template_location!
202
- options[:template_location]
203
- ensure
204
- options[:template_location] = old_template_location
205
- end
206
-
207
- private
208
-
209
- def normalize_template_location!
210
- return if options[:template_location].is_a?(Array)
211
- options[:template_location] =
212
- case options[:template_location]
213
- when nil
214
- css_location = options[:css_location] || './public/stylesheets'
215
- [[File.join(css_location, 'sass'), css_location]]
216
- when String; [[options[:template_location], options[:css_location]]]
217
- else; options[:template_location].to_a
218
- end
7
+ module Configuration
8
+
9
+ # Returns the default options for a {Sass::Plugin::Compiler}.
10
+ #
11
+ # @return [{Symbol => Object}]
12
+ def default_options
13
+ @default_options ||= {
14
+ :css_location => './public/stylesheets',
15
+ :always_update => false,
16
+ :always_check => true,
17
+ :full_exception => true,
18
+ :cache_location => ".sass-cache"
19
+ }.freeze
20
+ end
21
+
22
+ # Resets the options and {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
23
+ def reset!
24
+ @options = nil
25
+ clear_callbacks!
26
+ end
27
+
28
+ # An options hash.
29
+ # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
30
+ #
31
+ # @return [{Symbol => Object}]
32
+ def options
33
+ @options ||= default_options.dup
34
+ @options[:cache_store] ||= Sass::FileCacheStore.new(@options[:cache_location])
35
+ @options
36
+ end
37
+
38
+ # Sets the options hash.
39
+ # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
40
+ # See {Sass::Plugin::Configuration#reset!}
41
+ # @deprecated Instead, modify the options hash in-place.
42
+ # @param value [{Symbol => Object}] The options hash
43
+ def options=(value)
44
+ Haml::Util.haml_warn("Setting Sass::Plugin.options is deprecated " +
45
+ "and will be removed in a future release.")
46
+ options.merge!(value)
47
+ end
48
+
49
+ # Adds a new template-location/css-location mapping.
50
+ # This means that Sass/SCSS files in `template_location`
51
+ # will be compiled to CSS files in `css_location`.
52
+ #
53
+ # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
54
+ # since the option can be in multiple formats.
55
+ #
56
+ # Note that this method will change `options[:template_location]`
57
+ # to be in the Array format.
58
+ # This means that even if `options[:template_location]`
59
+ # had previously been a Hash or a String,
60
+ # it will now be an Array.
61
+ #
62
+ # @param template_location [String] The location where Sass/SCSS files will be.
63
+ # @param css_location [String] The location where compiled CSS files will go.
64
+ def add_template_location(template_location, css_location = options[:css_location])
65
+ normalize_template_location!
66
+ template_location_array << [template_location, css_location]
67
+ end
68
+
69
+ # Removes a template-location/css-location mapping.
70
+ # This means that Sass/SCSS files in `template_location`
71
+ # will no longer be compiled to CSS files in `css_location`.
72
+ #
73
+ # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
74
+ # since the option can be in multiple formats.
75
+ #
76
+ # Note that this method will change `options[:template_location]`
77
+ # to be in the Array format.
78
+ # This means that even if `options[:template_location]`
79
+ # had previously been a Hash or a String,
80
+ # it will now be an Array.
81
+ #
82
+ # @param template_location [String]
83
+ # The location where Sass/SCSS files were,
84
+ # which is now going to be ignored.
85
+ # @param css_location [String]
86
+ # The location where compiled CSS files went, but will no longer go.
87
+ # @return [Boolean]
88
+ # Non-`nil` if the given mapping already existed and was removed,
89
+ # or `nil` if nothing was changed.
90
+ def remove_template_location(template_location, css_location = options[:css_location])
91
+ normalize_template_location!
92
+ template_location_array.delete([template_location, css_location])
93
+ end
94
+
95
+ # Returns the template locations configured for Sass
96
+ # as an array of `[template_location, css_location]` pairs.
97
+ # See the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
98
+ # for details.
99
+ #
100
+ # @return [Array<(String, String)>]
101
+ # An array of `[template_location, css_location]` pairs.
102
+ def template_location_array
103
+ old_template_location = options[:template_location]
104
+ normalize_template_location!
105
+ options[:template_location]
106
+ ensure
107
+ options[:template_location] = old_template_location
108
+ end
109
+
110
+ private
111
+
112
+ def normalize_template_location!
113
+ return if options[:template_location].is_a?(Array)
114
+ options[:template_location] =
115
+ case options[:template_location]
116
+ when nil; [[File.join(options[:css_location], 'sass'), options[:css_location]]]
117
+ when String; [[options[:template_location], options[:css_location]]]
118
+ else; options[:template_location].to_a
119
+ end
120
+ end
219
121
  end
220
122
  end
221
123
  end
@@ -1,21 +1,32 @@
1
1
  unless defined?(Sass::MERB_LOADED)
2
2
  Sass::MERB_LOADED = true
3
3
 
4
- version = Merb::VERSION.split('.').map { |n| n.to_i }
5
- if version[0] <= 0 && version[1] < 5
6
- root = MERB_ROOT
7
- env = MERB_ENV
8
- else
9
- root = Merb.root.to_s
10
- env = Merb.environment
4
+ module Sass::Plugin::Configuration
5
+ # Different default options in a m envirionment.
6
+ def default_options
7
+ @default_options ||= begin
8
+ version = Merb::VERSION.split('.').map { |n| n.to_i }
9
+ if version[0] <= 0 && version[1] < 5
10
+ root = MERB_ROOT
11
+ env = MERB_ENV
12
+ else
13
+ root = Merb.root.to_s
14
+ env = Merb.environment
15
+ end
16
+
17
+ {
18
+ :always_update => false,
19
+ :template_location => root + '/public/stylesheets/sass',
20
+ :css_location => root + '/public/stylesheets',
21
+ :cache_location => root + '/tmp/sass-cache',
22
+ :always_check => env != "production",
23
+ :quiet => env != "production",
24
+ :full_exception => env != "production"
25
+ }.freeze
26
+ end
27
+ end
11
28
  end
12
29
 
13
- Sass::Plugin.options.merge!(:template_location => root + '/public/stylesheets/sass',
14
- :css_location => root + '/public/stylesheets',
15
- :cache_location => root + '/tmp/sass-cache',
16
- :always_check => env != "production",
17
- :quiet => env != "production",
18
- :full_exception => env != "production")
19
30
  config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {}
20
31
 
21
32
  if defined? config.symbolize_keys!
@@ -1,13 +1,22 @@
1
1
  unless defined?(Sass::RAILS_LOADED)
2
2
  Sass::RAILS_LOADED = true
3
3
 
4
- # Reverse-merging (we're in Rails, anyway) so we dont' clobber what's already been defined further up-stream
5
- Sass::Plugin.options.reverse_merge!(:template_location => Haml::Util.rails_root + '/public/stylesheets/sass',
6
- :css_location => Haml::Util.rails_root + '/public/stylesheets',
7
- :cache_location => Haml::Util.rails_root + '/tmp/sass-cache',
8
- :always_check => Haml::Util.rails_env == "development",
9
- :quiet => Haml::Util.rails_env != "production",
10
- :full_exception => Haml::Util.rails_env != "production")
4
+ module Sass::Plugin::Configuration
5
+ # Different default options in a rails envirionment.
6
+ def default_options
7
+ @default_options ||= {
8
+ :always_update => false,
9
+ :template_location => Haml::Util.rails_root + '/public/stylesheets/sass',
10
+ :css_location => Haml::Util.rails_root + '/public/stylesheets',
11
+ :cache_location => Haml::Util.rails_root + '/tmp/sass-cache',
12
+ :always_check => Haml::Util.rails_env == "development",
13
+ :quiet => Haml::Util.rails_env != "production",
14
+ :full_exception => Haml::Util.rails_env != "production"
15
+ }.freeze
16
+ end
17
+ end
18
+
19
+ Sass::Plugin.options.reverse_merge!(Sass::Plugin.default_options)
11
20
 
12
21
  if defined?(ActionController::Metal)
13
22
  # Rails >= 3.0
@@ -6,8 +6,9 @@ module Sass
6
6
  #
7
7
  # * A class-level dependency cache which stores @import paths for each file.
8
8
  # This is a long-lived cache that is reused by every StalenessChecker instance.
9
- # * Two short-lived instance-level caches, one for file mtimes
10
- # and one for whether a file is stale during this particular run.
9
+ # * Three short-lived instance-level caches, one for file mtimes,
10
+ # one for whether a file is stale during this particular run.
11
+ # and one for the parse tree for a file.
11
12
  # These are only used by a single StalenessChecker instance.
12
13
  #
13
14
  # Usage:
@@ -26,19 +27,24 @@ module Sass
26
27
  @dependencies_cache = {}
27
28
 
28
29
  class << self
30
+ # TODO: attach this to a compiler instance.
29
31
  # @private
30
32
  attr_accessor :dependencies_cache
31
33
  end
32
34
 
33
35
  # Creates a new StalenessChecker
34
36
  # for checking the staleness of several stylesheets at once.
35
- def initialize
37
+ #
38
+ # @param options [{Symbol => Object}]
39
+ # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
40
+ def initialize(options)
36
41
  @dependencies = self.class.dependencies_cache
37
42
 
38
43
  # Entries in the following instance-level caches are never explicitly expired.
39
44
  # Instead they are supposed to automaticaly go out of scope when a series of staleness checks
40
45
  # (this instance of StalenessChecker was created for) is finished.
41
- @mtimes, @dependencies_stale = {}, {}
46
+ @mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
47
+ @options = Sass::Engine.normalize_options(options)
42
48
  end
43
49
 
44
50
  # Returns whether or not a given CSS file is out of date
@@ -48,9 +54,15 @@ module Sass
48
54
  # @param template_file [String] The location of the Sass or SCSS template
49
55
  # that is compiled to `css_file`.
50
56
  def stylesheet_needs_update?(css_file, template_file)
51
- template_file, css_mtime = File.expand_path(template_file), mtime(css_file)
57
+ template_file = File.expand_path(template_file)
58
+ begin
59
+ css_mtime = File.mtime(css_file).to_i
60
+ rescue Errno::ENOENT
61
+ return true
62
+ end
52
63
 
53
- css_mtime == DELETED || dependency_updated?(css_mtime).call(template_file)
64
+ dependency_updated?(css_mtime).call(
65
+ template_file, @options[:filesystem_importer].new("."))
54
66
  end
55
67
 
56
68
  # Returns whether or not a given CSS file is out of date
@@ -64,13 +76,13 @@ module Sass
64
76
  # @param template_file [String] The location of the Sass or SCSS template
65
77
  # that is compiled to `css_file`.
66
78
  def self.stylesheet_needs_update?(css_file, template_file)
67
- new.stylesheet_needs_update?(css_file, template_file)
79
+ new(Plugin.engine_options).stylesheet_needs_update?(css_file, template_file)
68
80
  end
69
81
 
70
82
  private
71
83
 
72
- def dependencies_stale?(template_file, css_mtime)
73
- timestamps = @dependencies_stale[template_file] ||= {}
84
+ def dependencies_stale?(uri, importer, css_mtime)
85
+ timestamps = @dependencies_stale[[uri, importer]] ||= {}
74
86
  timestamps.each_pair do |checked_css_mtime, is_stale|
75
87
  if checked_css_mtime <= css_mtime && !is_stale
76
88
  return false
@@ -78,45 +90,55 @@ module Sass
78
90
  return true
79
91
  end
80
92
  end
81
- timestamps[css_mtime] = dependencies(template_file).any?(&dependency_updated?(css_mtime))
93
+ timestamps[css_mtime] = dependencies(uri, importer).any?(&dependency_updated?(css_mtime))
94
+ rescue Sass::SyntaxError
95
+ # If there's an error finding dependencies, default to recompiling.
96
+ true
82
97
  end
83
98
 
84
- def mtime(filename)
85
- @mtimes[filename] ||= begin
86
- File.mtime(filename).to_i
87
- rescue Errno::ENOENT
88
- @dependencies.delete(filename)
89
- DELETED
90
- end
99
+ def mtime(uri, importer)
100
+ @mtimes[[uri, importer]] ||=
101
+ begin
102
+ mtime = importer.mtime(uri, @options)
103
+ if mtime.nil?
104
+ @dependencies.delete([uri, importer])
105
+ DELETED
106
+ else
107
+ mtime.to_i
108
+ end
109
+ end
91
110
  end
92
111
 
93
- def dependencies(filename)
94
- stored_mtime, dependencies = @dependencies[filename]
112
+ def dependencies(uri, importer)
113
+ stored_mtime, dependencies = @dependencies[[uri, importer]]
95
114
 
96
- if !stored_mtime || stored_mtime < mtime(filename)
97
- @dependencies[filename] = [mtime(filename), dependencies = compute_dependencies(filename)]
115
+ if !stored_mtime || stored_mtime < mtime(uri, importer)
116
+ dependencies = compute_dependencies(uri, importer)
117
+ @dependencies[[uri, importer]] = [mtime(uri, importer), dependencies]
98
118
  end
99
119
 
100
120
  dependencies
101
121
  end
102
122
 
103
123
  def dependency_updated?(css_mtime)
104
- lambda do |dep|
105
- begin
106
- mtime(dep) > css_mtime || dependencies_stale?(dep, css_mtime)
107
- rescue Sass::SyntaxError
108
- # If there's an error finding depenencies, default to recompiling.
109
- true
110
- end
124
+ lambda do |uri, importer|
125
+ mtime(uri, importer) > css_mtime ||
126
+ dependencies_stale?(uri, importer, css_mtime)
111
127
  end
112
128
  end
113
129
 
114
- def compute_dependencies(filename)
115
- Files.tree_for(filename, Plugin.engine_options).grep(Tree::ImportNode) do |n|
116
- File.expand_path(n.full_filename) unless n.full_filename =~ /\.css$/
130
+ def compute_dependencies(uri, importer)
131
+ tree(uri, importer).grep(Tree::ImportNode) do |n|
132
+ next if n.css_import?
133
+ file = n.imported_file
134
+ key = [file.options[:filename], file.options[:importer]]
135
+ @parse_trees[key] = file.to_tree
136
+ key
117
137
  end.compact
118
- rescue Sass::SyntaxError => e
119
- [] # If the file has an error, we assume it has no dependencies
138
+ end
139
+
140
+ def tree(uri, importer)
141
+ @parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
120
142
  end
121
143
  end
122
144
  end