haml-edge 3.1.73 → 3.1.74

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.
@@ -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