sassc 2.1.0.pre1-x86-linux
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.rb +57 -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.rb +70 -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/sass_2_scss.rb +9 -0
- data/lib/sassc/script.rb +19 -0
- data/lib/sassc/script/functions.rb +8 -0
- data/lib/sassc/script/value.rb +137 -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_conversion.rb +69 -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/util.rb +231 -0
- data/lib/sassc/util/normalized_map.rb +117 -0
- data/lib/sassc/version.rb +5 -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,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,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
|
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
|