sassc 2.1.0.pre1-x86-mingw32
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +66 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +68 -0
- data/Rakefile +30 -0
- data/lib/sassc/2.3/libsass.so +0 -0
- data/lib/sassc/2.4/libsass.so +0 -0
- data/lib/sassc/2.5/libsass.so +0 -0
- data/lib/sassc/2.6/libsass.so +0 -0
- data/lib/sassc/dependency.rb +17 -0
- data/lib/sassc/engine.rb +139 -0
- data/lib/sassc/error.rb +37 -0
- data/lib/sassc/functions_handler.rb +75 -0
- data/lib/sassc/import_handler.rb +50 -0
- data/lib/sassc/importer.rb +31 -0
- data/lib/sassc/native/lib_c.rb +21 -0
- data/lib/sassc/native/native_context_api.rb +147 -0
- data/lib/sassc/native/native_functions_api.rb +164 -0
- data/lib/sassc/native/sass2scss_api.rb +10 -0
- data/lib/sassc/native/sass_input_style.rb +13 -0
- data/lib/sassc/native/sass_output_style.rb +12 -0
- data/lib/sassc/native/sass_value.rb +97 -0
- data/lib/sassc/native/string_list.rb +10 -0
- data/lib/sassc/native.rb +70 -0
- data/lib/sassc/sass_2_scss.rb +9 -0
- data/lib/sassc/script/functions.rb +8 -0
- data/lib/sassc/script/value/bool.rb +32 -0
- data/lib/sassc/script/value/color.rb +95 -0
- data/lib/sassc/script/value/list.rb +136 -0
- data/lib/sassc/script/value/map.rb +69 -0
- data/lib/sassc/script/value/number.rb +389 -0
- data/lib/sassc/script/value/string.rb +96 -0
- data/lib/sassc/script/value.rb +137 -0
- data/lib/sassc/script/value_conversion/base.rb +13 -0
- data/lib/sassc/script/value_conversion/bool.rb +13 -0
- data/lib/sassc/script/value_conversion/color.rb +18 -0
- data/lib/sassc/script/value_conversion/list.rb +25 -0
- data/lib/sassc/script/value_conversion/map.rb +21 -0
- data/lib/sassc/script/value_conversion/number.rb +13 -0
- data/lib/sassc/script/value_conversion/string.rb +17 -0
- data/lib/sassc/script/value_conversion.rb +69 -0
- data/lib/sassc/script.rb +19 -0
- data/lib/sassc/util/normalized_map.rb +117 -0
- data/lib/sassc/util.rb +231 -0
- data/lib/sassc/version.rb +5 -0
- data/lib/sassc.rb +57 -0
- data/sassc.gemspec +57 -0
- data/test/custom_importer_test.rb +127 -0
- data/test/engine_test.rb +314 -0
- data/test/error_test.rb +29 -0
- data/test/fixtures/paths.scss +10 -0
- data/test/functions_test.rb +303 -0
- data/test/native_test.rb +213 -0
- data/test/output_style_test.rb +107 -0
- data/test/sass_2_scss_test.rb +14 -0
- data/test/test_helper.rb +45 -0
- metadata +242 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The abstract superclass for SassScript objects.
|
4
|
+
# Many of these methods, especially the ones that correspond to SassScript operations,
|
5
|
+
# are designed to be overridden by subclasses which may change the semantics somewhat.
|
6
|
+
# The operations listed here are just the defaults.
|
7
|
+
|
8
|
+
class SassC::Script::Value
|
9
|
+
|
10
|
+
# Returns the pure Ruby value of the value.
|
11
|
+
# The type of this value varies based on the subclass.
|
12
|
+
attr_reader :value
|
13
|
+
|
14
|
+
# The source range in the document on which this node appeared.
|
15
|
+
attr_accessor :source_range
|
16
|
+
|
17
|
+
# Creates a new value.
|
18
|
+
def initialize(value = nil)
|
19
|
+
value.freeze unless value.nil? || value == true || value == false
|
20
|
+
@value = value
|
21
|
+
@options = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the options hash for this node,
|
25
|
+
# as well as for all child nodes.
|
26
|
+
# See the official Sass reference for options.
|
27
|
+
attr_writer :options
|
28
|
+
|
29
|
+
# Returns the options hash for this node.
|
30
|
+
# Raises SassC::SyntaxError if the value was created
|
31
|
+
# outside of the parser and \{#to\_s} was called on it
|
32
|
+
def options
|
33
|
+
return @options if @options
|
34
|
+
raise SassC::SyntaxError.new("The #options attribute is not set on this #{self.class}. This error is probably occurring because #to_s was called on this value within a custom Sass function without first setting the #options attribute.")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the hash code of this value. Two objects' hash codes should be
|
38
|
+
# equal if the objects are equal.
|
39
|
+
def hash
|
40
|
+
value.hash
|
41
|
+
end
|
42
|
+
|
43
|
+
# True if this Value is the same as `other`
|
44
|
+
def eql?(other)
|
45
|
+
self == other
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a system inspect value for this object
|
49
|
+
def inspect
|
50
|
+
value.inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns `true` (all Values are truthy)
|
54
|
+
def to_bool
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Compares this object to `other`
|
59
|
+
def ==(other)
|
60
|
+
self.class == other.class && value == other.value
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the integer value of this value.
|
64
|
+
# Raises SassC::SyntaxError if this value doesn’t implment integer conversion.
|
65
|
+
def to_i
|
66
|
+
raise SassC::SyntaxError.new("#{inspect} is not an integer.")
|
67
|
+
end
|
68
|
+
|
69
|
+
# @raise [SassC::SyntaxError] if this value isn't an integer
|
70
|
+
def assert_int!; to_i; end
|
71
|
+
|
72
|
+
# Returns the separator for this value. For non-list-like values or the
|
73
|
+
# empty list, this will be `nil`. For lists or maps, it will be `:space` or `:comma`.
|
74
|
+
def separator
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
# Whether the value is surrounded by square brackets. For non-list values,
|
79
|
+
# this will be `false`.
|
80
|
+
def bracketed
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the value of this Value as an array.
|
85
|
+
# Single Values are considered the same as single-element arrays.
|
86
|
+
def to_a
|
87
|
+
[self]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the value of this value as a hash. Most values don't have hash
|
91
|
+
# representations, but [Map]s and empty [List]s do.
|
92
|
+
#
|
93
|
+
# @return [Hash<Value, Value>] This value as a hash
|
94
|
+
# @raise [SassC::SyntaxError] if this value doesn't have a hash representation
|
95
|
+
def to_h
|
96
|
+
raise SassC::SyntaxError.new("#{inspect} is not a map.")
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the string representation of this value
|
100
|
+
# as it would be output to the CSS document.
|
101
|
+
#
|
102
|
+
# @options opts :quote [String]
|
103
|
+
# The preferred quote style for quoted strings. If `:none`, strings are
|
104
|
+
# always emitted unquoted.
|
105
|
+
# @return [String]
|
106
|
+
def to_s(opts = {})
|
107
|
+
SassC::Util.abstract(self)
|
108
|
+
end
|
109
|
+
alias_method :to_sass, :to_s
|
110
|
+
|
111
|
+
# Returns `false` (all Values are truthy)
|
112
|
+
def null?
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
# Creates a new list containing `contents` but with the same brackets and
|
117
|
+
# separators as this object, when interpreted as a list.
|
118
|
+
#
|
119
|
+
# @param contents [Array<Value>] The contents of the new list.
|
120
|
+
# @param separator [Symbol] The separator of the new list. Defaults to \{#separator}.
|
121
|
+
# @param bracketed [Boolean] Whether the new list is bracketed. Defaults to \{#bracketed}.
|
122
|
+
# @return [Sass::Script::Value::List]
|
123
|
+
def with_contents(contents, separator: self.separator, bracketed: self.bracketed)
|
124
|
+
SassC::Script::Value::List.new(contents, separator: separator, bracketed: bracketed)
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
# Evaluates the value.
|
130
|
+
#
|
131
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
132
|
+
# @return [Value] This value
|
133
|
+
def _perform(environment)
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
137
|
+
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,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
|
@@ -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
|
data/lib/sassc/script.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SassC
|
4
|
+
module Script
|
5
|
+
|
6
|
+
def self.custom_functions
|
7
|
+
Functions.instance_methods.select do |function|
|
8
|
+
Functions.public_method_defined?(function)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.formatted_function_name(function_name)
|
13
|
+
params = Functions.instance_method(function_name).parameters
|
14
|
+
params = params.map { |param_type, name| "$#{name}#{': null' if param_type == :opt}" }.join(", ")
|
15
|
+
return "#{function_name}(#{params})"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
# A hash that normalizes its string keys while still allowing you to get back
|
6
|
+
# to the original keys that were stored. If several different values normalize
|
7
|
+
# to the same value, whichever is stored last wins.
|
8
|
+
|
9
|
+
class SassC::Util::NormalizedMap
|
10
|
+
|
11
|
+
# Create a normalized map
|
12
|
+
def initialize(map = nil)
|
13
|
+
@key_strings = {}
|
14
|
+
@map = {}
|
15
|
+
map.each {|key, value| self[key] = value} if map
|
16
|
+
end
|
17
|
+
|
18
|
+
# Specifies how to transform the key.
|
19
|
+
# This can be overridden to create other normalization behaviors.
|
20
|
+
def normalize(key)
|
21
|
+
key.tr("-", "_")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the version of `key` as it was stored before
|
25
|
+
# normalization. If `key` isn't in the map, returns it as it was
|
26
|
+
# passed in.
|
27
|
+
# @return [String]
|
28
|
+
def denormalize(key)
|
29
|
+
@key_strings[normalize(key)] || key
|
30
|
+
end
|
31
|
+
|
32
|
+
# @private
|
33
|
+
def []=(k, v)
|
34
|
+
normalized = normalize(k)
|
35
|
+
@map[normalized] = v
|
36
|
+
@key_strings[normalized] = k
|
37
|
+
v
|
38
|
+
end
|
39
|
+
|
40
|
+
# @private
|
41
|
+
def [](k)
|
42
|
+
@map[normalize(k)]
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private
|
46
|
+
def has_key?(k)
|
47
|
+
@map.has_key?(normalize(k))
|
48
|
+
end
|
49
|
+
|
50
|
+
# @private
|
51
|
+
def delete(k)
|
52
|
+
normalized = normalize(k)
|
53
|
+
@key_strings.delete(normalized)
|
54
|
+
@map.delete(normalized)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Hash] Hash with the keys as they were stored (before normalization).
|
58
|
+
def as_stored
|
59
|
+
SassC::Util.map_keys(@map) {|k| @key_strings[k]}
|
60
|
+
end
|
61
|
+
|
62
|
+
def empty?
|
63
|
+
@map.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
def values
|
67
|
+
@map.values
|
68
|
+
end
|
69
|
+
|
70
|
+
def keys
|
71
|
+
@map.keys
|
72
|
+
end
|
73
|
+
|
74
|
+
def each
|
75
|
+
@map.each {|k, v| yield(k, v)}
|
76
|
+
end
|
77
|
+
|
78
|
+
def size
|
79
|
+
@map.size
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_hash
|
83
|
+
@map.dup
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_a
|
87
|
+
@map.to_a
|
88
|
+
end
|
89
|
+
|
90
|
+
def map
|
91
|
+
@map.map {|k, v| yield(k, v)}
|
92
|
+
end
|
93
|
+
|
94
|
+
def dup
|
95
|
+
d = super
|
96
|
+
d.send(:instance_variable_set, "@map", @map.dup)
|
97
|
+
d
|
98
|
+
end
|
99
|
+
|
100
|
+
def sort_by
|
101
|
+
@map.sort_by {|k, v| yield k, v}
|
102
|
+
end
|
103
|
+
|
104
|
+
def update(map)
|
105
|
+
map = map.as_stored if map.is_a?(NormalizedMap)
|
106
|
+
map.each {|k, v| self[k] = v}
|
107
|
+
end
|
108
|
+
|
109
|
+
def method_missing(method, *args, &block)
|
110
|
+
@map.send(method, *args, &block)
|
111
|
+
end
|
112
|
+
|
113
|
+
def respond_to_missing?(method, include_private = false)
|
114
|
+
@map.respond_to?(method, include_private)
|
115
|
+
end
|
116
|
+
|
117
|
+
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
|