sassc 2.1.0.pre1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +11 -0
  5. data/CHANGELOG.md +66 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +68 -0
  10. data/Rakefile +30 -0
  11. data/lib/sassc.rb +57 -0
  12. data/lib/sassc/dependency.rb +17 -0
  13. data/lib/sassc/engine.rb +139 -0
  14. data/lib/sassc/error.rb +37 -0
  15. data/lib/sassc/functions_handler.rb +75 -0
  16. data/lib/sassc/import_handler.rb +50 -0
  17. data/lib/sassc/importer.rb +31 -0
  18. data/lib/sassc/native.rb +70 -0
  19. data/lib/sassc/native/lib_c.rb +21 -0
  20. data/lib/sassc/native/native_context_api.rb +147 -0
  21. data/lib/sassc/native/native_functions_api.rb +164 -0
  22. data/lib/sassc/native/sass2scss_api.rb +10 -0
  23. data/lib/sassc/native/sass_input_style.rb +13 -0
  24. data/lib/sassc/native/sass_output_style.rb +12 -0
  25. data/lib/sassc/native/sass_value.rb +97 -0
  26. data/lib/sassc/native/string_list.rb +10 -0
  27. data/lib/sassc/sass_2_scss.rb +9 -0
  28. data/lib/sassc/script.rb +19 -0
  29. data/lib/sassc/script/functions.rb +8 -0
  30. data/lib/sassc/script/value.rb +137 -0
  31. data/lib/sassc/script/value/bool.rb +32 -0
  32. data/lib/sassc/script/value/color.rb +95 -0
  33. data/lib/sassc/script/value/list.rb +136 -0
  34. data/lib/sassc/script/value/map.rb +69 -0
  35. data/lib/sassc/script/value/number.rb +389 -0
  36. data/lib/sassc/script/value/string.rb +96 -0
  37. data/lib/sassc/script/value_conversion.rb +69 -0
  38. data/lib/sassc/script/value_conversion/base.rb +13 -0
  39. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  40. data/lib/sassc/script/value_conversion/color.rb +18 -0
  41. data/lib/sassc/script/value_conversion/list.rb +25 -0
  42. data/lib/sassc/script/value_conversion/map.rb +21 -0
  43. data/lib/sassc/script/value_conversion/number.rb +13 -0
  44. data/lib/sassc/script/value_conversion/string.rb +17 -0
  45. data/lib/sassc/util.rb +231 -0
  46. data/lib/sassc/util/normalized_map.rb +117 -0
  47. data/lib/sassc/version.rb +5 -0
  48. data/sassc.gemspec +57 -0
  49. data/test/custom_importer_test.rb +127 -0
  50. data/test/engine_test.rb +314 -0
  51. data/test/error_test.rb +29 -0
  52. data/test/fixtures/paths.scss +10 -0
  53. data/test/functions_test.rb +303 -0
  54. data/test/native_test.rb +213 -0
  55. data/test/output_style_test.rb +107 -0
  56. data/test/sass_2_scss_test.rb +14 -0
  57. data/test/test_helper.rb +45 -0
  58. metadata +242 -0
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SassC::Script::Value::String < SassC::Script::Value
4
+
5
+ # The Ruby value of the string.
6
+ attr_reader :value
7
+
8
+ # Whether this is a CSS string or a CSS identifier.
9
+ # The difference is that strings are written with double-quotes,
10
+ # while identifiers aren't.
11
+ #
12
+ # @return [Symbol] `:string` or `:identifier`
13
+ attr_reader :type
14
+
15
+ # Returns the quoted string representation of `contents`.
16
+ #
17
+ # @options opts :quote [String]
18
+ # The preferred quote style for quoted strings. If `:none`, strings are
19
+ # always emitted unquoted. If `nil`, quoting is determined automatically.
20
+ # @options opts :sass [String]
21
+ # Whether to quote strings for Sass source, as opposed to CSS. Defaults to `false`.
22
+ def self.quote(contents, opts = {})
23
+ quote = opts[:quote]
24
+
25
+ # Short-circuit if there are no characters that need quoting.
26
+ unless contents =~ /[\n\\"']|\#\{/
27
+ quote ||= '"'
28
+ return "#{quote}#{contents}#{quote}"
29
+ end
30
+
31
+ if quote.nil?
32
+ if contents.include?('"')
33
+ if contents.include?("'")
34
+ quote = '"'
35
+ else
36
+ quote = "'"
37
+ end
38
+ else
39
+ quote = '"'
40
+ end
41
+ end
42
+
43
+ # Replace single backslashes with multiples.
44
+ contents = contents.gsub("\\", "\\\\\\\\")
45
+
46
+ # Escape interpolation.
47
+ contents = contents.gsub('#{', "\\\#{") if opts[:sass]
48
+
49
+ if quote == '"'
50
+ contents = contents.gsub('"', "\\\"")
51
+ else
52
+ contents = contents.gsub("'", "\\'")
53
+ end
54
+
55
+ contents = contents.gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
56
+ "#{quote}#{contents}#{quote}"
57
+ end
58
+
59
+ # Creates a new string.
60
+ #
61
+ # @param value [String] See \{#value}
62
+ # @param type [Symbol] See \{#type}
63
+ # @param deprecated_interp_equivalent [String?]
64
+ # If this was created via a potentially-deprecated string interpolation,
65
+ # this is the replacement expression that should be suggested to the user.
66
+ def initialize(value, type = :identifier)
67
+ super(value)
68
+ @type = type
69
+ end
70
+
71
+ # @see Value#plus
72
+ def plus(other)
73
+ if other.is_a?(SassC::Script::Value::String)
74
+ other_value = other.value
75
+ else
76
+ other_value = other.to_s(:quote => :none)
77
+ end
78
+ SassC::Script::Value::String.new(value + other_value, type)
79
+ end
80
+
81
+ # @see Value#to_s
82
+ def to_s(opts = {})
83
+ return @value.gsub(/\n\s*/, ' ') if opts[:quote] == :none || @type == :identifier
84
+ self.class.quote(value, opts)
85
+ end
86
+
87
+ # @see Value#to_sass
88
+ def to_sass(opts = {})
89
+ to_s(opts.merge(:sass => true))
90
+ end
91
+
92
+ def inspect
93
+ String.quote(value)
94
+ end
95
+
96
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC::Script::ValueConversion
4
+
5
+ def self.from_native(native_value, options)
6
+ case value_tag = SassC::Native.value_get_tag(native_value)
7
+ when :sass_null
8
+ # no-op
9
+ when :sass_string
10
+ value = SassC::Native.string_get_value(native_value)
11
+ type = SassC::Native.string_get_type(native_value)
12
+ argument = SassC::Script::Value::String.new(value, type)
13
+ argument
14
+ when :sass_boolean
15
+ value = SassC::Native.boolean_get_value(native_value)
16
+ argument = SassC::Script::Value::Bool.new(value)
17
+ argument
18
+ when :sass_number
19
+ value = SassC::Native.number_get_value(native_value)
20
+ unit = SassC::Native.number_get_unit(native_value)
21
+ argument = SassC::Script::Value::Number.new(value, unit)
22
+ argument
23
+ when :sass_color
24
+ red, green, blue, alpha = SassC::Native.color_get_r(native_value), SassC::Native.color_get_g(native_value), SassC::Native.color_get_b(native_value), SassC::Native.color_get_a(native_value)
25
+ argument = SassC::Script::Value::Color.new(red:red, green:green, blue:blue, alpha:alpha)
26
+ argument.options = options
27
+ argument
28
+ when :sass_map
29
+ values = {}
30
+ length = SassC::Native::map_get_length native_value
31
+ (0..length-1).each do |index|
32
+ key = SassC::Native::map_get_key(native_value, index)
33
+ value = SassC::Native::map_get_value(native_value, index)
34
+ values[from_native(key, options)] = from_native(value, options)
35
+ end
36
+ argument = SassC::Script::Value::Map.new values
37
+ argument
38
+ when :sass_list
39
+ length = SassC::Native::list_get_length(native_value)
40
+ items = (0...length).map do |index|
41
+ native_item = SassC::Native::list_get_value(native_value, index)
42
+ from_native(native_item, options)
43
+ end
44
+ SassC::Script::Value::List.new(items, separator: :space)
45
+ else
46
+ raise UnsupportedValue.new("Sass argument of type #{value_tag} unsupported")
47
+ end
48
+ end
49
+
50
+ def self.to_native(value)
51
+ case value_name = value.class.name.split("::").last
52
+ when "String"
53
+ SassC::Script::ValueConversion::String.new(value).to_native
54
+ when "Color"
55
+ SassC::Script::ValueConversion::Color.new(value).to_native
56
+ when "Number"
57
+ SassC::Script::ValueConversion::Number.new(value).to_native
58
+ when "Map"
59
+ SassC::Script::ValueConversion::Map.new(value).to_native
60
+ when "List"
61
+ SassC::Script::ValueConversion::List.new(value).to_native
62
+ when "Bool"
63
+ SassC::Script::ValueConversion::Bool.new(value).to_native
64
+ else
65
+ raise SassC::UnsupportedValue.new("Sass return type #{value_name} unsupported")
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class Base
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class Bool < Base
7
+ def to_native
8
+ Native::make_boolean(@value.value)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class Color < Base
7
+ def to_native
8
+ Native::make_color(
9
+ @value.red,
10
+ @value.green,
11
+ @value.blue,
12
+ @value.alpha
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ SEPARATORS = {
7
+ space: :sass_space,
8
+ comma: :sass_comma
9
+ }
10
+
11
+ class List < Base
12
+ def to_native
13
+ list = @value.to_a
14
+ sep = SEPARATORS.fetch(@value.separator)
15
+ native_list = Native::make_list(list.size, sep)
16
+ list.each_with_index do |item, index|
17
+ native_item = ValueConversion.to_native(item)
18
+ Native::list_set_value(native_list, index, native_item)
19
+ end
20
+ native_list
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class Map < Base
7
+ def to_native
8
+ hash = @value.to_h
9
+ native_map = Native::make_map( hash.size )
10
+ hash.each_with_index do |(key, value), index|
11
+ key = ValueConversion.to_native key
12
+ value = ValueConversion.to_native value
13
+ Native::map_set_key( native_map, index, key )
14
+ Native::map_set_value( native_map, index, value )
15
+ end
16
+ return native_map
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class Number < Base
7
+ def to_native
8
+ Native::make_number(@value.value, @value.numerator_units.first)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Script
5
+ module ValueConversion
6
+ class String < Base
7
+ def to_native(opts = {})
8
+ if opts[:quote] == :none || @value.type == :identifier
9
+ Native::make_string(@value.to_s)
10
+ else
11
+ Native::make_qstring(@value.to_s)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/sassc/util.rb ADDED
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "set"
5
+ require "enumerator"
6
+ require "stringio"
7
+ require "rbconfig"
8
+ require "uri"
9
+ require "thread"
10
+ require "pathname"
11
+
12
+ # A module containing various useful functions.
13
+
14
+ module SassC::Util
15
+
16
+ extend self
17
+
18
+ # An array of ints representing the Ruby version number.
19
+ # @api public
20
+ RUBY_VERSION_COMPONENTS = RUBY_VERSION.split(".").map {|s| s.to_i}
21
+
22
+ # The Ruby engine we're running under. Defaults to `"ruby"`
23
+ # if the top-level constant is undefined.
24
+ # @api public
25
+ RUBY_ENGINE = defined?(::RUBY_ENGINE) ? ::RUBY_ENGINE : "ruby"
26
+
27
+ # Maps the keys in a hash according to a block.
28
+ # @example
29
+ # map_keys({:foo => "bar", :baz => "bang"}) {|k| k.to_s}
30
+ # #=> {"foo" => "bar", "baz" => "bang"}
31
+ # @param hash [Hash] The hash to map
32
+ # @yield [key] A block in which the keys are transformed
33
+ # @yieldparam key [Object] The key that should be mapped
34
+ # @yieldreturn [Object] The new value for the key
35
+ # @return [Hash] The mapped hash
36
+ # @see #map_vals
37
+ # @see #map_hash
38
+ def map_keys(hash)
39
+ map_hash(hash) {|k, v| [yield(k), v]}
40
+ end
41
+
42
+ # Restricts the numeric `value` to be within `min` and `max`, inclusive.
43
+ # If the value is lower than `min`
44
+ def clamp(value, min, max)
45
+ return min if value < min
46
+ return max if value > max
47
+ return value
48
+ end
49
+
50
+ # Like [Fixnum.round], but leaves rooms for slight floating-point
51
+ # differences.
52
+ #
53
+ # @param value [Numeric]
54
+ # @return [Numeric]
55
+ def round(value)
56
+ # If the number is within epsilon of X.5, round up (or down for negative
57
+ # numbers).
58
+ mod = value % 1
59
+ mod_is_half = (mod - 0.5).abs < SassC::Script::Value::Number.epsilon
60
+ if value > 0
61
+ !mod_is_half && mod < 0.5 ? value.floor : value.ceil
62
+ else
63
+ mod_is_half || mod < 0.5 ? value.floor : value.ceil
64
+ end
65
+ end
66
+
67
+ # Return an array of all possible paths through the given arrays.
68
+ #
69
+ # @param arrs [Array<Array>]
70
+ # @return [Array<Arrays>]
71
+ #
72
+ # @example
73
+ # paths([[1, 2], [3, 4], [5]]) #=>
74
+ # # [[1, 3, 5],
75
+ # # [2, 3, 5],
76
+ # # [1, 4, 5],
77
+ # # [2, 4, 5]]
78
+ def paths(arrs)
79
+ arrs.inject([[]]) do |paths, arr|
80
+ arr.map {|e| paths.map {|path| path + [e]}}.flatten(1)
81
+ end
82
+ end
83
+
84
+ # Returns information about the caller of the previous method.
85
+ #
86
+ # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
87
+ # @return [[String, Integer, (String, nil)]]
88
+ # An array containing the filename, line, and method name of the caller.
89
+ # The method name may be nil
90
+ def caller_info(entry = nil)
91
+ # JRuby evaluates `caller` incorrectly when it's in an actual default argument.
92
+ entry ||= caller[1]
93
+ info = entry.scan(/^((?:[A-Za-z]:)?.*?):(-?.*?)(?::.*`(.+)')?$/).first
94
+ info[1] = info[1].to_i
95
+ # This is added by Rubinius to designate a block, but we don't care about it.
96
+ info[2].sub!(/ \{\}\Z/, '') if info[2]
97
+ info
98
+ end
99
+
100
+ # Throws a NotImplementedError for an abstract method.
101
+ #
102
+ # @param obj [Object] `self`
103
+ # @raise [NotImplementedError]
104
+ def abstract(obj)
105
+ raise NotImplementedError.new("#{obj.class} must implement ##{caller_info[2]}")
106
+ end
107
+
108
+ # Prints a deprecation warning for the caller method.
109
+ #
110
+ # @param obj [Object] `self`
111
+ # @param message [String] A message describing what to do instead.
112
+ def deprecated(obj, message = nil)
113
+ obj_class = obj.is_a?(Class) ? "#{obj}." : "#{obj.class}#"
114
+ full_message = "DEPRECATION WARNING: #{obj_class}#{caller_info[2]} " +
115
+ "will be removed in a future version of Sass.#{("\n" + message) if message}"
116
+ SassC::Util.sass_warn full_message
117
+ end
118
+
119
+ # Silences all Sass warnings within a block.
120
+ #
121
+ # @yield A block in which no Sass warnings will be printed
122
+ def silence_sass_warnings
123
+ old_level, Sass.logger.log_level = Sass.logger.log_level, :error
124
+ yield
125
+ ensure
126
+ SassC.logger.log_level = old_level
127
+ end
128
+
129
+ # The same as `Kernel#warn`, but is silenced by \{#silence\_sass\_warnings}.
130
+ #
131
+ # @param msg [String]
132
+ def sass_warn(msg)
133
+ Sass.logger.warn("#{msg}\n")
134
+ end
135
+
136
+ ## Cross Rails Version Compatibility
137
+
138
+ # Returns the root of the Rails application,
139
+ # if this is running in a Rails context.
140
+ # Returns `nil` if no such root is defined.
141
+ #
142
+ # @return [String, nil]
143
+ def rails_root
144
+ if defined?(::Rails.root)
145
+ return ::Rails.root.to_s if ::Rails.root
146
+ raise "ERROR: Rails.root is nil!"
147
+ end
148
+ return RAILS_ROOT.to_s if defined?(RAILS_ROOT)
149
+ nil
150
+ end
151
+
152
+ # Returns the environment of the Rails application,
153
+ # if this is running in a Rails context.
154
+ # Returns `nil` if no such environment is defined.
155
+ #
156
+ # @return [String, nil]
157
+ def rails_env
158
+ return ::Rails.env.to_s if defined?(::Rails.env)
159
+ return RAILS_ENV.to_s if defined?(RAILS_ENV)
160
+ nil
161
+ end
162
+
163
+ ## Cross-OS Compatibility
164
+ #
165
+ # These methods are cached because some of them are called quite frequently
166
+ # and even basic checks like String#== are too costly to be called repeatedly.
167
+
168
+ # Whether or not this is running on Windows.
169
+ #
170
+ # @return [Boolean]
171
+ def windows?
172
+ return @windows if defined?(@windows)
173
+ @windows = (RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i)
174
+ end
175
+
176
+ # Whether or not this is running on IronRuby.
177
+ #
178
+ # @return [Boolean]
179
+ def ironruby?
180
+ return @ironruby if defined?(@ironruby)
181
+ @ironruby = RUBY_ENGINE == "ironruby"
182
+ end
183
+
184
+ # Whether or not this is running on Rubinius.
185
+ #
186
+ # @return [Boolean]
187
+ def rbx?
188
+ return @rbx if defined?(@rbx)
189
+ @rbx = RUBY_ENGINE == "rbx"
190
+ end
191
+
192
+ # Whether or not this is running on JRuby.
193
+ #
194
+ # @return [Boolean]
195
+ def jruby?
196
+ return @jruby if defined?(@jruby)
197
+ @jruby = RUBY_PLATFORM =~ /java/
198
+ end
199
+
200
+ # Returns an array of ints representing the JRuby version number.
201
+ #
202
+ # @return [Array<Integer>]
203
+ def jruby_version
204
+ @jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
205
+ end
206
+
207
+ # Returns `path` relative to `from`.
208
+ #
209
+ # This is like `Pathname#relative_path_from` except it accepts both strings
210
+ # and pathnames, it handles Windows path separators correctly, and it throws
211
+ # an error rather than crashing if the paths use different encodings
212
+ # (https://github.com/ruby/ruby/pull/713).
213
+ #
214
+ # @param path [String, Pathname]
215
+ # @param from [String, Pathname]
216
+ # @return [Pathname?]
217
+ def relative_path_from(path, from)
218
+ pathname(path.to_s).relative_path_from(pathname(from.to_s))
219
+ rescue NoMethodError => e
220
+ raise e unless e.name == :zero?
221
+
222
+ # Work around https://github.com/ruby/ruby/pull/713.
223
+ path = path.to_s
224
+ from = from.to_s
225
+ raise ArgumentError("Incompatible path encodings: #{path.inspect} is #{path.encoding}, " +
226
+ "#{from.inspect} is #{from.encoding}")
227
+ end
228
+
229
+ singleton_methods.each {|method| module_function method}
230
+
231
+ end