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,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
+