libpath-ruby 0.2.2 → 0.2.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 +4 -4
- data/LICENSE +33 -0
- data/README.md +25 -8
- data/examples/path_from_arg0.md +43 -43
- data/examples/path_from_arg0.rb +25 -23
- data/lib/libpath/constants/unix.rb +71 -71
- data/lib/libpath/constants/windows.rb +72 -72
- data/lib/libpath/constants.rb +18 -19
- data/lib/libpath/diagnostics/parameter_checking.rb +25 -25
- data/lib/libpath/diagnostics.rb +1 -1
- data/lib/libpath/exceptions/libpath_base_exception.rb +13 -13
- data/lib/libpath/exceptions/malformed_name_exception.rb +23 -22
- data/lib/libpath/exceptions.rb +1 -1
- data/lib/libpath/form/unix.rb +104 -103
- data/lib/libpath/form/windows.rb +200 -199
- data/lib/libpath/form.rb +18 -18
- data/lib/libpath/internal_/array.rb +53 -53
- data/lib/libpath/internal_/platform.rb +24 -24
- data/lib/libpath/internal_/string.rb +18 -18
- data/lib/libpath/internal_/unix/form.rb +116 -116
- data/lib/libpath/internal_/windows/drive.rb +59 -59
- data/lib/libpath/internal_/windows/form.rb +189 -189
- data/lib/libpath/libpath.rb +3 -0
- data/lib/libpath/path/unix.rb +114 -112
- data/lib/libpath/path/windows.rb +120 -118
- data/lib/libpath/path.rb +18 -20
- data/lib/libpath/util/unix.rb +258 -258
- data/lib/libpath/util/windows.rb +400 -400
- data/lib/libpath/util.rb +18 -19
- data/lib/libpath/version.rb +23 -24
- data/lib/libpath.rb +1 -1
- data/test/performance/benchmark_drive_letter.rb +50 -10
- data/test/performance/benchmark_gsub_string_or_regex.rb +27 -23
- data/test/performance/benchmark_rindex2.rb +56 -48
- data/test/performance/benchmark_split.rb +16 -10
- data/test/unit/compare/ts_all.rb +4 -4
- data/test/unit/equate/ts_all.rb +4 -4
- data/test/unit/equate/unix/ts_all.rb +4 -4
- data/test/unit/equate/windows/ts_all.rb +4 -4
- data/test/unit/exceptions/tc_libpath_base_exception.rb +10 -8
- data/test/unit/exceptions/tc_malformed_name_exception.rb +14 -12
- data/test/unit/exceptions/ts_all.rb +4 -4
- data/test/unit/form/tc_absolute_functions.rb +242 -240
- data/test/unit/form/ts_all.rb +4 -4
- data/test/unit/form/unix/tc_absolute_functions.rb +158 -155
- data/test/unit/form/unix/ts_all.rb +4 -4
- data/test/unit/form/windows/tc_absolute_functions.rb +628 -625
- data/test/unit/form/windows/ts_all.rb +4 -4
- data/test/unit/internal_/tc_array.rb +36 -32
- data/test/unit/internal_/ts_all.rb +4 -4
- data/test/unit/internal_/unix/form/tc_slash_functions.rb +38 -35
- data/test/unit/internal_/unix/form/ts_all.rb +4 -4
- data/test/unit/internal_/unix/tc_split_path.rb +387 -384
- data/test/unit/internal_/unix/ts_all.rb +4 -4
- data/test/unit/internal_/windows/form/tc_get_windows_volume.rb +157 -153
- data/test/unit/internal_/windows/form/tc_slash_functions.rb +39 -35
- data/test/unit/internal_/windows/form/ts_all.rb +4 -4
- data/test/unit/internal_/windows/tc_split_path.rb +874 -869
- data/test/unit/internal_/windows/ts_all.rb +4 -4
- data/test/unit/parse/ts_all.rb +4 -4
- data/test/unit/path/tc_path.rb +732 -732
- data/test/unit/path/ts_all.rb +4 -4
- data/test/unit/path/unix/tc_path.rb +544 -540
- data/test/unit/path/unix/ts_all.rb +4 -4
- data/test/unit/path/windows/tc_path.rb +608 -603
- data/test/unit/path/windows/ts_all.rb +4 -4
- data/test/unit/tc_version.rb +25 -22
- data/test/unit/ts_all.rb +4 -4
- data/test/unit/util/tc_combine_paths.rb +110 -105
- data/test/unit/util/tc_derive_relative_path.rb +8 -3
- data/test/unit/util/tc_make_path_canonical.rb +142 -138
- data/test/unit/util/ts_all.rb +4 -4
- data/test/unit/util/unix/tc_combine_paths.rb +38 -34
- data/test/unit/util/unix/tc_derive_relative_path.rb +80 -75
- data/test/unit/util/unix/tc_make_path_absolute.rb +74 -70
- data/test/unit/util/unix/tc_make_path_canonical.rb +95 -90
- data/test/unit/util/unix/ts_all.rb +4 -4
- data/test/unit/util/windows/tc_combine_paths.rb +82 -77
- data/test/unit/util/windows/tc_derive_relative_path.rb +98 -93
- data/test/unit/util/windows/tc_make_path_absolute.rb +105 -101
- data/test/unit/util/windows/tc_make_path_canonical.rb +158 -153
- data/test/unit/util/windows/ts_all.rb +4 -4
- metadata +9 -8
data/lib/libpath/util/windows.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
|
2
2
|
# ######################################################################## #
|
3
|
-
# File:
|
3
|
+
# File: libpath/util/windows.rb
|
4
4
|
#
|
5
|
-
# Purpose:
|
5
|
+
# Purpose: LibPath::Util::Windows module
|
6
6
|
#
|
7
|
-
# Created:
|
8
|
-
# Updated:
|
7
|
+
# Created: 10th January 2019
|
8
|
+
# Updated: 6th April 2024
|
9
9
|
#
|
10
|
-
# Home:
|
10
|
+
# Home: http://github.com/synesissoftware/libpath.Ruby
|
11
11
|
#
|
12
|
-
# Author:
|
12
|
+
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
+
# Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems
|
14
15
|
# Copyright (c) 2019, Matthew Wilson and Synesis Software
|
15
16
|
# All rights reserved.
|
16
17
|
#
|
@@ -44,593 +45,592 @@
|
|
44
45
|
# ######################################################################## #
|
45
46
|
|
46
47
|
|
47
|
-
|
48
48
|
=begin
|
49
49
|
=end
|
50
50
|
|
51
|
-
|
52
51
|
require 'libpath/diagnostics'
|
53
52
|
require 'libpath/form/windows'
|
54
53
|
require 'libpath/internal_/array'
|
55
54
|
require 'libpath/internal_/windows/form'
|
56
55
|
|
56
|
+
|
57
57
|
module LibPath # :nodoc:
|
58
58
|
module Util # :nodoc:
|
59
59
|
module Windows # :nodoc:
|
60
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
|
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
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
75
|
|
76
|
-
|
77
|
-
|
76
|
+
_Form_Windows = Form::Windows
|
77
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
78
78
|
|
79
|
-
|
79
|
+
args.each_with_index { |arg, index| Diagnostics.check_string_parameter(arg, "arg#{index}", allow_nil: true) } if $DEBUG
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
first = []
|
82
|
+
dirs = []
|
83
|
+
last = []
|
84
84
|
|
85
|
-
|
85
|
+
if options[:elide_single_dots]
|
86
86
|
|
87
|
-
|
87
|
+
args = args.map do |arg|
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
case arg
|
90
|
+
when '.', './'
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
nil
|
93
|
+
else
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
arg
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
99
|
|
100
|
-
|
100
|
+
args = args.reject { |arg| arg.nil? || arg.empty? }
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
rix_abs = nil
|
103
|
+
rix_drv = nil
|
104
|
+
rix_dir = nil
|
105
105
|
|
106
|
-
|
106
|
+
args.each_with_index do |arg, index|
|
107
107
|
|
108
|
-
|
108
|
+
vol, rem, _ = _Internal_Windows_Form.get_windows_volume arg
|
109
109
|
|
110
|
-
|
110
|
+
rem = nil unless rem && _Internal_Windows_Form.char_is_path_name_separator?(rem[0])
|
111
111
|
|
112
|
-
|
112
|
+
if vol
|
113
113
|
|
114
|
-
|
114
|
+
if rem
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
rix_abs = index
|
117
|
+
else
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
119
|
+
rix_drv = index
|
120
|
+
end
|
121
|
+
elsif rem
|
122
122
|
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
rix_dir = index
|
124
|
+
end
|
125
|
+
end
|
126
126
|
|
127
|
-
|
128
|
-
|
127
|
+
rix_drv = nil if (rix_drv || -1) <= (rix_abs || -1)
|
128
|
+
rix_dir = nil if (rix_dir || -1) <= (rix_abs || -1)
|
129
129
|
|
130
|
-
|
130
|
+
if rix_drv && rix_dir && rix_abs
|
131
131
|
|
132
|
-
|
132
|
+
if rix_abs < rix_drv && rix_abs < rix_dir
|
133
133
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
141
|
|
142
|
-
|
142
|
+
if rix_drv.nil? && rix_dir.nil?
|
143
143
|
|
144
|
-
|
144
|
+
if rix_abs
|
145
145
|
|
146
|
-
|
147
|
-
|
146
|
+
args = args[rix_abs..-1]
|
147
|
+
end
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
dirs = args
|
150
|
+
last << args.pop unless args.empty?
|
151
|
+
else
|
152
152
|
|
153
|
-
|
153
|
+
if false
|
154
154
|
|
155
|
-
|
156
|
-
|
155
|
+
;
|
156
|
+
elsif rix_drv
|
157
157
|
|
158
|
-
|
158
|
+
if rix_dir
|
159
159
|
|
160
|
-
|
161
|
-
|
162
|
-
|
160
|
+
drv = args.delete_at rix_drv
|
161
|
+
rix_dir -= 1 if rix_drv < rix_dir
|
162
|
+
dir = args.delete_at rix_dir
|
163
163
|
|
164
|
-
|
164
|
+
args = args[rix_dir..-1]
|
165
165
|
|
166
|
-
|
166
|
+
if dir.size > 1
|
167
167
|
|
168
|
-
|
169
|
-
|
170
|
-
|
168
|
+
args.unshift dir[1..-1]
|
169
|
+
dir = dir[0]
|
170
|
+
end
|
171
171
|
|
172
|
-
|
172
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{drv}#{dir}")
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
174
|
+
first << root
|
175
|
+
last << args.pop unless args.empty?
|
176
|
+
dirs = args
|
177
|
+
elsif rix_abs
|
178
178
|
|
179
|
-
|
180
|
-
|
181
|
-
|
179
|
+
drv = args.delete_at rix_drv
|
180
|
+
rix_abs -= 1 if rix_drv < rix_abs
|
181
|
+
abs = args.delete_at rix_abs
|
182
182
|
|
183
|
-
|
183
|
+
_, _, dir, bas, _, _, _, _ = _Internal_Windows_Form.split_path abs
|
184
184
|
|
185
|
-
|
185
|
+
args = args[rix_abs..-1]
|
186
186
|
|
187
|
-
|
187
|
+
if dir.size > 1
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
189
|
+
args.unshift dir[1..-1]
|
190
|
+
dir = dir[0]
|
191
|
+
end
|
192
192
|
|
193
|
-
|
193
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{drv}#{dir}#{bas}")
|
194
194
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
195
|
+
first << root
|
196
|
+
last << args.pop unless args.empty?
|
197
|
+
dirs = args
|
198
|
+
else
|
199
199
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
first << args.delete_at(rix_drv)
|
201
|
+
last << args.pop unless args.empty?
|
202
|
+
dirs = args
|
203
|
+
end
|
204
|
+
elsif rix_dir
|
205
205
|
|
206
|
-
|
206
|
+
if rix_abs
|
207
207
|
|
208
|
-
|
209
|
-
|
210
|
-
|
208
|
+
abs = args.delete_at rix_abs
|
209
|
+
rix_dir -= 1 if rix_abs < rix_dir
|
210
|
+
dir = args.delete_at rix_dir
|
211
211
|
|
212
|
-
|
212
|
+
_, vol, _, _, _, _, _, _ = _Internal_Windows_Form.split_path abs
|
213
213
|
|
214
|
-
|
214
|
+
args = args[rix_dir..-1]
|
215
215
|
|
216
|
-
|
216
|
+
root = _Internal_Windows_Form.append_trailing_slash("#{vol}#{dir}")
|
217
217
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
218
|
+
first << root
|
219
|
+
last << args.pop unless args.empty?
|
220
|
+
dirs = args
|
221
|
+
else
|
222
222
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
223
|
+
args = args[rix_dir..-1]
|
224
|
+
last << args.pop unless args.empty?
|
225
|
+
dirs = args
|
226
|
+
end
|
227
|
+
else
|
228
228
|
|
229
|
-
|
230
|
-
|
231
|
-
|
229
|
+
;
|
230
|
+
end
|
231
|
+
end
|
232
232
|
|
233
|
-
|
233
|
+
dirs = dirs.map { |el| _Internal_Windows_Form.append_trailing_slash el }
|
234
234
|
|
235
|
-
|
236
|
-
|
235
|
+
(first + dirs + last).join('')
|
236
|
+
end
|
237
237
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
252
|
|
253
|
-
|
254
|
-
|
253
|
+
return path if origin.nil? || origin.empty?
|
254
|
+
return path if path.nil? || path.empty?
|
255
255
|
|
256
|
-
|
257
|
-
|
258
|
-
|
256
|
+
_Form_Windows = Form::Windows
|
257
|
+
_Util_Windows = Util::Windows
|
258
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
259
259
|
|
260
|
-
|
260
|
+
_MPA_COMMON_OPTIONS = %i{ home locator pwd }
|
261
261
|
|
262
|
-
|
262
|
+
tr_sl = _Internal_Windows_Form.get_trailing_slash(path)
|
263
263
|
|
264
|
-
|
264
|
+
# Possibly naive home-correction
|
265
265
|
|
266
|
-
|
267
|
-
|
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
268
|
|
269
269
|
|
270
|
-
|
271
|
-
|
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
272
|
|
273
|
-
|
273
|
+
if o_vol && p_vol
|
274
274
|
|
275
|
-
|
275
|
+
# always give absolute answer when 'volume's are different
|
276
276
|
|
277
|
-
|
277
|
+
if o_vol != p_vol
|
278
278
|
|
279
|
-
|
279
|
+
if options[:make_path_canonical]
|
280
280
|
|
281
|
-
|
282
|
-
|
281
|
+
path = _Util_Windows.make_path_canonical(path, make_slashes_canonical: true)
|
282
|
+
else
|
283
283
|
|
284
|
-
|
285
|
-
|
284
|
+
path = path.tr('/', '\\')
|
285
|
+
end
|
286
286
|
|
287
|
-
|
288
|
-
|
289
|
-
|
287
|
+
return path
|
288
|
+
end
|
289
|
+
end
|
290
290
|
|
291
291
|
|
292
|
-
|
293
|
-
|
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
294
|
|
295
|
-
|
296
|
-
|
295
|
+
o_is_abs = o_vol && o_is_rooted
|
296
|
+
p_is_abs = p_vol && p_is_rooted
|
297
297
|
|
298
|
-
|
298
|
+
mpa_opts = options.select { |k| _MPA_COMMON_OPTIONS.include?(k) }
|
299
299
|
|
300
|
-
|
300
|
+
if o_is_abs != p_is_abs || o_is_rooted != p_is_rooted
|
301
301
|
|
302
|
-
|
303
|
-
|
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
304
|
|
305
|
-
|
306
|
-
|
305
|
+
return derive_relative_path(origin, path, **options)
|
306
|
+
end
|
307
307
|
|
308
|
-
|
309
|
-
|
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
310
|
|
311
|
-
|
312
|
-
|
311
|
+
return '.' + tr_sl.to_s if origin == path
|
312
|
+
return path if '.\\' == origin
|
313
313
|
|
314
|
-
|
314
|
+
if o_is_abs != p_is_abs || '.\\' == path
|
315
315
|
|
316
|
-
|
317
|
-
|
318
|
-
|
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
319
|
|
320
320
|
|
321
|
-
|
322
|
-
|
321
|
+
_, _, _, o3_basename, _, _, o6_parts, _ = _Internal_Windows_Form.split_path(origin)
|
322
|
+
_, _, _, p3_basename, _, _, p6_parts, _ = _Internal_Windows_Form.split_path(path)
|
323
323
|
|
324
|
-
|
325
|
-
|
324
|
+
o_parts = o6_parts
|
325
|
+
o_parts << o3_basename if o3_basename && '.' != o3_basename
|
326
326
|
|
327
|
-
|
328
|
-
|
327
|
+
p_parts = p6_parts
|
328
|
+
p_parts << p3_basename if p3_basename && '.' != p3_basename
|
329
329
|
|
330
330
|
|
331
|
-
|
331
|
+
while true
|
332
332
|
|
333
|
-
|
334
|
-
|
333
|
+
break if o_parts.empty?
|
334
|
+
break if p_parts.empty?
|
335
335
|
|
336
|
-
|
337
|
-
|
336
|
+
o_part = o_parts[0]
|
337
|
+
p_part = p_parts[0]
|
338
338
|
|
339
|
-
|
339
|
+
if 1 == o_parts.size || 1 == p_parts.size
|
340
340
|
|
341
|
-
|
342
|
-
|
343
|
-
|
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
344
|
|
345
|
-
|
345
|
+
parts_equal = false
|
346
346
|
|
347
|
-
|
347
|
+
if o_part.size == p_part.size
|
348
348
|
|
349
|
-
|
350
|
-
|
349
|
+
o_part = o_part.tr('/', '\\') if o_part.include? '/'
|
350
|
+
p_part = p_part.tr('/', '\\') if p_part.include? '/'
|
351
351
|
|
352
|
-
|
353
|
-
|
352
|
+
parts_equal = o_part == p_part
|
353
|
+
end
|
354
354
|
|
355
355
|
|
356
|
-
|
356
|
+
if parts_equal
|
357
357
|
|
358
|
-
|
359
|
-
|
360
|
-
|
358
|
+
o_parts.shift
|
359
|
+
p_parts.shift
|
360
|
+
else
|
361
361
|
|
362
|
-
|
363
|
-
|
364
|
-
|
362
|
+
break
|
363
|
+
end
|
364
|
+
end
|
365
365
|
|
366
366
|
|
367
|
-
|
367
|
+
return '.' + tr_sl.to_s if 0 == (o_parts.size + p_parts.size)
|
368
368
|
|
369
|
-
|
369
|
+
return o_parts.map { |rp| '..' }.join('\\') + (tr_sl || (o_parts.size > 0 ? '\\' : nil)).to_s if p_parts.empty?
|
370
370
|
|
371
371
|
|
372
|
-
|
373
|
-
|
374
|
-
|
372
|
+
ar = [ '..' ] * o_parts.size + p_parts
|
373
|
+
last = ar.pop
|
374
|
+
ar = ar.map { |el| _Internal_Windows_Form.append_trailing_slash(el) }
|
375
375
|
|
376
|
-
|
376
|
+
last[-1] = '\\' if '/' == last[-1]
|
377
377
|
|
378
|
-
|
379
|
-
|
378
|
+
ar.join + last.to_s
|
379
|
+
end
|
380
380
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
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
409
|
|
410
|
-
|
410
|
+
if splits = options[:splits]
|
411
411
|
|
412
|
-
|
412
|
+
if volume = splits[1]
|
413
413
|
|
414
|
-
|
414
|
+
if volume.respond_to?(:form)
|
415
415
|
|
416
|
-
|
417
|
-
|
416
|
+
case volume.form
|
417
|
+
when :form_2, :form_3, :form_4, :form_5, :form_6
|
418
418
|
|
419
|
-
|
420
|
-
|
419
|
+
directory = splits[2] || ''
|
420
|
+
basename = splits[3] || ''
|
421
421
|
|
422
|
-
|
423
|
-
|
422
|
+
return "#{volume}#{directory.upcase}#{basename.upcase}"
|
423
|
+
else
|
424
424
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
429
|
|
430
|
-
|
431
|
-
|
430
|
+
path.upcase
|
431
|
+
end
|
432
432
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
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
437
|
|
438
|
-
|
439
|
-
|
438
|
+
_Form_Windows = Form::Windows
|
439
|
+
_Internal_Windows_Form = Internal_::Windows::Form
|
440
440
|
|
441
|
-
|
442
|
-
|
441
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
442
|
+
Diagnostics.check_options(options, known: %i{ home locator make_canonical pwd }) if $DEBUG
|
443
443
|
|
444
|
-
|
444
|
+
return path if path.nil? || path.empty?
|
445
445
|
|
446
|
-
|
446
|
+
r = nil
|
447
447
|
|
448
|
-
|
448
|
+
if false
|
449
449
|
|
450
|
-
|
451
|
-
|
450
|
+
;
|
451
|
+
elsif _Form_Windows.path_is_homed? path
|
452
452
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
453
|
+
home = nil
|
454
|
+
home ||= options[:home]
|
455
|
+
home ||= options[:locator].home if options.has_key?(:locator)
|
456
|
+
home ||= Dir.home
|
457
457
|
|
458
|
-
|
458
|
+
unless _Internal_Windows_Form.has_trailing_slash? home
|
459
459
|
|
460
|
-
|
461
|
-
|
460
|
+
home = home + path[1].to_s
|
461
|
+
end
|
462
462
|
|
463
|
-
|
464
|
-
|
463
|
+
r = combine_paths(home, path[2..-1])
|
464
|
+
elsif _Form_Windows.path_is_UNC? path
|
465
465
|
|
466
|
-
|
467
|
-
|
466
|
+
r = path
|
467
|
+
elsif _Form_Windows.path_is_absolute? path
|
468
468
|
|
469
|
-
|
470
|
-
|
469
|
+
r = path
|
470
|
+
elsif _Form_Windows.path_is_rooted? path
|
471
471
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
472
|
+
pwd = nil
|
473
|
+
pwd ||= options[:pwd]
|
474
|
+
pwd ||= options[:locator].pwd if options.has_key?(:locator)
|
475
|
+
pwd ||= Dir.pwd
|
476
476
|
|
477
|
-
|
478
|
-
|
477
|
+
r = pwd[0..1] + path
|
478
|
+
else
|
479
479
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
480
|
+
pwd = nil
|
481
|
+
pwd ||= options[:pwd]
|
482
|
+
pwd ||= options[:locator].pwd if options.has_key?(:locator)
|
483
|
+
pwd ||= Dir.pwd
|
484
484
|
|
485
|
-
|
486
|
-
|
485
|
+
r = combine_paths(pwd, path, elide_single_dots: false)
|
486
|
+
end
|
487
487
|
|
488
|
-
|
488
|
+
if options[:make_canonical]
|
489
489
|
|
490
|
-
|
491
|
-
|
490
|
+
r = make_path_canonical r
|
491
|
+
else
|
492
492
|
|
493
|
-
|
493
|
+
vol, rem, _ = _Internal_Windows_Form.get_windows_volume r
|
494
494
|
|
495
|
-
|
495
|
+
_Internal_Windows_Form.elide_redundant_path_name_separators! rem
|
496
496
|
|
497
|
-
|
498
|
-
|
497
|
+
r = "#{vol}#{rem}"
|
498
|
+
end
|
499
499
|
|
500
|
-
|
501
|
-
|
500
|
+
return r
|
501
|
+
end
|
502
502
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
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
522
|
|
523
|
-
|
523
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
524
524
|
|
525
|
-
|
525
|
+
if path.include?('/') && options[:make_slashes_canonical]
|
526
526
|
|
527
|
-
|
528
|
-
|
527
|
+
path = path.tr '/', '\\'
|
528
|
+
end
|
529
529
|
|
530
|
-
|
530
|
+
return path unless '.' == path[-1] || path =~ /[.\\\/][\\\/]/
|
531
531
|
|
532
|
-
|
533
|
-
|
532
|
+
_Form = ::LibPath::Internal_::Windows::Form
|
533
|
+
_Array = ::LibPath::Internal_::Array
|
534
534
|
|
535
|
-
|
535
|
+
path = path[0...-1] if '.' == path[-1] && _Form.char_is_path_name_separator?(path[-2])
|
536
536
|
|
537
537
|
|
538
|
-
|
538
|
+
f0_path, f1_volume, f2_directory, f3_basename, _, _, f6_dir_parts, _ = _Form.split_path path
|
539
539
|
|
540
|
-
|
540
|
+
if f6_dir_parts.empty?
|
541
541
|
|
542
|
-
|
543
|
-
|
542
|
+
case f3_basename
|
543
|
+
when '.'
|
544
544
|
|
545
|
-
|
546
|
-
|
545
|
+
return "#{f1_volume}.\\"
|
546
|
+
when '..'
|
547
547
|
|
548
|
-
|
549
|
-
|
548
|
+
return "#{f1_volume}..\\"
|
549
|
+
else
|
550
550
|
|
551
|
-
|
552
|
-
|
553
|
-
|
551
|
+
return f0_path
|
552
|
+
end
|
553
|
+
end
|
554
554
|
|
555
|
-
|
555
|
+
last_slash = nil
|
556
556
|
|
557
|
-
|
558
|
-
|
557
|
+
case f3_basename
|
558
|
+
when '.', '..'
|
559
559
|
|
560
|
-
|
561
|
-
|
562
|
-
|
560
|
+
f6_dir_parts << f3_basename + '\\'
|
561
|
+
basename = nil
|
562
|
+
when nil
|
563
563
|
|
564
|
-
|
565
|
-
|
564
|
+
last_slash = _Form.get_trailing_slash(f2_directory) || '\\'
|
565
|
+
else
|
566
566
|
|
567
|
-
|
568
|
-
|
567
|
+
basename = f3_basename
|
568
|
+
end
|
569
569
|
|
570
|
-
|
570
|
+
is_rooted = _Form.char_is_path_name_separator?(f2_directory[0])
|
571
571
|
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
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
576
|
|
577
|
-
|
577
|
+
return "#{f1_volume}#{new_parts.join}#{basename}" unless new_parts.size != f6_dir_parts.size || ix_2dots
|
578
578
|
|
579
|
-
|
579
|
+
while (ix_2dots || 0) > 0
|
580
580
|
|
581
|
-
|
582
|
-
|
581
|
+
new_parts.delete_at(ix_2dots - 0)
|
582
|
+
new_parts.delete_at(ix_2dots - 1) if ix_2dots != 1 || !is_rooted
|
583
583
|
|
584
|
-
|
585
|
-
|
586
|
-
|
584
|
+
ix_nodots = new_parts.index { |p| '../' != p && '..\\' != p } or break
|
585
|
+
ix_2dots = _Array.index2(new_parts, '../', '..\\', ix_nodots)
|
586
|
+
end
|
587
587
|
|
588
|
-
|
588
|
+
if new_parts.empty? && (basename || '').empty?
|
589
589
|
|
590
|
-
|
591
|
-
|
590
|
+
case f3_basename
|
591
|
+
when nil, '.', '..'
|
592
592
|
|
593
|
-
|
594
|
-
|
593
|
+
return '.' + (last_slash || '\\').to_s
|
594
|
+
else
|
595
595
|
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
596
|
+
return '.'
|
597
|
+
end
|
598
|
+
return '.' + last_slash.to_s
|
599
|
+
end
|
600
600
|
|
601
|
-
|
602
|
-
|
603
|
-
end # module LibPath_Util_Windows_Methods
|
601
|
+
return f1_volume.to_s + new_parts.join('') + basename.to_s
|
602
|
+
end
|
603
|
+
end # module LibPath_Util_Windows_Methods
|
604
604
|
|
605
|
-
# @!visibility private
|
606
|
-
def self.extended receiver # :nodoc:
|
605
|
+
# @!visibility private
|
606
|
+
def self.extended receiver # :nodoc:
|
607
607
|
|
608
|
-
|
608
|
+
receiver.class_eval do
|
609
609
|
|
610
|
-
|
611
|
-
|
610
|
+
extend LibPath_Util_Windows_Methods
|
611
|
+
end
|
612
612
|
|
613
|
-
|
614
|
-
end
|
613
|
+
$stderr.puts "#{receiver} extended by #{LibPath_Util_Windows_Methods}" if $DEBUG
|
614
|
+
end
|
615
615
|
|
616
|
-
# @!visibility private
|
617
|
-
def self.included receiver # :nodoc:
|
616
|
+
# @!visibility private
|
617
|
+
def self.included receiver # :nodoc:
|
618
618
|
|
619
|
-
|
619
|
+
receiver.class_eval do
|
620
620
|
|
621
|
-
|
622
|
-
|
621
|
+
include LibPath_Util_Windows_Methods
|
622
|
+
end
|
623
623
|
|
624
|
-
|
625
|
-
end
|
624
|
+
$stderr.puts "#{receiver} included #{LibPath_Util_Windows_Methods}" if $DEBUG
|
625
|
+
end
|
626
626
|
|
627
|
-
extend LibPath_Util_Windows_Methods
|
628
|
-
include LibPath_Util_Windows_Methods
|
627
|
+
extend LibPath_Util_Windows_Methods
|
628
|
+
include LibPath_Util_Windows_Methods
|
629
629
|
|
630
630
|
end # module Windows
|
631
631
|
end # module Util
|
632
632
|
end # module LibPath
|
633
633
|
|
634
|
-
# ############################## end of file ############################# #
|
635
634
|
|
635
|
+
# ############################## end of file ############################# #
|
636
636
|
|