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
data/lib/libpath/path.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'libpath/internal_/platform'
|
3
|
+
|
4
|
+
if ::LibPath::Internal_::Platform::Constants::PLATFORM_IS_WINDOWS then
|
5
|
+
|
6
|
+
require 'libpath/path/windows'
|
7
|
+
else
|
8
|
+
|
9
|
+
require 'libpath/path/unix'
|
10
|
+
end
|
11
|
+
|
12
|
+
module LibPath # :nodoc:
|
13
|
+
module Path # :nodoc:
|
14
|
+
|
15
|
+
if ::LibPath::Internal_::Platform::Constants::PLATFORM_IS_WINDOWS then
|
16
|
+
|
17
|
+
extend ::LibPath::Path::Windows
|
18
|
+
include ::LibPath::Path::Windows
|
19
|
+
else
|
20
|
+
|
21
|
+
extend ::LibPath::Path::Unix
|
22
|
+
include ::LibPath::Path::Unix
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!visibility private
|
26
|
+
def self.extended receiver # :nodoc:
|
27
|
+
|
28
|
+
$stderr.puts "#{receiver} extended by #{self}" if $DEBUG
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
def self.included receiver # :nodoc:
|
33
|
+
|
34
|
+
$stderr.puts "#{receiver} included #{self}" if $DEBUG
|
35
|
+
end
|
36
|
+
|
37
|
+
end # module Path
|
38
|
+
end # module LibPath
|
39
|
+
|
40
|
+
# ############################## end of file ############################# #
|
41
|
+
|
42
|
+
|
43
|
+
|
@@ -0,0 +1,170 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: libpath/path/unix.rb
|
4
|
+
#
|
5
|
+
# Purpose: LibPath::Path::Unix module
|
6
|
+
#
|
7
|
+
# Created: 21st 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
|
+
require 'libpath/diagnostics'
|
52
|
+
require 'libpath/internal_/unix/form'
|
53
|
+
require 'libpath/util/unix'
|
54
|
+
|
55
|
+
module LibPath # :nodoc:
|
56
|
+
module Path # :nodoc:
|
57
|
+
module Unix # :nodoc:
|
58
|
+
|
59
|
+
# Class representing a parsed path (for UNIX)
|
60
|
+
class ParsedPath
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
module ParsedPath_Constants # :nodoc: all
|
64
|
+
|
65
|
+
INIT_VALID_OPTIONS = %i{ home locator pwd }
|
66
|
+
INIT_MPA_COMMON_OPTIONS = %i{ home locator pwd }
|
67
|
+
INIT_DRP_COMMON_OPTIONS = %i{ home locator pwd }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Initialises an instance from the given +path+, optional
|
71
|
+
# +search_directory+ and options
|
72
|
+
#
|
73
|
+
# === Signature
|
74
|
+
#
|
75
|
+
# * *Parameters:*
|
76
|
+
# - +path+ (String) The path. May not be +nil+
|
77
|
+
# - +search_directory+ (String) The search_directory, from which the relative attributes are calculated for the path. May be +nil+
|
78
|
+
# - +options+ (Hash) Options
|
79
|
+
#
|
80
|
+
# * *Options:*
|
81
|
+
# - +????+
|
82
|
+
#
|
83
|
+
# * *Exceptions:*
|
84
|
+
# - +ArgumentError+ Raised if +path+ is +nil+
|
85
|
+
def initialize path, search_directory = nil, **options
|
86
|
+
|
87
|
+
raise ::ArgumentError, "path may not be nil or empty" if path.nil? || path.empty?
|
88
|
+
|
89
|
+
_Diagnostics = ::LibPath::Diagnostics
|
90
|
+
_Internal_Form = ::LibPath::Internal_::Unix::Form
|
91
|
+
_Util = ::LibPath::Util::Unix
|
92
|
+
_C = ::LibPath::Path::Unix::ParsedPath::ParsedPath_Constants
|
93
|
+
|
94
|
+
_Diagnostics.check_options(options, known: _C::INIT_VALID_OPTIONS)
|
95
|
+
|
96
|
+
|
97
|
+
abs_path = _Util.make_path_absolute(path, make_canonical: true, **options.select { |k| _C::INIT_MPA_COMMON_OPTIONS.include?(k) })
|
98
|
+
|
99
|
+
_, _, f2_dir, f3_basename, f4_stem, f5_ext, f6_dir_parts, _ = _Internal_Form.split_path(abs_path)
|
100
|
+
|
101
|
+
@given_path = path
|
102
|
+
@absolute_path = abs_path
|
103
|
+
@compare_path = _Util.make_compare_path abs_path
|
104
|
+
@directory = f2_dir
|
105
|
+
@directory_path = f2_dir
|
106
|
+
@directory_parts = f6_dir_parts
|
107
|
+
|
108
|
+
@file_full_name = f3_basename
|
109
|
+
@file_name_only = f4_stem
|
110
|
+
@file_extension = f5_ext
|
111
|
+
|
112
|
+
if search_directory
|
113
|
+
|
114
|
+
drp_options = options.select { |k| _C::INIT_DRP_COMMON_OPTIONS.include?(k) }
|
115
|
+
|
116
|
+
search_directory = _Util.make_path_absolute(search_directory, make_canonical: true, **options.select { |k| _C::INIT_MPA_COMMON_OPTIONS.include?(k) })
|
117
|
+
search_directory = _Internal_Form.append_trailing_slash search_directory
|
118
|
+
|
119
|
+
@search_directory = search_directory
|
120
|
+
@search_relative_path = _Util.derive_relative_path(search_directory, abs_path, **drp_options)
|
121
|
+
@search_relative_path = _Internal_Form.append_trailing_slash(@search_relative_path) if _Internal_Form.char_is_path_name_separator?(abs_path[-1])
|
122
|
+
@search_relative_directory_path = _Internal_Form.append_trailing_slash _Util.derive_relative_path(search_directory, f2_dir, **drp_options)
|
123
|
+
@search_relative_directory_parts = @search_relative_directory_path.split('/').map { |v| v + '/' }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# (String) The path given to initialise the instance
|
128
|
+
attr_reader :given_path
|
129
|
+
# (String) The full-path of the instance
|
130
|
+
attr_reader :absolute_path
|
131
|
+
# (String) A normalised form of #path that can be used in comparisons
|
132
|
+
attr_reader :compare_path
|
133
|
+
# (String) The entry's directory (excluding the #drive if on Windows)
|
134
|
+
attr_reader :directory
|
135
|
+
# (String) The full path of the entry's directory
|
136
|
+
attr_reader :directory_path
|
137
|
+
alias_method :dirname, :directory_path
|
138
|
+
# ([String]) An array of directory parts, where each part ends in the path name separator
|
139
|
+
attr_reader :directory_parts
|
140
|
+
# (String) The entry's file name (combination of #stem + #extension)
|
141
|
+
attr_reader :file_full_name
|
142
|
+
alias_method :basename, :file_full_name
|
143
|
+
# (String) The entry's file stem
|
144
|
+
attr_reader :file_name_only
|
145
|
+
alias_method :stem, :file_name_only
|
146
|
+
# (String) The entry's file extension
|
147
|
+
attr_reader :file_extension
|
148
|
+
alias_method :extension, :file_extension
|
149
|
+
# (String) The search directory if specified; +nil+ otherwise
|
150
|
+
attr_reader :search_directory
|
151
|
+
# (String) The #path relative to #search_directory; +nil+ if no search directory specified
|
152
|
+
attr_reader :search_relative_path
|
153
|
+
# (String) The #directory_path relative to #search_directory; +nil+ if no search directory specified
|
154
|
+
attr_reader :search_relative_directory_path
|
155
|
+
# ([String]) The #directory_parts relative to #search_directory; +nil+ if no search directory specified
|
156
|
+
attr_reader :search_relative_directory_parts
|
157
|
+
|
158
|
+
# (String) String form of path
|
159
|
+
def to_s
|
160
|
+
|
161
|
+
absolute_path
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end # module Unix
|
166
|
+
end # module Path
|
167
|
+
end # module LibPath
|
168
|
+
|
169
|
+
# ############################## end of file ############################# #
|
170
|
+
|
@@ -0,0 +1,176 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: libpath/path/windows.rb
|
4
|
+
#
|
5
|
+
# Purpose: LibPath::Path::Windows module
|
6
|
+
#
|
7
|
+
# Created: 21st 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
|
+
require 'libpath/diagnostics'
|
52
|
+
require 'libpath/internal_/windows/form'
|
53
|
+
require 'libpath/util/windows'
|
54
|
+
|
55
|
+
module LibPath # :nodoc:
|
56
|
+
module Path # :nodoc:
|
57
|
+
module Windows # :nodoc:
|
58
|
+
|
59
|
+
# Class representing a parsed path (for Windows)
|
60
|
+
class ParsedPath
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
module ParsedPath_Constants # :nodoc: all
|
64
|
+
|
65
|
+
INIT_VALID_OPTIONS = %i{ home locator pwd }
|
66
|
+
INIT_MPA_COMMON_OPTIONS = %i{ home locator pwd }
|
67
|
+
INIT_DRP_COMMON_OPTIONS = %i{ home locator pwd }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Initialises an instance from the given +path+, optional
|
71
|
+
# +search_directory+ and options
|
72
|
+
#
|
73
|
+
# === Signature
|
74
|
+
#
|
75
|
+
# * *Parameters:*
|
76
|
+
# - +path+ (String) The path. May not be +nil+
|
77
|
+
# - +search_directory+ (String) The search_directory, from which the relative attributes are calculated for the path. May be +nil+
|
78
|
+
# - +options+ (Hash) Options
|
79
|
+
#
|
80
|
+
# * *Options:*
|
81
|
+
# - +????+
|
82
|
+
#
|
83
|
+
# * *Exceptions:*
|
84
|
+
# - +ArgumentError+ Raised if +path+ is +nil+
|
85
|
+
def initialize path, search_directory = nil, **options
|
86
|
+
|
87
|
+
raise ::ArgumentError, "path may not be nil or empty" if path.nil? || path.empty?
|
88
|
+
|
89
|
+
_Diagnostics = ::LibPath::Diagnostics
|
90
|
+
_Internal_Form = ::LibPath::Internal_::Windows::Form
|
91
|
+
_Util = ::LibPath::Util::Windows
|
92
|
+
_C = ::LibPath::Path::Windows::ParsedPath::ParsedPath_Constants
|
93
|
+
|
94
|
+
_Diagnostics.check_options(options, known: _C::INIT_VALID_OPTIONS)
|
95
|
+
|
96
|
+
|
97
|
+
abs_path = _Util.make_path_absolute(path, make_canonical: true, **options.select { |k| _C::INIT_MPA_COMMON_OPTIONS.include?(k) })
|
98
|
+
|
99
|
+
splits = _Internal_Form.split_path(abs_path)
|
100
|
+
|
101
|
+
_, f1_vol, f2_dir, f3_basename, f4_stem, f5_ext, f6_dir_parts, f7_abs_parts = *splits
|
102
|
+
|
103
|
+
@given_path = path
|
104
|
+
@absolute_path = abs_path
|
105
|
+
@compare_path = _Util.make_compare_path abs_path, splits: splits
|
106
|
+
@volume = f1_vol
|
107
|
+
@directory = f2_dir
|
108
|
+
@directory_path = "#{f1_vol}#{f2_dir}"
|
109
|
+
@directory_parts = f6_dir_parts
|
110
|
+
|
111
|
+
@file_full_name = f3_basename
|
112
|
+
@file_name_only = f4_stem
|
113
|
+
@file_extension = f5_ext
|
114
|
+
|
115
|
+
if search_directory
|
116
|
+
|
117
|
+
drp_options = options.select { |k| _C::INIT_DRP_COMMON_OPTIONS.include?(k) }
|
118
|
+
|
119
|
+
search_directory = _Util.make_path_canonical search_directory, make_slashes_canonical: true
|
120
|
+
search_directory = _Internal_Form.append_trailing_slash search_directory
|
121
|
+
|
122
|
+
@search_directory = search_directory
|
123
|
+
@search_relative_path = _Util.derive_relative_path(search_directory, abs_path, **drp_options)
|
124
|
+
@search_relative_path = _Internal_Form.append_trailing_slash(@search_relative_path) if _Internal_Form.char_is_path_name_separator?(abs_path[-1])
|
125
|
+
@search_relative_directory_path = _Internal_Form.append_trailing_slash _Util.derive_relative_path(search_directory, "#{f1_vol}#{f2_dir}", **drp_options)
|
126
|
+
@search_relative_directory_parts = @search_relative_directory_path.split('\\').map { |v| v + '\\' }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# (String) The path given to initialise the instance
|
131
|
+
attr_reader :given_path
|
132
|
+
# (String) The full-path of the instance
|
133
|
+
attr_reader :absolute_path
|
134
|
+
# (String) A normalised form of #path that can be used in comparisons
|
135
|
+
attr_reader :compare_path
|
136
|
+
# (String) The Windows volume, which may be a drive, or a UNC specification
|
137
|
+
attr_reader :volume
|
138
|
+
# (String) The entry's directory (excluding the #drive if on Windows)
|
139
|
+
attr_reader :directory
|
140
|
+
# (String) The full path of the entry's directory (taking into account the
|
141
|
+
# #drive if on Windows)
|
142
|
+
attr_reader :directory_path
|
143
|
+
alias_method :dirname, :directory_path
|
144
|
+
# ([String]) An array of directory parts, where each part ends in the path name separator
|
145
|
+
attr_reader :directory_parts
|
146
|
+
# (String) The entry's file name (combination of #stem + #extension)
|
147
|
+
attr_reader :file_full_name
|
148
|
+
alias_method :basename, :file_full_name
|
149
|
+
# (String) The entry's file stem
|
150
|
+
attr_reader :file_name_only
|
151
|
+
alias_method :stem, :file_name_only
|
152
|
+
# (String) The entry's file extension
|
153
|
+
attr_reader :file_extension
|
154
|
+
alias_method :extension, :file_extension
|
155
|
+
# (String) The search directory if specified; +nil+ otherwise
|
156
|
+
attr_reader :search_directory
|
157
|
+
# (String) The #path relative to #search_directory; +nil+ if no search directory specified
|
158
|
+
attr_reader :search_relative_path
|
159
|
+
# (String) The #directory_path relative to #search_directory; +nil+ if no search directory specified
|
160
|
+
attr_reader :search_relative_directory_path
|
161
|
+
# ([String]) The #directory_parts relative to #search_directory; +nil+ if no search directory specified
|
162
|
+
attr_reader :search_relative_directory_parts
|
163
|
+
|
164
|
+
# (String) String form of path
|
165
|
+
def to_s
|
166
|
+
|
167
|
+
absolute_path
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end # module Windows
|
172
|
+
end # module Path
|
173
|
+
end # module LibPath
|
174
|
+
|
175
|
+
# ############################## end of file ############################# #
|
176
|
+
|
data/lib/libpath/util.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'libpath/internal_/platform'
|
3
|
+
|
4
|
+
if ::LibPath::Internal_::Platform::Constants::PLATFORM_IS_WINDOWS then
|
5
|
+
|
6
|
+
require 'libpath/util/windows'
|
7
|
+
else
|
8
|
+
|
9
|
+
require 'libpath/util/unix'
|
10
|
+
end
|
11
|
+
|
12
|
+
module LibPath # :nodoc:
|
13
|
+
module Util # :nodoc:
|
14
|
+
|
15
|
+
if ::LibPath::Internal_::Platform::Constants::PLATFORM_IS_WINDOWS then
|
16
|
+
|
17
|
+
extend ::LibPath::Util::Windows
|
18
|
+
include ::LibPath::Util::Windows
|
19
|
+
else
|
20
|
+
|
21
|
+
extend ::LibPath::Util::Unix
|
22
|
+
include ::LibPath::Util::Unix
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!visibility private
|
26
|
+
def self.extended receiver # :nodoc:
|
27
|
+
|
28
|
+
$stderr.puts "#{receiver} extended by #{self}" if $DEBUG
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
def self.included receiver # :nodoc:
|
33
|
+
|
34
|
+
$stderr.puts "#{receiver} included #{self}" if $DEBUG
|
35
|
+
end
|
36
|
+
|
37
|
+
end # module Util
|
38
|
+
end # module LibPath
|
39
|
+
|
40
|
+
# ############################## end of file ############################# #
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,414 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: libpath/util/unix.rb
|
4
|
+
#
|
5
|
+
# Purpose: LibPath::Util::Unix module
|
6
|
+
#
|
7
|
+
# Created: 14th 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/unix'
|
54
|
+
require 'libpath/internal_/array'
|
55
|
+
require 'libpath/internal_/unix/form'
|
56
|
+
|
57
|
+
module LibPath # :nodoc:
|
58
|
+
module Util # :nodoc:
|
59
|
+
module Unix # :nodoc:
|
60
|
+
|
61
|
+
# Module defining instance functions that will be included and extended into
|
62
|
+
# any class or module including/extending module LibPath::Util::Unix
|
63
|
+
module LibPath_Util_Unix_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
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
69
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
70
|
+
def combine_paths *args, **options
|
71
|
+
|
72
|
+
_Form_Unix = Form::Unix
|
73
|
+
_Internal_Unix_Form = Internal_::Unix::Form
|
74
|
+
|
75
|
+
args.each_with_index { |arg, index| Diagnostics.check_string_parameter(arg, "arg#{index}", allow_nil: true) } if $DEBUG
|
76
|
+
|
77
|
+
if options[:elide_single_dots]
|
78
|
+
|
79
|
+
args = args.map do |arg|
|
80
|
+
|
81
|
+
case arg
|
82
|
+
when '.', './'
|
83
|
+
|
84
|
+
nil
|
85
|
+
else
|
86
|
+
|
87
|
+
arg
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
args = args.reject { |arg| arg.nil? || arg.empty? }
|
93
|
+
|
94
|
+
case args.size
|
95
|
+
when 0
|
96
|
+
|
97
|
+
''
|
98
|
+
when 1
|
99
|
+
|
100
|
+
args[0]
|
101
|
+
else
|
102
|
+
|
103
|
+
rix = args.rindex { |arg| arg && _Form_Unix.path_is_absolute?(arg) }
|
104
|
+
rix ||= 0
|
105
|
+
|
106
|
+
els = args[rix..-1]
|
107
|
+
|
108
|
+
File.join(*els)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Obtains the form of the given +path+ relative to the given +origin+
|
113
|
+
#
|
114
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
115
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
116
|
+
#
|
117
|
+
# === Signature
|
118
|
+
#
|
119
|
+
# * *Options:*
|
120
|
+
# +:home+:: (String)
|
121
|
+
# +:locator+:: (boolean)
|
122
|
+
# +:pwd+:: (String)
|
123
|
+
def derive_relative_path origin, path, **options
|
124
|
+
|
125
|
+
return path if origin.nil? || origin.empty?
|
126
|
+
return path if path.nil? || path.empty?
|
127
|
+
|
128
|
+
_Form_Unix = Form::Unix
|
129
|
+
_Util_Unix = Util::Unix
|
130
|
+
_Internal_Unix_Form = Internal_::Unix::Form
|
131
|
+
|
132
|
+
_MPA_COMMON_OPTIONS = %i{ home locator pwd }
|
133
|
+
|
134
|
+
tr_sl = _Internal_Unix_Form.get_trailing_slash(path)
|
135
|
+
|
136
|
+
origin = _Util_Unix.make_path_canonical(origin)
|
137
|
+
path = _Util_Unix.make_path_canonical(path)
|
138
|
+
|
139
|
+
return '.' + tr_sl.to_s if origin == path
|
140
|
+
return path if '.' == origin || './' == origin
|
141
|
+
|
142
|
+
o_is_abs = _Form_Unix.path_is_absolute?(origin)
|
143
|
+
p_is_abs = _Form_Unix.path_is_absolute?(path)
|
144
|
+
|
145
|
+
if o_is_abs != p_is_abs || './' == path
|
146
|
+
|
147
|
+
origin = _Util_Unix.make_path_absolute(origin, make_canonical: true, **options.select { |k| _MPA_COMMON_OPTIONS.include?(k) })
|
148
|
+
path = _Util_Unix.make_path_absolute(path, make_canonical: true, **options.select { |k| _MPA_COMMON_OPTIONS.include?(k) })
|
149
|
+
end
|
150
|
+
|
151
|
+
origin = _Internal_Unix_Form.trim_trailing_slash(origin) unless origin.size < 2
|
152
|
+
path = _Internal_Unix_Form.trim_trailing_slash(path) if tr_sl && path.size > 1
|
153
|
+
|
154
|
+
|
155
|
+
_, _, _, o3_basename, _, _, o6_parts, _ = _Internal_Unix_Form.split_path(origin)
|
156
|
+
_, _, _, p3_basename, _, _, p6_parts, _ = _Internal_Unix_Form.split_path(path)
|
157
|
+
|
158
|
+
o_parts = o6_parts
|
159
|
+
o_parts << o3_basename if o3_basename && '.' != o3_basename
|
160
|
+
|
161
|
+
p_parts = p6_parts
|
162
|
+
p_parts << p3_basename if p3_basename && '.' != p3_basename
|
163
|
+
|
164
|
+
|
165
|
+
while true
|
166
|
+
|
167
|
+
break if o_parts.empty?
|
168
|
+
break if p_parts.empty?
|
169
|
+
|
170
|
+
o_part = o_parts[0]
|
171
|
+
p_part = p_parts[0]
|
172
|
+
|
173
|
+
if 1 == o_parts.size || 1 == p_parts.size
|
174
|
+
|
175
|
+
o_part = _Internal_Unix_Form.append_trailing_slash o_part
|
176
|
+
p_part = _Internal_Unix_Form.append_trailing_slash p_part
|
177
|
+
end
|
178
|
+
|
179
|
+
if o_part == p_part
|
180
|
+
|
181
|
+
o_parts.shift
|
182
|
+
p_parts.shift
|
183
|
+
else
|
184
|
+
|
185
|
+
break
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
return '.' + tr_sl.to_s if 0 == (o_parts.size + p_parts.size)
|
191
|
+
|
192
|
+
return o_parts.map { |rp| '..' }.join('/') + (tr_sl || (o_parts.size != 0 ? '/' : nil)).to_s if p_parts.empty?
|
193
|
+
|
194
|
+
|
195
|
+
ar = [ '..' ] * o_parts.size + p_parts
|
196
|
+
last = ar.pop
|
197
|
+
ar = ar.map { |el| _Internal_Unix_Form.append_trailing_slash(el) }
|
198
|
+
|
199
|
+
ar.join + last.to_s + tr_sl.to_s
|
200
|
+
end
|
201
|
+
|
202
|
+
# Returns a "compare path" for the given absolute path
|
203
|
+
#
|
204
|
+
# A compare path is one that would refer definitely to a given entry,
|
205
|
+
# regardless of such operating system-specific issues such as
|
206
|
+
# case-insensitivity
|
207
|
+
#
|
208
|
+
# NOTE: the function does not make +path+ absolute. That is up to the
|
209
|
+
# caller if required
|
210
|
+
#
|
211
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
212
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
213
|
+
#
|
214
|
+
# === Signature
|
215
|
+
#
|
216
|
+
# * *Parameters:*
|
217
|
+
# - +path+:: (String) The path whose definitive equivalent is to be
|
218
|
+
# obtained
|
219
|
+
# - +options+:: (Hash) options
|
220
|
+
#
|
221
|
+
# * *Options:*
|
222
|
+
# For reasons of compatibility (with the Windows version) no options
|
223
|
+
# are currently supported; none are proscribed.
|
224
|
+
def make_compare_path path, **options
|
225
|
+
|
226
|
+
path
|
227
|
+
end
|
228
|
+
|
229
|
+
#
|
230
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
231
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
232
|
+
#
|
233
|
+
# === Signature
|
234
|
+
#
|
235
|
+
# * *Parameters:*
|
236
|
+
# - +path+:: (String) The path to be evaluated. May not be +nil+
|
237
|
+
# - +options+:: (Hash) Options that moderate the behaviour of the
|
238
|
+
# function
|
239
|
+
#
|
240
|
+
# * *Options:*
|
241
|
+
# - +:home+:: (String) A specific home to assume, which means that the
|
242
|
+
# +locator+'s +home+ method will not be invoked
|
243
|
+
# - +:locator+:: (object) An object that provides the methods
|
244
|
+
# +pwd+ and +home+, as needed. This allows for mocking. If not
|
245
|
+
# given, then the functions +Dir::pwd+ and +Dir::home+ are used
|
246
|
+
# - +:make_canonical+:: (boolean) Determines whether canonicalisation
|
247
|
+
# is conducted on the result
|
248
|
+
# - +:pwd+:: (String) A specific directory to assume, which means that
|
249
|
+
# the +locator+'s +pwd+ method will not be invoked
|
250
|
+
def make_path_absolute path, **options
|
251
|
+
|
252
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
253
|
+
Diagnostics.check_options(options, known: %i{ home locator make_canonical pwd }) if $DEBUG
|
254
|
+
|
255
|
+
return path if path.nil? || path.empty?
|
256
|
+
|
257
|
+
r = nil
|
258
|
+
|
259
|
+
case path[0]
|
260
|
+
when '/'
|
261
|
+
|
262
|
+
r = path
|
263
|
+
when '~'
|
264
|
+
|
265
|
+
case path[1]
|
266
|
+
when nil, '/'
|
267
|
+
|
268
|
+
home = nil
|
269
|
+
home ||= options[:home]
|
270
|
+
home ||= options[:locator].home if options.has_key?(:locator)
|
271
|
+
home ||= Dir.home
|
272
|
+
|
273
|
+
r = File.join(home, path[2..-1].to_s)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
unless r
|
278
|
+
|
279
|
+
pwd = nil
|
280
|
+
pwd ||= options[:pwd]
|
281
|
+
pwd ||= options[:locator].pwd if options.has_key?(:locator)
|
282
|
+
pwd ||= Dir.pwd
|
283
|
+
|
284
|
+
r = File.join(pwd, path)
|
285
|
+
end
|
286
|
+
|
287
|
+
r ||= path
|
288
|
+
|
289
|
+
r = make_path_canonical r if options[:make_canonical]
|
290
|
+
|
291
|
+
return r
|
292
|
+
end
|
293
|
+
|
294
|
+
# Converts a path into canonical form, which is to say that all possible
|
295
|
+
# dots directory parts are removed:
|
296
|
+
#
|
297
|
+
# - single-dot (trailing) parts - '???/.' are converted to '???/' (where
|
298
|
+
# ??? represents 0+ other characters);
|
299
|
+
# - single-dot parts - './' - are all removed
|
300
|
+
# - double-dot parts - '../' - are removed where they follow a non-dots
|
301
|
+
# directory part, or where they follow the root
|
302
|
+
#
|
303
|
+
# NOTE: The behaviour of this method is undefined if any of the parts
|
304
|
+
# are malformed. See +::LibPath::Form::Windows::name_is_malformed?+
|
305
|
+
#
|
306
|
+
# === Signature
|
307
|
+
#
|
308
|
+
# * *Parameters:*
|
309
|
+
# - +path+:: (String) The path to be evaluated. May not be +nil+
|
310
|
+
def make_path_canonical path, **options
|
311
|
+
|
312
|
+
Diagnostics.check_string_parameter(path, "path") if $DEBUG
|
313
|
+
|
314
|
+
return path unless '.' == path[-1] || path.include?('./') || path.include?('//')
|
315
|
+
|
316
|
+
_Form = ::LibPath::Internal_::Unix::Form
|
317
|
+
_Array = ::LibPath::Internal_::Array
|
318
|
+
|
319
|
+
path = path[0...-1] if '.' == path[-1] && '/' == path[-2]
|
320
|
+
|
321
|
+
|
322
|
+
f0_path, _, f2_dir, f3_basename, _, _, f6_dir_parts, _ = _Form.split_path path
|
323
|
+
|
324
|
+
if f6_dir_parts.empty?
|
325
|
+
|
326
|
+
case f3_basename
|
327
|
+
when '.'
|
328
|
+
|
329
|
+
return './'
|
330
|
+
when '..'
|
331
|
+
|
332
|
+
return '../'
|
333
|
+
else
|
334
|
+
|
335
|
+
return f0_path
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
case f3_basename
|
340
|
+
when '.', '..'
|
341
|
+
|
342
|
+
f6_dir_parts << f3_basename + '/'
|
343
|
+
basename = nil
|
344
|
+
else
|
345
|
+
|
346
|
+
basename = f3_basename
|
347
|
+
end
|
348
|
+
|
349
|
+
is_rooted = '/' == f2_dir[0]
|
350
|
+
|
351
|
+
new_parts = f6_dir_parts.dup
|
352
|
+
new_parts.reject! { |p| './' == p }
|
353
|
+
ix_nodots = new_parts.index { |p| '../' != p } || new_parts.size
|
354
|
+
ix_2dots = _Array.index(new_parts, '../', ix_nodots)
|
355
|
+
|
356
|
+
return "#{new_parts.join}#{basename}" unless new_parts.size != f6_dir_parts.size || ix_2dots
|
357
|
+
|
358
|
+
while (ix_2dots || 0) > 0
|
359
|
+
|
360
|
+
new_parts.delete_at(ix_2dots - 0)
|
361
|
+
new_parts.delete_at(ix_2dots - 1) if ix_2dots != 1 || !is_rooted
|
362
|
+
|
363
|
+
ix_nodots = new_parts.index { |p| '../' != p } or break
|
364
|
+
ix_2dots = _Array.index(new_parts, '../', ix_nodots)
|
365
|
+
end
|
366
|
+
|
367
|
+
if new_parts.empty? && (basename || '').empty?
|
368
|
+
|
369
|
+
case f3_basename
|
370
|
+
when nil, '.', '..'
|
371
|
+
|
372
|
+
return './'
|
373
|
+
else
|
374
|
+
|
375
|
+
return '.'
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
return new_parts.join('') + basename.to_s
|
380
|
+
end
|
381
|
+
end # module LibPath_Util_Unix_Methods
|
382
|
+
|
383
|
+
# @!visibility private
|
384
|
+
def self.extended receiver # :nodoc:
|
385
|
+
|
386
|
+
receiver.class_eval do
|
387
|
+
|
388
|
+
extend LibPath_Util_Unix_Methods
|
389
|
+
end
|
390
|
+
|
391
|
+
$stderr.puts "#{receiver} extended by #{LibPath_Util_Unix_Methods}" if $DEBUG
|
392
|
+
end
|
393
|
+
|
394
|
+
# @!visibility private
|
395
|
+
def self.included receiver # :nodoc:
|
396
|
+
|
397
|
+
receiver.class_eval do
|
398
|
+
|
399
|
+
include LibPath_Util_Unix_Methods
|
400
|
+
end
|
401
|
+
|
402
|
+
$stderr.puts "#{receiver} included #{LibPath_Util_Unix_Methods}" if $DEBUG
|
403
|
+
end
|
404
|
+
|
405
|
+
extend LibPath_Util_Unix_Methods
|
406
|
+
include LibPath_Util_Unix_Methods
|
407
|
+
|
408
|
+
end # module Unix
|
409
|
+
end # module Util
|
410
|
+
end # module LibPath
|
411
|
+
|
412
|
+
# ############################## end of file ############################# #
|
413
|
+
|
414
|
+
|