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.
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,53 @@
1
+
2
+ # :stopdoc:
3
+
4
+ module LibPath # :nodoc:
5
+ # @!visibility private
6
+ module Internal_ # :nodoc: all
7
+
8
+ # @!visibility private
9
+ module Platform # :nodoc: all
10
+
11
+ # @!visibility private
12
+ module OS_Internal_ # :nodoc: all
13
+
14
+ # @!visibility private
15
+ def self.win_platform_? # :nodoc:
16
+
17
+ return true if 'Windows_NT' == ENV['OS']
18
+
19
+ [
20
+ 'bccwin',
21
+ 'cygwin',
22
+ 'djgpp',
23
+ 'mingw',
24
+ 'mswin',
25
+ 'wince',
26
+ ].each do |os_name|
27
+
28
+ return true if /#{os_name}/i =~ RUBY_PLATFORM
29
+ end
30
+
31
+ false
32
+ end
33
+
34
+ end # module OS_Internal_
35
+
36
+ # @!visibility private
37
+ module Constants # :nodoc: all
38
+
39
+ # @!visibility private
40
+ PLATFORM_IS_WINDOWS = OS_Internal_.win_platform_? # :nodoc:
41
+
42
+ end # module Constants
43
+
44
+ end # module Platform
45
+
46
+ end # module Internal_
47
+ end # module LibPath
48
+
49
+ # :startdoc:
50
+
51
+ # ############################## end of file ############################# #
52
+
53
+
@@ -0,0 +1,33 @@
1
+
2
+ module LibPath # :nodoc:
3
+ # @!visibility private
4
+ module Internal_ # :nodoc: all
5
+
6
+ module String # :nodoc:
7
+
8
+ # @!visibility private
9
+ def self.rindex2(s, c1, c2) # :nodoc:
10
+
11
+ ri_1 = s.rindex(c1)
12
+ ri_2 = s.rindex(c2)
13
+
14
+ if ri_1
15
+
16
+ if ri_2
17
+
18
+ ri_1 < ri_2 ? ri_2 : ri_1
19
+ else
20
+
21
+ ri_1
22
+ end
23
+ else
24
+
25
+ ri_2
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+
@@ -0,0 +1,160 @@
1
+
2
+ module LibPath # :nodoc:
3
+ # @!visibility private
4
+ module Internal_ # :nodoc: all
5
+ module Unix # :nodoc:
6
+
7
+ module Form # :nodoc:
8
+
9
+ # [INTERNAL] This function is undocumented, and subject to change at any
10
+ # time
11
+ #
12
+ # @!visibility private
13
+ def self.char_is_path_name_separator? c # :nodoc:
14
+
15
+ '/' == c
16
+ end
17
+
18
+ # [INTERNAL] This function is undocumented, and subject to change at any
19
+ # time
20
+ #
21
+ # @!visibility private
22
+ def self.append_trailing_slash s # :nodoc:
23
+
24
+ return s if '/' == s[-1]
25
+
26
+ s + '/'
27
+ end
28
+
29
+ # [INTERNAL] This function is undocumented, and subject to change at any
30
+ # time
31
+ #
32
+ # @!visibility private
33
+ def self.get_trailing_slash s # :nodoc:
34
+
35
+ '/' == s[-1] ? '/' : nil
36
+ end
37
+
38
+ # [INTERNAL] This function is undocumented, and subject to change at any
39
+ # time
40
+ #
41
+ # @!visibility private
42
+ def self.has_trailing_slash? s # :nodoc:
43
+
44
+ '/' == s[-1]
45
+ end
46
+
47
+ # [INTERNAL] This function is undocumented, and subject to change at any
48
+ # time
49
+ #
50
+ # @!visibility private
51
+ def self.trim_trailing_slash s # :nodoc:
52
+
53
+ return s unless '/' == s[-1]
54
+
55
+ s.chop
56
+ end
57
+
58
+ # [INTERNAL] This function is undocumented, and subject to change at any
59
+ # time
60
+ #
61
+ # @!visibility private
62
+ def self.elide_redundant_path_name_separators s # :nodoc:
63
+
64
+ s.gsub(/\/\/+/, '/')
65
+ end
66
+
67
+ # [INTERNAL] This function is undocumented, and subject to change at any
68
+ # time
69
+ #
70
+ # @!visibility private
71
+ def self.elide_redundant_path_name_separators! s # :nodoc:
72
+
73
+ s.gsub!(/\/\/+/, '/')
74
+
75
+ s
76
+ end
77
+
78
+
79
+ # [INTERNAL] This function is undocumented, and subject to change at any
80
+ # time
81
+ #
82
+ # Returns tuple of:
83
+ #
84
+ # 0. source path (with redundant path name separators elided)
85
+ # 1. Windows volume (which is always nil)
86
+ # 2. Directory
87
+ # 3. Basename
88
+ # 4. Stem
89
+ # 5. Extension
90
+ # 6. Directory parts
91
+ # 7. Directory path parts
92
+ #
93
+ # @!visibility private
94
+ def self.split_path s, **options # :nodoc:
95
+
96
+ f2_directory = nil
97
+ f3_basename = nil
98
+ f4_stem = nil
99
+ f5_extension = nil
100
+ f6_dir_parts = []
101
+
102
+ s = self.elide_redundant_path_name_separators s
103
+
104
+ ri_slash = s.rindex('/')
105
+
106
+ if ri_slash
107
+
108
+ f2_directory = s[0..ri_slash]
109
+ f3_basename = s[(1 + ri_slash)..-1]
110
+ else
111
+
112
+ f2_directory = nil
113
+ f3_basename = s
114
+ end
115
+
116
+ case f3_basename
117
+ when '.', '..'
118
+
119
+ f4_stem = f3_basename
120
+ f5_extension = nil
121
+ else
122
+
123
+ ri_dot = f3_basename.rindex('.')
124
+
125
+ if ri_dot
126
+
127
+ f4_stem = f3_basename[0...ri_dot]
128
+ f5_extension = f3_basename[ri_dot..-1]
129
+ else
130
+
131
+ f4_stem = f3_basename
132
+ f5_extension = nil
133
+ end
134
+ end
135
+
136
+ unless options[:suppress_parts]
137
+
138
+ case f2_directory
139
+ when nil
140
+
141
+ ;
142
+ when '/'
143
+
144
+ f6_dir_parts = [ '/' ]
145
+ else
146
+
147
+ f6_dir_parts = f2_directory.split('/').reject { |v| v.empty? }.map { |v| v + '/' }
148
+ f6_dir_parts.unshift('/') if '/' == f2_directory[0]
149
+ end
150
+ end
151
+
152
+
153
+ [ s, nil, f2_directory, f3_basename, f4_stem, f5_extension, f6_dir_parts, f6_dir_parts ].map { |v| ::String === v && v.empty? ? nil : v }
154
+ end
155
+ end # module Form
156
+
157
+ end # module Unix
158
+ end # module Internal_
159
+ end # module LibPath
160
+
@@ -0,0 +1,84 @@
1
+
2
+ module LibPath # :nodoc:
3
+ # @!visibility private
4
+ module Internal_ # :nodoc: all
5
+ module Windows # :nodoc:
6
+ module Drive # :nodoc:
7
+
8
+ module Constants # :nodoc:
9
+
10
+ DRIVE_LETTERS = [
11
+
12
+ 'C',
13
+ 'D',
14
+ 'E',
15
+ 'F',
16
+ 'G',
17
+ 'H',
18
+ 'I',
19
+ 'J',
20
+ 'K',
21
+ 'L',
22
+ 'M',
23
+ 'N',
24
+ 'P',
25
+ 'Q',
26
+ 'R',
27
+ 'S',
28
+ 'T',
29
+ 'U',
30
+ 'V',
31
+ 'W',
32
+ 'I',
33
+ 'X',
34
+ 'Y',
35
+ 'Z',
36
+
37
+ 'c',
38
+ 'd',
39
+ 'e',
40
+ 'f',
41
+ 'g',
42
+ 'h',
43
+ 'i',
44
+ 'j',
45
+ 'k',
46
+ 'l',
47
+ 'm',
48
+ 'n',
49
+ 'p',
50
+ 'q',
51
+ 'r',
52
+ 's',
53
+ 't',
54
+ 'u',
55
+ 'v',
56
+ 'w',
57
+ 'i',
58
+ 'x',
59
+ 'y',
60
+ 'z',
61
+
62
+ 'A',
63
+ 'B',
64
+
65
+ 'a',
66
+ 'b',
67
+
68
+ ]
69
+ end # module Constants
70
+
71
+ # @!visibility private
72
+ def self.character_is_drive_letter? ch # :nodoc:
73
+
74
+ ::LibPath::Internal_::Windows::Drive::Constants::DRIVE_LETTERS.include? ch
75
+ end
76
+
77
+ end # module Drive
78
+ end # module Windows
79
+ end # module Internal_
80
+ end # module LibPath
81
+
82
+ # ############################## end of file ############################# #
83
+
84
+
@@ -0,0 +1,281 @@
1
+
2
+ require 'libpath/internal_/string'
3
+ require 'libpath/internal_/windows/drive'
4
+
5
+ module LibPath # :nodoc:
6
+ # @!visibility private
7
+ module Internal_ # :nodoc: all
8
+ module Windows # :nodoc:
9
+
10
+ module Form # :nodoc:
11
+
12
+ # [INTERNAL] This function is undocumented, and subject to change at any
13
+ # time
14
+ #
15
+ # @!visibility private
16
+ def self.char_is_path_name_separator? c # :nodoc:
17
+
18
+ '/' == c || '\\' == c
19
+ end
20
+
21
+ # [INTERNAL] This function is undocumented, and subject to change at any
22
+ # time
23
+ #
24
+ # @!visibility private
25
+ def self.append_trailing_slash s # :nodoc:
26
+
27
+ return s if self.char_is_path_name_separator?(s[-1])
28
+
29
+ s + '\\'
30
+ end
31
+
32
+ # [INTERNAL] This function is undocumented, and subject to change at any
33
+ # time
34
+ #
35
+ # @!visibility private
36
+ def self.get_trailing_slash s # :nodoc:
37
+
38
+ last = s[-1]
39
+
40
+ self.char_is_path_name_separator?(last) ? last : nil
41
+ end
42
+
43
+ # [INTERNAL] This function is undocumented, and subject to change at any
44
+ # time
45
+ #
46
+ # @!visibility private
47
+ def self.has_trailing_slash? s # :nodoc:
48
+
49
+ self.char_is_path_name_separator?(s[-1])
50
+ end
51
+
52
+ # [INTERNAL] This function is undocumented, and subject to change at any
53
+ # time
54
+ #
55
+ # @!visibility private
56
+ def self.trim_trailing_slash s # :nodoc:
57
+
58
+ return s unless self.char_is_path_name_separator?(s[-1])
59
+
60
+ s.chop
61
+ end
62
+
63
+ # [INTERNAL] This function is undocumented, and subject to change at any
64
+ # time
65
+ #
66
+ # @!visibility private
67
+ def self.elide_redundant_path_name_separators s # :nodoc:
68
+
69
+ s.gsub(/[\\\/]{2,}/, '\\')
70
+ end
71
+
72
+ # [INTERNAL] This function is undocumented, and subject to change at any
73
+ # time
74
+ #
75
+ # @!visibility private
76
+ def self.elide_redundant_path_name_separators! s # :nodoc:
77
+
78
+ s.gsub!(/[\\\/]{2,}/, '\\')
79
+
80
+ s
81
+ end
82
+
83
+ # [INTERNAL] This function is undocumented, and subject to change at any
84
+ # time
85
+ #
86
+ # === Signature
87
+ #
88
+ # * *Parameters:*
89
+ # - +s+ (String)
90
+ #
91
+ # === Return
92
+ # A 3-element array, consisting of [ volume, remainder, form ]
93
+ #
94
+ # @!visibility private
95
+ def self.get_windows_volume s # :nodoc:
96
+
97
+ # 0. not matched
98
+ # 1. X:
99
+ # 2. \\server\share
100
+ # 3. \\?\X:
101
+ # 4. \\?\server\share
102
+ # 5. \\?\UNC\server\share
103
+ # 6. \\.\device
104
+
105
+ if '\\' == s[0]
106
+
107
+ if '\\' == s[1]
108
+
109
+ case s[2]
110
+ when '?'
111
+
112
+ if '\\' == s[3]
113
+
114
+ if ':' == s[5] && ::LibPath::Internal_::Windows::Drive.character_is_drive_letter?(s[4])
115
+
116
+ # 3. \\?\X:
117
+
118
+ return [ s[0..5], s[6..-1], :form_3 ]
119
+ end
120
+
121
+ if 'U' == s[4] && 'N' == s[5] && 'C' == s[6]
122
+
123
+ # 5. \\?\UNC\server\share
124
+
125
+ if s =~ /^\\\\\?\\UNC\\[^\\]+\\[^\\\/]+/
126
+
127
+ return [ $&, $', :form_5 ]
128
+ end
129
+ else
130
+
131
+ if s =~ /^\\\\\?\\[^\\]+\\[^\\\/]+/
132
+
133
+ # 4. \\?\server\share
134
+
135
+ return [ $&, $', :form_4 ]
136
+ end
137
+ end
138
+
139
+ return [ s, '', :malformed ]
140
+ end
141
+ when '.'
142
+
143
+ if s =~ /^\\\\\.\\[^\\]+/
144
+
145
+ # 6. \\.\device
146
+
147
+ return [ $&, $', :form_6 ]
148
+ end
149
+ else
150
+
151
+ if s =~ /^\\\\[^\\]+\\[^\\\/]+/
152
+
153
+ # 2. \\server\share
154
+
155
+ return [ $&, $', :form_2 ]
156
+ end
157
+ end
158
+ else
159
+
160
+ end
161
+ elsif ':' == s[1] && ::LibPath::Internal_::Windows::Drive.character_is_drive_letter?(s[0])
162
+
163
+ # 1. X:
164
+
165
+ return [ s[0..1], s[2..-1], :form_1 ]
166
+ end
167
+
168
+ # 0. not matched
169
+
170
+ [ nil, s, :form_0 ]
171
+ end
172
+
173
+ # [INTERNAL] This function is undocumented, and subject to change at any
174
+ # time
175
+ #
176
+ # Returns tuple of:
177
+ #
178
+ # 0. source path (with redundant path name separators elided)
179
+ # 1. Windows volume (which is always nil)
180
+ # 2. Directory
181
+ # 3. Basename
182
+ # 4. Stem
183
+ # 5. Extension
184
+ # 6. Directory parts
185
+ # 7. Directory path parts
186
+ #
187
+ # @!visibility private
188
+ def self.split_path s # :nodoc:
189
+
190
+ f1_volume = nil
191
+ f2_directory = nil
192
+ f3_basename = nil
193
+ f4_stem = nil
194
+ f5_extension = nil
195
+ f6_dir_parts = []
196
+ f7_all_parts = []
197
+
198
+ f1_volume, rem, frm = self.get_windows_volume s
199
+
200
+ self.elide_redundant_path_name_separators! rem
201
+
202
+ f1_volume.define_singleton_method(:form) { frm } if f1_volume
203
+
204
+ if :malformed == frm
205
+
206
+ return [ s, f1_volume, nil, nil, nil, nil, [], [] ]
207
+ end
208
+
209
+ unless rem.empty?
210
+
211
+ ri_slash = ::LibPath::Internal_::String.rindex2(rem, '/', '\\')
212
+
213
+ if ri_slash
214
+
215
+ f2_directory = rem[0..ri_slash]
216
+ f3_basename = rem[(1 + ri_slash)..-1]
217
+ else
218
+
219
+ f2_directory = nil
220
+ f3_basename = rem
221
+ end
222
+
223
+ case f3_basename
224
+ when '.', '..'
225
+
226
+ f4_stem = f3_basename
227
+ f5_extension = nil
228
+ else
229
+
230
+ ri_dot = f3_basename.rindex('.')
231
+
232
+ if ri_dot
233
+
234
+ f4_stem = f3_basename[0...ri_dot]
235
+ f5_extension = f3_basename[ri_dot..-1]
236
+ else
237
+
238
+ f4_stem = f3_basename
239
+ f5_extension = nil
240
+ end
241
+ end
242
+
243
+ case f2_directory
244
+ when nil
245
+
246
+ ;
247
+ when '\\', '/'
248
+
249
+ f6_dir_parts = [ f2_directory ]
250
+ else
251
+
252
+ parts = f2_directory.split(/([\\\/])/)
253
+
254
+ f6_dir_parts = []
255
+
256
+ (0...(parts.size / 2)).each do |ix|
257
+
258
+ f6_dir_parts << parts[2 * ix + 0] + parts[2 * ix + 1]
259
+ end
260
+ end
261
+
262
+ if f1_volume
263
+
264
+ f7_all_parts = f6_dir_parts.dup
265
+
266
+ f7_all_parts[0] = f1_volume + f7_all_parts[0].to_s
267
+ else
268
+
269
+ f7_all_parts = f6_dir_parts
270
+ end
271
+ end
272
+
273
+
274
+ [ "#{f1_volume}#{rem}", f1_volume, f2_directory, f3_basename, f4_stem, f5_extension, f6_dir_parts, f7_all_parts ].map { |v| ::String === v && v.empty? ? nil : v }
275
+ end
276
+ end # module Form
277
+
278
+ end # module Windows
279
+ end # module Internal_
280
+ end # module LibPath
281
+