libpath-ruby 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +61 -0
  3. data/examples/path_from_arg0.md +99 -0
  4. data/examples/path_from_arg0.rb +55 -0
  5. data/lib/libpath.rb +12 -0
  6. data/lib/libpath/constants.rb +42 -0
  7. data/lib/libpath/constants/unix.rb +146 -0
  8. data/lib/libpath/constants/windows.rb +147 -0
  9. data/lib/libpath/diagnostics.rb +6 -0
  10. data/lib/libpath/diagnostics/parameter_checking.rb +46 -0
  11. data/lib/libpath/exceptions.rb +7 -0
  12. data/lib/libpath/exceptions/libpath_base_exception.rb +77 -0
  13. data/lib/libpath/exceptions/malformed_name_exception.rb +85 -0
  14. data/lib/libpath/form.rb +42 -0
  15. data/lib/libpath/form/unix.rb +215 -0
  16. data/lib/libpath/form/windows.rb +358 -0
  17. data/lib/libpath/internal_/array.rb +96 -0
  18. data/lib/libpath/internal_/platform.rb +53 -0
  19. data/lib/libpath/internal_/string.rb +33 -0
  20. data/lib/libpath/internal_/unix/form.rb +160 -0
  21. data/lib/libpath/internal_/windows/drive.rb +84 -0
  22. data/lib/libpath/internal_/windows/form.rb +281 -0
  23. data/lib/libpath/libpath.rb +6 -0
  24. data/lib/libpath/path.rb +43 -0
  25. data/lib/libpath/path/unix.rb +170 -0
  26. data/lib/libpath/path/windows.rb +176 -0
  27. data/lib/libpath/util.rb +42 -0
  28. data/lib/libpath/util/unix.rb +414 -0
  29. data/lib/libpath/util/windows.rb +636 -0
  30. data/lib/libpath/version.rb +73 -0
  31. data/test/performance/benchmark_drive_letter.rb +31 -0
  32. data/test/performance/benchmark_gsub_string_or_regex.rb +45 -0
  33. data/test/performance/benchmark_rindex2.rb +109 -0
  34. data/test/performance/benchmark_split.rb +32 -0
  35. data/test/unit/compare/ts_all.rb +22 -0
  36. data/test/unit/equate/ts_all.rb +22 -0
  37. data/test/unit/equate/unix/ts_all.rb +22 -0
  38. data/test/unit/equate/windows/ts_all.rb +22 -0
  39. data/test/unit/exceptions/tc_libpath_base_exception.rb +27 -0
  40. data/test/unit/exceptions/tc_malformed_name_exception.rb +31 -0
  41. data/test/unit/exceptions/ts_all.rb +22 -0
  42. data/test/unit/form/tc_absolute_functions.rb +369 -0
  43. data/test/unit/form/ts_all.rb +22 -0
  44. data/test/unit/form/unix/tc_absolute_functions.rb +269 -0
  45. data/test/unit/form/unix/ts_all.rb +22 -0
  46. data/test/unit/form/windows/tc_absolute_functions.rb +854 -0
  47. data/test/unit/form/windows/ts_all.rb +22 -0
  48. data/test/unit/internal_/tc_array.rb +62 -0
  49. data/test/unit/internal_/ts_all.rb +22 -0
  50. data/test/unit/internal_/unix/form/tc_slash_functions.rb +60 -0
  51. data/test/unit/internal_/unix/form/ts_all.rb +22 -0
  52. data/test/unit/internal_/unix/tc_split_path.rb +396 -0
  53. data/test/unit/internal_/unix/ts_all.rb +22 -0
  54. data/test/unit/internal_/windows/form/tc_get_windows_volume.rb +220 -0
  55. data/test/unit/internal_/windows/form/tc_slash_functions.rb +61 -0
  56. data/test/unit/internal_/windows/form/ts_all.rb +22 -0
  57. data/test/unit/internal_/windows/tc_split_path.rb +881 -0
  58. data/test/unit/internal_/windows/ts_all.rb +22 -0
  59. data/test/unit/parse/ts_all.rb +22 -0
  60. data/test/unit/path/tc_path.rb +778 -0
  61. data/test/unit/path/ts_all.rb +22 -0
  62. data/test/unit/path/unix/tc_path.rb +565 -0
  63. data/test/unit/path/unix/ts_all.rb +22 -0
  64. data/test/unit/path/windows/tc_path.rb +630 -0
  65. data/test/unit/path/windows/ts_all.rb +22 -0
  66. data/test/unit/tc_version.rb +47 -0
  67. data/test/unit/ts_all.rb +22 -0
  68. data/test/unit/util/tc_combine_paths.rb +179 -0
  69. data/test/unit/util/tc_derive_relative_path.rb +19 -0
  70. data/test/unit/util/tc_make_path_canonical.rb +228 -0
  71. data/test/unit/util/ts_all.rb +22 -0
  72. data/test/unit/util/unix/tc_combine_paths.rb +65 -0
  73. data/test/unit/util/unix/tc_derive_relative_path.rb +123 -0
  74. data/test/unit/util/unix/tc_make_path_absolute.rb +117 -0
  75. data/test/unit/util/unix/tc_make_path_canonical.rb +139 -0
  76. data/test/unit/util/unix/ts_all.rb +22 -0
  77. data/test/unit/util/windows/tc_combine_paths.rb +131 -0
  78. data/test/unit/util/windows/tc_derive_relative_path.rb +155 -0
  79. data/test/unit/util/windows/tc_make_path_absolute.rb +163 -0
  80. data/test/unit/util/windows/tc_make_path_canonical.rb +220 -0
  81. data/test/unit/util/windows/ts_all.rb +22 -0
  82. 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
+