libpath-ruby 0.2.1
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/README.md +61 -0
- data/examples/path_from_arg0.md +99 -0
- data/examples/path_from_arg0.rb +55 -0
- data/lib/libpath.rb +12 -0
- data/lib/libpath/constants.rb +42 -0
- data/lib/libpath/constants/unix.rb +146 -0
- data/lib/libpath/constants/windows.rb +147 -0
- data/lib/libpath/diagnostics.rb +6 -0
- data/lib/libpath/diagnostics/parameter_checking.rb +46 -0
- data/lib/libpath/exceptions.rb +7 -0
- data/lib/libpath/exceptions/libpath_base_exception.rb +77 -0
- data/lib/libpath/exceptions/malformed_name_exception.rb +85 -0
- data/lib/libpath/form.rb +42 -0
- data/lib/libpath/form/unix.rb +215 -0
- data/lib/libpath/form/windows.rb +358 -0
- data/lib/libpath/internal_/array.rb +96 -0
- data/lib/libpath/internal_/platform.rb +53 -0
- data/lib/libpath/internal_/string.rb +33 -0
- data/lib/libpath/internal_/unix/form.rb +160 -0
- data/lib/libpath/internal_/windows/drive.rb +84 -0
- data/lib/libpath/internal_/windows/form.rb +281 -0
- data/lib/libpath/libpath.rb +6 -0
- data/lib/libpath/path.rb +43 -0
- data/lib/libpath/path/unix.rb +170 -0
- data/lib/libpath/path/windows.rb +176 -0
- data/lib/libpath/util.rb +42 -0
- data/lib/libpath/util/unix.rb +414 -0
- data/lib/libpath/util/windows.rb +636 -0
- data/lib/libpath/version.rb +73 -0
- data/test/performance/benchmark_drive_letter.rb +31 -0
- data/test/performance/benchmark_gsub_string_or_regex.rb +45 -0
- data/test/performance/benchmark_rindex2.rb +109 -0
- data/test/performance/benchmark_split.rb +32 -0
- data/test/unit/compare/ts_all.rb +22 -0
- data/test/unit/equate/ts_all.rb +22 -0
- data/test/unit/equate/unix/ts_all.rb +22 -0
- data/test/unit/equate/windows/ts_all.rb +22 -0
- data/test/unit/exceptions/tc_libpath_base_exception.rb +27 -0
- data/test/unit/exceptions/tc_malformed_name_exception.rb +31 -0
- data/test/unit/exceptions/ts_all.rb +22 -0
- data/test/unit/form/tc_absolute_functions.rb +369 -0
- data/test/unit/form/ts_all.rb +22 -0
- data/test/unit/form/unix/tc_absolute_functions.rb +269 -0
- data/test/unit/form/unix/ts_all.rb +22 -0
- data/test/unit/form/windows/tc_absolute_functions.rb +854 -0
- data/test/unit/form/windows/ts_all.rb +22 -0
- data/test/unit/internal_/tc_array.rb +62 -0
- data/test/unit/internal_/ts_all.rb +22 -0
- data/test/unit/internal_/unix/form/tc_slash_functions.rb +60 -0
- data/test/unit/internal_/unix/form/ts_all.rb +22 -0
- data/test/unit/internal_/unix/tc_split_path.rb +396 -0
- data/test/unit/internal_/unix/ts_all.rb +22 -0
- data/test/unit/internal_/windows/form/tc_get_windows_volume.rb +220 -0
- data/test/unit/internal_/windows/form/tc_slash_functions.rb +61 -0
- data/test/unit/internal_/windows/form/ts_all.rb +22 -0
- data/test/unit/internal_/windows/tc_split_path.rb +881 -0
- data/test/unit/internal_/windows/ts_all.rb +22 -0
- data/test/unit/parse/ts_all.rb +22 -0
- data/test/unit/path/tc_path.rb +778 -0
- data/test/unit/path/ts_all.rb +22 -0
- data/test/unit/path/unix/tc_path.rb +565 -0
- data/test/unit/path/unix/ts_all.rb +22 -0
- data/test/unit/path/windows/tc_path.rb +630 -0
- data/test/unit/path/windows/ts_all.rb +22 -0
- data/test/unit/tc_version.rb +47 -0
- data/test/unit/ts_all.rb +22 -0
- data/test/unit/util/tc_combine_paths.rb +179 -0
- data/test/unit/util/tc_derive_relative_path.rb +19 -0
- data/test/unit/util/tc_make_path_canonical.rb +228 -0
- data/test/unit/util/ts_all.rb +22 -0
- data/test/unit/util/unix/tc_combine_paths.rb +65 -0
- data/test/unit/util/unix/tc_derive_relative_path.rb +123 -0
- data/test/unit/util/unix/tc_make_path_absolute.rb +117 -0
- data/test/unit/util/unix/tc_make_path_canonical.rb +139 -0
- data/test/unit/util/unix/ts_all.rb +22 -0
- data/test/unit/util/windows/tc_combine_paths.rb +131 -0
- data/test/unit/util/windows/tc_derive_relative_path.rb +155 -0
- data/test/unit/util/windows/tc_make_path_absolute.rb +163 -0
- data/test/unit/util/windows/tc_make_path_canonical.rb +220 -0
- data/test/unit/util/windows/ts_all.rb +22 -0
- metadata +144 -0
@@ -0,0 +1,636 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: libpath/util/windows.rb
|
4
|
+
#
|
5
|
+
# Purpose: LibPath::Util::Windows module
|
6
|
+
#
|
7
|
+
# Created: 10th January 2019
|
8
|
+
# Updated: 16th April 2019
|
9
|
+
#
|
10
|
+
# Home: http://github.com/synesissoftware/libpath.Ruby
|
11
|
+
#
|
12
|
+
# Author: Matthew Wilson
|
13
|
+
#
|
14
|
+
# Copyright (c) 2019, Matthew Wilson and Synesis Software
|
15
|
+
# All rights reserved.
|
16
|
+
#
|
17
|
+
# Redistribution and use in source and binary forms, with or without
|
18
|
+
# modification, are permitted provided that the following conditions are
|
19
|
+
# met:
|
20
|
+
#
|
21
|
+
# * Redistributions of source code must retain the above copyright
|
22
|
+
# notice, this list of conditions and the following disclaimer.
|
23
|
+
#
|
24
|
+
# * Redistributions in binary form must reproduce the above copyright
|
25
|
+
# notice, this list of conditions and the following disclaimer in the
|
26
|
+
# documentation and/or other materials provided with the distribution.
|
27
|
+
#
|
28
|
+
# * Neither the names of the copyright holder nor the names of its
|
29
|
+
# contributors may be used to endorse or promote products derived from
|
30
|
+
# this software without specific prior written permission.
|
31
|
+
#
|
32
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
33
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
34
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
35
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
36
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
37
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
38
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
39
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
40
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
41
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
42
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
43
|
+
#
|
44
|
+
# ######################################################################## #
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
=begin
|
49
|
+
=end
|
50
|
+
|
51
|
+
|
52
|
+
require 'libpath/diagnostics'
|
53
|
+
require 'libpath/form/windows'
|
54
|
+
require 'libpath/internal_/array'
|
55
|
+
require 'libpath/internal_/windows/form'
|
56
|
+
|
57
|
+
module LibPath # :nodoc:
|
58
|
+
module Util # :nodoc:
|
59
|
+
module Windows # :nodoc:
|
60
|
+
|
61
|
+
# Module defining instance functions that will be included and extended into
|
62
|
+
# any class or module including/extending module LibPath::Util::Windows
|
63
|
+
module LibPath_Util_Windows_Methods
|
64
|
+
|
65
|
+
# Combines a number of path parts into a single path, ignoring any parts
|
66
|
+
# that are preceded by an absolute part
|
67
|
+
#
|
68
|
+
# Because Windows paths' absolute nature comprises two elements - the
|
69
|
+
# volume(/drive) and the root directory - it is possible to combine
|
70
|
+
# elements where either the volume or the root directory is missing.
|
71
|
+
#
|
72
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
73
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
74
|
+
def combine_paths *args, **options
|
75
|
+
|
76
|
+
_Form_Windows = Form::Windows
|
77
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
78
|
+
|
79
|
+
args.each_with_index { |arg, index| Diagnostics.check_string_parameter(arg, "arg#{index}", allow_nil: true) } if $DEBUG
|
80
|
+
|
81
|
+
first = []
|
82
|
+
dirs = []
|
83
|
+
last = []
|
84
|
+
|
85
|
+
if options[:elide_single_dots]
|
86
|
+
|
87
|
+
args = args.map do |arg|
|
88
|
+
|
89
|
+
case arg
|
90
|
+
when '.', './'
|
91
|
+
|
92
|
+
nil
|
93
|
+
else
|
94
|
+
|
95
|
+
arg
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
args = args.reject { |arg| arg.nil? || arg.empty? }
|
101
|
+
|
102
|
+
rix_abs = nil
|
103
|
+
rix_drv = nil
|
104
|
+
rix_dir = nil
|
105
|
+
|
106
|
+
args.each_with_index do |arg, index|
|
107
|
+
|
108
|
+
vol, rem, _ = _Internal_Windows_Form.get_windows_volume arg
|
109
|
+
|
110
|
+
rem = nil unless rem && _Internal_Windows_Form.char_is_path_name_separator?(rem[0])
|
111
|
+
|
112
|
+
if vol
|
113
|
+
|
114
|
+
if rem
|
115
|
+
|
116
|
+
rix_abs = index
|
117
|
+
else
|
118
|
+
|
119
|
+
rix_drv = index
|
120
|
+
end
|
121
|
+
elsif rem
|
122
|
+
|
123
|
+
rix_dir = index
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
rix_drv = nil if (rix_drv || -1) <= (rix_abs || -1)
|
128
|
+
rix_dir = nil if (rix_dir || -1) <= (rix_abs || -1)
|
129
|
+
|
130
|
+
if rix_drv && rix_dir && rix_abs
|
131
|
+
|
132
|
+
if rix_abs < rix_drv && rix_abs < rix_dir
|
133
|
+
|
134
|
+
rix_abs += 1
|
135
|
+
args = args[rix_abs..-1]
|
136
|
+
rix_drv -= rix_abs
|
137
|
+
rix_dir -= rix_abs
|
138
|
+
rix_abs = nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
if rix_drv.nil? && rix_dir.nil?
|
143
|
+
|
144
|
+
if rix_abs
|
145
|
+
|
146
|
+
args = args[rix_abs..-1]
|
147
|
+
end
|
148
|
+
|
149
|
+
dirs = args
|
150
|
+
last << args.pop unless args.empty?
|
151
|
+
else
|
152
|
+
|
153
|
+
if false
|
154
|
+
|
155
|
+
;
|
156
|
+
elsif rix_drv
|
157
|
+
|
158
|
+
if rix_dir
|
159
|
+
|
160
|
+
drv = args.delete_at rix_drv
|
161
|
+
rix_dir -= 1 if rix_drv < rix_dir
|
162
|
+
dir = args.delete_at rix_dir
|
163
|
+
|
164
|
+
args = args[rix_dir..-1]
|
165
|
+
|
166
|
+
if dir.size > 1
|
167
|
+
|
168
|
+
args.unshift dir[1..-1]
|
169
|
+
dir = dir[0]
|
170
|
+
end
|
171
|
+
|
172
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{drv}#{dir}")
|
173
|
+
|
174
|
+
first << root
|
175
|
+
last << args.pop unless args.empty?
|
176
|
+
dirs = args
|
177
|
+
elsif rix_abs
|
178
|
+
|
179
|
+
drv = args.delete_at rix_drv
|
180
|
+
rix_abs -= 1 if rix_drv < rix_abs
|
181
|
+
abs = args.delete_at rix_abs
|
182
|
+
|
183
|
+
_, _, dir, bas, _, _, _, _ = _Internal_Windows_Form.split_path abs
|
184
|
+
|
185
|
+
args = args[rix_abs..-1]
|
186
|
+
|
187
|
+
if dir.size > 1
|
188
|
+
|
189
|
+
args.unshift dir[1..-1]
|
190
|
+
dir = dir[0]
|
191
|
+
end
|
192
|
+
|
193
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{drv}#{dir}#{bas}")
|
194
|
+
|
195
|
+
first << root
|
196
|
+
last << args.pop unless args.empty?
|
197
|
+
dirs = args
|
198
|
+
else
|
199
|
+
|
200
|
+
first << args.delete_at(rix_drv)
|
201
|
+
last << args.pop unless args.empty?
|
202
|
+
dirs = args
|
203
|
+
end
|
204
|
+
elsif rix_dir
|
205
|
+
|
206
|
+
if rix_abs
|
207
|
+
|
208
|
+
abs = args.delete_at rix_abs
|
209
|
+
rix_dir -= 1 if rix_abs < rix_dir
|
210
|
+
dir = args.delete_at rix_dir
|
211
|
+
|
212
|
+
_, vol, _, _, _, _, _, _ = _Internal_Windows_Form.split_path abs
|
213
|
+
|
214
|
+
args = args[rix_dir..-1]
|
215
|
+
|
216
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{vol}#{dir}")
|
217
|
+
|
218
|
+
first << root
|
219
|
+
last << args.pop unless args.empty?
|
220
|
+
dirs = args
|
221
|
+
else
|
222
|
+
|
223
|
+
args = args[rix_dir..-1]
|
224
|
+
last << args.pop unless args.empty?
|
225
|
+
dirs = args
|
226
|
+
end
|
227
|
+
else
|
228
|
+
|
229
|
+
;
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
dirs = dirs.map { |el| _Internal_Windows_Form.append_trailing_slash el }
|
234
|
+
|
235
|
+
(first + dirs + last).join('')
|
236
|
+
end
|
237
|
+
|
238
|
+
# Obtains the form of the given +path+ relative to the given +origin+
|
239
|
+
#
|
240
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
241
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
242
|
+
#
|
243
|
+
#
|
244
|
+
# === Signature
|
245
|
+
#
|
246
|
+
# * *Options:*
|
247
|
+
# +:home+:: (String)
|
248
|
+
# +:locator+:: (boolean)
|
249
|
+
# +:make_canonical+:: (boolean)
|
250
|
+
# +:pwd+:: (String)
|
251
|
+
def derive_relative_path origin, path, **options
|
252
|
+
|
253
|
+
return path if origin.nil? || origin.empty?
|
254
|
+
return path if path.nil? || path.empty?
|
255
|
+
|
256
|
+
_Form_Windows = Form::Windows
|
257
|
+
_Util_Windows = Util::Windows
|
258
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
259
|
+
|
260
|
+
_MPA_COMMON_OPTIONS = %i{ home locator pwd }
|
261
|
+
|
262
|
+
tr_sl = _Internal_Windows_Form.get_trailing_slash(path)
|
263
|
+
|
264
|
+
# Possibly naive home-correction
|
265
|
+
|
266
|
+
return derive_relative_path(absolute_path(origin), path, **options) if _Form_Windows.path_is_homed?(origin)
|
267
|
+
return derive_relative_path(origin, absolute_path(path), **options) if _Form_Windows.path_is_homed?(path)
|
268
|
+
|
269
|
+
|
270
|
+
o_vol, o_rem, _ = _Internal_Windows_Form.get_windows_volume origin
|
271
|
+
p_vol, p_rem, _ = _Internal_Windows_Form.get_windows_volume path
|
272
|
+
|
273
|
+
if o_vol && p_vol
|
274
|
+
|
275
|
+
# always give absolute answer when 'volume's are different
|
276
|
+
|
277
|
+
if o_vol != p_vol
|
278
|
+
|
279
|
+
if options[:make_path_canonical]
|
280
|
+
|
281
|
+
path = _Util_Windows.make_path_canonical(path, make_slashes_canonical: true)
|
282
|
+
else
|
283
|
+
|
284
|
+
path = path.tr('/', '\\')
|
285
|
+
end
|
286
|
+
|
287
|
+
return path
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
o_is_rooted = o_rem && _Internal_Windows_Form.char_is_path_name_separator?(o_rem[0])
|
293
|
+
p_is_rooted = p_rem && _Internal_Windows_Form.char_is_path_name_separator?(p_rem[0])
|
294
|
+
|
295
|
+
o_is_abs = o_vol && o_is_rooted
|
296
|
+
p_is_abs = p_vol && p_is_rooted
|
297
|
+
|
298
|
+
mpa_opts = options.select { |k| _MPA_COMMON_OPTIONS.include?(k) }
|
299
|
+
|
300
|
+
if o_is_abs != p_is_abs || o_is_rooted != p_is_rooted
|
301
|
+
|
302
|
+
origin = _Util_Windows.make_path_absolute(origin, **mpa_opts) unless o_is_abs
|
303
|
+
path = _Util_Windows.make_path_absolute(path, **mpa_opts) unless p_is_abs
|
304
|
+
|
305
|
+
return derive_relative_path(origin, path, **options)
|
306
|
+
end
|
307
|
+
|
308
|
+
origin = _Util_Windows.make_path_canonical(origin, make_slashes_canonical: true)
|
309
|
+
path = _Util_Windows.make_path_canonical(path, make_slashes_canonical: true)
|
310
|
+
|
311
|
+
return '.' + tr_sl.to_s if origin == path
|
312
|
+
return path if '.\\' == origin
|
313
|
+
|
314
|
+
if o_is_abs != p_is_abs || '.\\' == path
|
315
|
+
|
316
|
+
origin = _Util_Windows.make_path_absolute(origin, make_canonical: true, **options.select { |k| _MPA_COMMON_OPTIONS.include?(k) })
|
317
|
+
path = _Util_Windows.make_path_absolute(path, make_canonical: true, **options.select { |k| _MPA_COMMON_OPTIONS.include?(k) })
|
318
|
+
end
|
319
|
+
|
320
|
+
|
321
|
+
_, _, _, o3_basename, _, _, o6_parts, _ = _Internal_Windows_Form.split_path(origin)
|
322
|
+
_, _, _, p3_basename, _, _, p6_parts, _ = _Internal_Windows_Form.split_path(path)
|
323
|
+
|
324
|
+
o_parts = o6_parts
|
325
|
+
o_parts << o3_basename if o3_basename && '.' != o3_basename
|
326
|
+
|
327
|
+
p_parts = p6_parts
|
328
|
+
p_parts << p3_basename if p3_basename && '.' != p3_basename
|
329
|
+
|
330
|
+
|
331
|
+
while true
|
332
|
+
|
333
|
+
break if o_parts.empty?
|
334
|
+
break if p_parts.empty?
|
335
|
+
|
336
|
+
o_part = o_parts[0]
|
337
|
+
p_part = p_parts[0]
|
338
|
+
|
339
|
+
if 1 == o_parts.size || 1 == p_parts.size
|
340
|
+
|
341
|
+
o_part = _Internal_Windows_Form.append_trailing_slash o_part
|
342
|
+
p_part = _Internal_Windows_Form.append_trailing_slash p_part
|
343
|
+
end
|
344
|
+
|
345
|
+
parts_equal = false
|
346
|
+
|
347
|
+
if o_part.size == p_part.size
|
348
|
+
|
349
|
+
o_part = o_part.tr('/', '\\') if o_part.include? '/'
|
350
|
+
p_part = p_part.tr('/', '\\') if p_part.include? '/'
|
351
|
+
|
352
|
+
parts_equal = o_part == p_part
|
353
|
+
end
|
354
|
+
|
355
|
+
|
356
|
+
if parts_equal
|
357
|
+
|
358
|
+
o_parts.shift
|
359
|
+
p_parts.shift
|
360
|
+
else
|
361
|
+
|
362
|
+
break
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
return '.' + tr_sl.to_s if 0 == (o_parts.size + p_parts.size)
|
368
|
+
|
369
|
+
return o_parts.map { |rp| '..' }.join('\\') + (tr_sl || (o_parts.size > 0 ? '\\' : nil)).to_s if p_parts.empty?
|
370
|
+
|
371
|
+
|
372
|
+
ar = [ '..' ] * o_parts.size + p_parts
|
373
|
+
last = ar.pop
|
374
|
+
ar = ar.map { |el| _Internal_Windows_Form.append_trailing_slash(el) }
|
375
|
+
|
376
|
+
last[-1] = '\\' if '/' == last[-1]
|
377
|
+
|
378
|
+
ar.join + last.to_s
|
379
|
+
end
|
380
|
+
|
381
|
+
# Returns a "compare path" for the given absolute path
|
382
|
+
#
|
383
|
+
# A compare path is one that would refer definitely to a given entry,
|
384
|
+
# regardless of such operating system-specific issues such as
|
385
|
+
# case-insensitivity
|
386
|
+
#
|
387
|
+
# NOTE: the function does not make +path+ absolute. That is up to the
|
388
|
+
# caller if required
|
389
|
+
#
|
390
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
391
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
392
|
+
#
|
393
|
+
# === Signature
|
394
|
+
#
|
395
|
+
# * *Parameters:*
|
396
|
+
# - +path+:: (String) The path whose definitive equivalent is to be
|
397
|
+
# obtained
|
398
|
+
# - +options+:: (Hash) options
|
399
|
+
#
|
400
|
+
# * *Options:*
|
401
|
+
# - +:splits+:: ([ String ]) An array of string-like objects. If the
|
402
|
+
# object at index 1 exists and supports the +form+ attribute and
|
403
|
+
# that returns one of { +:form_2+, +:form_3+, +:form_4+, +:form_5+,
|
404
|
+
# +:form_6+ } then it is assumed to be the volume, and the objects
|
405
|
+
# at indexes 2 and 3 are assumed to be the directory and the
|
406
|
+
# basename, respectively. In this case, the compare path is
|
407
|
+
# constructed from a UNC-respecting form
|
408
|
+
def make_compare_path path, **options
|
409
|
+
|
410
|
+
if splits = options[:splits]
|
411
|
+
|
412
|
+
if volume = splits[1]
|
413
|
+
|
414
|
+
if volume.respond_to?(:form)
|
415
|
+
|
416
|
+
case volume.form
|
417
|
+
when :form_2, :form_3, :form_4, :form_5, :form_6
|
418
|
+
|
419
|
+
directory = splits[2] || ''
|
420
|
+
basename = splits[3] || ''
|
421
|
+
|
422
|
+
return "#{volume}#{directory.upcase}#{basename.upcase}"
|
423
|
+
else
|
424
|
+
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
path.upcase
|
431
|
+
end
|
432
|
+
|
433
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
434
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
435
|
+
#
|
436
|
+
def make_path_absolute path, **options
|
437
|
+
|
438
|
+
_Form_Windows = Form::Windows
|
439
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
440
|
+
|
441
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
442
|
+
Diagnostics.check_options(options, known: %i{ home locator make_canonical pwd }) if $DEBUG
|
443
|
+
|
444
|
+
return path if path.nil? || path.empty?
|
445
|
+
|
446
|
+
r = nil
|
447
|
+
|
448
|
+
if false
|
449
|
+
|
450
|
+
;
|
451
|
+
elsif _Form_Windows.path_is_homed? path
|
452
|
+
|
453
|
+
home = nil
|
454
|
+
home ||= options[:home]
|
455
|
+
home ||= options[:locator].home if options.has_key?(:locator)
|
456
|
+
home ||= Dir.home
|
457
|
+
|
458
|
+
unless _Internal_Windows_Form.has_trailing_slash? home
|
459
|
+
|
460
|
+
home = home + path[1].to_s
|
461
|
+
end
|
462
|
+
|
463
|
+
r = combine_paths(home, path[2..-1])
|
464
|
+
elsif _Form_Windows.path_is_UNC? path
|
465
|
+
|
466
|
+
r = path
|
467
|
+
elsif _Form_Windows.path_is_absolute? path
|
468
|
+
|
469
|
+
r = path
|
470
|
+
elsif _Form_Windows.path_is_rooted? path
|
471
|
+
|
472
|
+
pwd = nil
|
473
|
+
pwd ||= options[:pwd]
|
474
|
+
pwd ||= options[:locator].pwd if options.has_key?(:locator)
|
475
|
+
pwd ||= Dir.pwd
|
476
|
+
|
477
|
+
r = pwd[0..1] + path
|
478
|
+
else
|
479
|
+
|
480
|
+
pwd = nil
|
481
|
+
pwd ||= options[:pwd]
|
482
|
+
pwd ||= options[:locator].pwd if options.has_key?(:locator)
|
483
|
+
pwd ||= Dir.pwd
|
484
|
+
|
485
|
+
r = combine_paths(pwd, path, elide_single_dots: false)
|
486
|
+
end
|
487
|
+
|
488
|
+
if options[:make_canonical]
|
489
|
+
|
490
|
+
r = make_path_canonical r
|
491
|
+
else
|
492
|
+
|
493
|
+
vol, rem, _ = _Internal_Windows_Form.get_windows_volume r
|
494
|
+
|
495
|
+
_Internal_Windows_Form.elide_redundant_path_name_separators! rem
|
496
|
+
|
497
|
+
r = "#{vol}#{rem}"
|
498
|
+
end
|
499
|
+
|
500
|
+
return r
|
501
|
+
end
|
502
|
+
|
503
|
+
# Converts a path into canonical form, which is to say that all possible
|
504
|
+
# dots directory parts are removed:
|
505
|
+
#
|
506
|
+
# - single-dot parts - './' or '.\\' - are all removed
|
507
|
+
# - double-dot parts - '../' or '..\\' - are removed where they follow a
|
508
|
+
# non-dots directory part, or where they follow the root
|
509
|
+
#
|
510
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
511
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
512
|
+
#
|
513
|
+
# === Signature
|
514
|
+
#
|
515
|
+
# * *Parameters:*
|
516
|
+
# - +path+:: (String) The path to be evaluated. May not be +nil+
|
517
|
+
#
|
518
|
+
# * *Options:*
|
519
|
+
# - +:make_slashes_canonical+:: (boolean) Determines whether to
|
520
|
+
# additionally convert all forward slashes to backslashes
|
521
|
+
def make_path_canonical path, **options
|
522
|
+
|
523
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
524
|
+
|
525
|
+
if path.include?('/') && options[:make_slashes_canonical]
|
526
|
+
|
527
|
+
path = path.tr '/', '\\'
|
528
|
+
end
|
529
|
+
|
530
|
+
return path unless '.' == path[-1] || path =~ /[.\\\/][\\\/]/
|
531
|
+
|
532
|
+
_Form = ::LibPath::Internal_::Windows::Form
|
533
|
+
_Array = ::LibPath::Internal_::Array
|
534
|
+
|
535
|
+
path = path[0...-1] if '.' == path[-1] && _Form.char_is_path_name_separator?(path[-2])
|
536
|
+
|
537
|
+
|
538
|
+
f0_path, f1_volume, f2_directory, f3_basename, _, _, f6_dir_parts, _ = _Form.split_path path
|
539
|
+
|
540
|
+
if f6_dir_parts.empty?
|
541
|
+
|
542
|
+
case f3_basename
|
543
|
+
when '.'
|
544
|
+
|
545
|
+
return "#{f1_volume}.\\"
|
546
|
+
when '..'
|
547
|
+
|
548
|
+
return "#{f1_volume}..\\"
|
549
|
+
else
|
550
|
+
|
551
|
+
return f0_path
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
last_slash = nil
|
556
|
+
|
557
|
+
case f3_basename
|
558
|
+
when '.', '..'
|
559
|
+
|
560
|
+
f6_dir_parts << f3_basename + '\\'
|
561
|
+
basename = nil
|
562
|
+
when nil
|
563
|
+
|
564
|
+
last_slash = _Form.get_trailing_slash(f2_directory) || '\\'
|
565
|
+
else
|
566
|
+
|
567
|
+
basename = f3_basename
|
568
|
+
end
|
569
|
+
|
570
|
+
is_rooted = _Form.char_is_path_name_separator?(f2_directory[0])
|
571
|
+
|
572
|
+
new_parts = f6_dir_parts.dup
|
573
|
+
new_parts.reject! { |p| '.\\' == p || './' == p }
|
574
|
+
ix_nodots = new_parts.index { |p| '../' != p && '..\\' != p } || new_parts.size
|
575
|
+
ix_2dots = _Array.index2(new_parts, '../', '..\\', ix_nodots)
|
576
|
+
|
577
|
+
return "#{f1_volume}#{new_parts.join}#{basename}" unless new_parts.size != f6_dir_parts.size || ix_2dots
|
578
|
+
|
579
|
+
while (ix_2dots || 0) > 0
|
580
|
+
|
581
|
+
new_parts.delete_at(ix_2dots - 0)
|
582
|
+
new_parts.delete_at(ix_2dots - 1) if ix_2dots != 1 || !is_rooted
|
583
|
+
|
584
|
+
ix_nodots = new_parts.index { |p| '../' != p && '..\\' != p } or break
|
585
|
+
ix_2dots = _Array.index2(new_parts, '../', '..\\', ix_nodots)
|
586
|
+
end
|
587
|
+
|
588
|
+
if new_parts.empty? && (basename || '').empty?
|
589
|
+
|
590
|
+
case f3_basename
|
591
|
+
when nil, '.', '..'
|
592
|
+
|
593
|
+
return '.' + (last_slash || '\\').to_s
|
594
|
+
else
|
595
|
+
|
596
|
+
return '.'
|
597
|
+
end
|
598
|
+
return '.' + last_slash.to_s
|
599
|
+
end
|
600
|
+
|
601
|
+
return f1_volume.to_s + new_parts.join('') + basename.to_s
|
602
|
+
end
|
603
|
+
end # module LibPath_Util_Windows_Methods
|
604
|
+
|
605
|
+
# @!visibility private
|
606
|
+
def self.extended receiver # :nodoc:
|
607
|
+
|
608
|
+
receiver.class_eval do
|
609
|
+
|
610
|
+
extend LibPath_Util_Windows_Methods
|
611
|
+
end
|
612
|
+
|
613
|
+
$stderr.puts "#{receiver} extended by #{LibPath_Util_Windows_Methods}" if $DEBUG
|
614
|
+
end
|
615
|
+
|
616
|
+
# @!visibility private
|
617
|
+
def self.included receiver # :nodoc:
|
618
|
+
|
619
|
+
receiver.class_eval do
|
620
|
+
|
621
|
+
include LibPath_Util_Windows_Methods
|
622
|
+
end
|
623
|
+
|
624
|
+
$stderr.puts "#{receiver} included #{LibPath_Util_Windows_Methods}" if $DEBUG
|
625
|
+
end
|
626
|
+
|
627
|
+
extend LibPath_Util_Windows_Methods
|
628
|
+
include LibPath_Util_Windows_Methods
|
629
|
+
|
630
|
+
end # module Windows
|
631
|
+
end # module Util
|
632
|
+
end # module LibPath
|
633
|
+
|
634
|
+
# ############################## end of file ############################# #
|
635
|
+
|
636
|
+
|