recls-ruby 2.12.0 → 2.12.0.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +27 -24
  3. data/README.md +242 -1
  4. data/examples/find_files_and_directories.md +33 -30
  5. data/examples/find_files_and_directories.recursive.md +255 -254
  6. data/examples/show_hidden_files.md +4 -1
  7. data/examples/show_hidden_files.rb +1 -1
  8. data/examples/show_readonly_files.md +4 -1
  9. data/examples/show_readonly_files.rb +1 -1
  10. data/lib/recls/api.rb +76 -73
  11. data/lib/recls/combine_paths_1.rb +26 -23
  12. data/lib/recls/combine_paths_2plus.rb +32 -29
  13. data/lib/recls/entry.rb +277 -273
  14. data/lib/recls/file_search.rb +194 -193
  15. data/lib/recls/flags.rb +48 -45
  16. data/lib/recls/foreach.rb +105 -98
  17. data/lib/recls/obsolete.rb +85 -79
  18. data/lib/recls/recls.rb +19 -24
  19. data/lib/recls/stat.rb +137 -134
  20. data/lib/recls/util.rb +95 -92
  21. data/lib/recls/version.rb +22 -17
  22. data/lib/recls/ximpl/os.rb +49 -48
  23. data/lib/recls/ximpl/unix.rb +41 -38
  24. data/lib/recls/ximpl/util.rb +600 -599
  25. data/lib/recls/ximpl/windows.rb +142 -139
  26. data/lib/recls.rb +10 -9
  27. data/test/scratch/test_display_parts.rb +33 -33
  28. data/test/scratch/test_entry.rb +6 -6
  29. data/test/scratch/test_files_and_directories.rb +8 -8
  30. data/test/scratch/test_foreach.rb +10 -10
  31. data/test/scratch/test_module_function.rb +33 -33
  32. data/test/scratch/test_pattern_arrays.rb +5 -5
  33. data/test/scratch/test_show_dev_and_ino.rb +1 -1
  34. data/test/scratch/test_show_hidden.rb +3 -3
  35. data/test/unit/tc_recls_entries.rb +31 -31
  36. data/test/unit/tc_recls_entry.rb +19 -19
  37. data/test/unit/tc_recls_file_search.rb +32 -32
  38. data/test/unit/tc_recls_module.rb +25 -25
  39. data/test/unit/tc_recls_util.rb +161 -161
  40. data/test/unit/tc_recls_ximpl_util.rb +676 -676
  41. data/test/unit/test_all_separately.sh +1 -1
  42. data/test/unit/ts_all.rb +4 -4
  43. metadata +7 -7
data/lib/recls/entry.rb CHANGED
@@ -1,14 +1,14 @@
1
- # ######################################################################### #
2
- # File: recls/entry.rb
1
+ # ######################################################################## #
2
+ # File: recls/entry.rb
3
3
  #
4
- # Purpose: Defines the Recls::Entry class for the recls.Ruby library.
4
+ # Purpose: Defines the Recls::Entry class for the recls.Ruby library.
5
5
  #
6
- # Created: 24th July 2012
7
- # Updated: 25th May 2020
6
+ # Created: 24th July 2012
7
+ # Updated: 20th April 2024
8
8
  #
9
- # Author: Matthew Wilson
9
+ # Author: Matthew Wilson
10
10
  #
11
- # Copyright (c) 2019-2020, Matthew Wilson and Synesis Information Systems
11
+ # Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems
12
12
  # Copyright (c) 2012-2019, Matthew Wilson and Synesis Software
13
13
  # All rights reserved.
14
14
  #
@@ -34,7 +34,7 @@
34
34
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
35
  # POSSIBILITY OF SUCH DAMAGE.
36
36
  #
37
- # ######################################################################### #
37
+ # ######################################################################## #
38
38
 
39
39
 
40
40
  require 'recls/ximpl/os'
@@ -42,357 +42,361 @@ require 'recls/ximpl/' + (Recls::Ximpl::OS::OS_IS_WINDOWS ? 'windows' : 'unix')
42
42
  require 'recls/ximpl/util'
43
43
  require 'recls/flags'
44
44
 
45
+
45
46
  =begin
46
47
  =end
47
48
 
49
+ # @!visibility private
48
50
  class Object; end # :nodoc:
49
51
 
50
52
  module Recls
51
53
 
52
- # A file-system entry
53
- class Entry
54
-
55
- private
56
- # @!visibility private
57
- def self.get_compare_path_(path)
58
- return path.upcase if Recls::Ximpl::OS::OS_IS_WINDOWS
59
- path
60
- end
61
- public
62
-
63
- # initialises an entry instance from the given path,
64
- # file_stat, and search_dir
65
- def initialize(path, file_stat, search_dir, flags)
66
-
67
- @file_stat = file_stat
68
-
69
- @path = Recls::Ximpl.absolute_path path
70
- @short_path = nil
71
- @compare_path = Entry.get_compare_path_ @path
72
- @hash = @compare_path.hash
73
-
74
- windows_drive, directory, basename, file_name, file_ext = Recls::Ximpl::Util.split_path @path
75
-
76
- @drive = windows_drive
77
- @directory_path = "#{windows_drive}#{directory}"
78
- @directory = directory ? directory : ''
79
- @directory_parts = Recls::Ximpl.directory_parts_from_directory directory
80
- @file_full_name = basename ? basename : ''
81
- @file_short_name = nil
82
- @file_name_only = file_name ? file_name : ''
83
- @file_extension = file_ext ? file_ext : ''
84
-
85
- @search_directory = search_dir
86
- @search_relative_path = Recls::Ximpl.derive_relative_path search_dir, @path
87
- @search_relative_directory_path = Recls::Ximpl.derive_relative_path search_dir, @directory_path
88
- @search_relative_directory = @search_relative_directory_path
89
- @search_relative_directory_parts = Recls::Ximpl.directory_parts_from_directory @search_relative_directory
90
-
91
- if 0 != (Recls::MARK_DIRECTORIES & flags) && directory?
92
- @path = Recls::Ximpl::Util.append_trailing_slash @path
93
- @search_relative_path = Recls::Ximpl::Util.append_trailing_slash @search_relative_path
94
- end
95
-
96
- @dev = @file_stat.dev if @file_stat
97
- @ino = @file_stat.ino if @file_stat
98
- @nlink = @file_stat.nlink if @file_stat
99
-
100
- if Recls::Ximpl::OS::OS_IS_WINDOWS && @file_stat
101
-
102
- @dev = @file_stat.by_handle_information.volume_id
103
- @ino = @file_stat.by_handle_information.file_index
104
- @nlink = @file_stat.by_handle_information.num_links
105
- @short_path = @file_stat.short_path
106
- @file_short_name = Recls::Ximpl::Util.split_path(@short_path)[2]
107
- else
108
- end
109
- end
110
-
111
- # ##########################
112
- # Name-related attributes
113
-
114
- # (String) A normalised form of #path that can be used in comparisons
115
- attr_reader :compare_path
116
-
117
- # (String) The full-path of the instance
118
- attr_reader :path
119
- # (String) The (Windows) short-form of #path, or +nil+ if not on Windows
120
- attr_reader :short_path
121
- # (String) The (Windows) drive. +nil+ if does not exist
122
- attr_reader :drive
123
- # (String) The full path of the entry's directory (taking into account the
124
- # #drive if on Windows)
125
- attr_reader :directory_path
126
- alias_method :dirname, :directory_path
127
- # (String) The entry's directory (excluding the #drive if on Windows)
128
- attr_reader :directory
129
- # ([String]) An array of directory parts, where each part ends in Recls::PATH_NAME_SEPARATOR
130
- attr_reader :directory_parts
131
- # (String) The entry's file name (combination of #stem + #extension)
132
- attr_reader :file_full_name
133
- # (String) The (Windows) short-form of #basename, or +nil+ if not on Windows
134
- attr_reader :file_short_name
135
- alias_method :basename, :file_full_name
136
- # (String) The entry's file stem
137
- attr_reader :file_name_only
138
- alias_method :stem, :file_name_only
139
- # (String) The entry's file extension
140
- attr_reader :file_extension
141
- alias_method :extension, :file_extension
142
- # (String) The search directory if specified; +nil+ otherwise
143
- attr_reader :search_directory
144
- # (String) The #path relative to #search_directory; +nil+ if no search directory specified
145
- attr_reader :search_relative_path
146
- # (String) The #directory relative to #search_directory; +nil+ if no search directory specified
147
- attr_reader :search_relative_directory
148
- # (String) The #directory_path relative to #search_directory; +nil+ if no search directory specified
149
- attr_reader :search_relative_directory_path
150
- # ([String]) The #directory_parts relative to #search_directory; +nil+ if no search directory specified
151
- attr_reader :search_relative_directory_parts
54
+ # A file-system entry
55
+ class Entry
56
+
57
+ private
58
+ # @!visibility private
59
+ def self.get_compare_path_(path)
60
+ return path.upcase if Recls::Ximpl::OS::OS_IS_WINDOWS
61
+ path
62
+ end
63
+ public
64
+
65
+ # initialises an entry instance from the given path,
66
+ # file_stat, and search_dir
67
+ def initialize(path, file_stat, search_dir, flags)
68
+
69
+ @file_stat = file_stat
70
+
71
+ @path = Recls::Ximpl.absolute_path path
72
+ @short_path = nil
73
+ @compare_path = Entry.get_compare_path_ @path
74
+ @hash = @compare_path.hash
75
+
76
+ windows_drive, directory, basename, file_name, file_ext = Recls::Ximpl::Util.split_path @path
77
+
78
+ @drive = windows_drive
79
+ @directory_path = "#{windows_drive}#{directory}"
80
+ @directory = directory ? directory : ''
81
+ @directory_parts = Recls::Ximpl.directory_parts_from_directory directory
82
+ @file_full_name = basename ? basename : ''
83
+ @file_short_name = nil
84
+ @file_name_only = file_name ? file_name : ''
85
+ @file_extension = file_ext ? file_ext : ''
86
+
87
+ @search_directory = search_dir
88
+ @search_relative_path = Recls::Ximpl.derive_relative_path search_dir, @path
89
+ @search_relative_directory_path = Recls::Ximpl.derive_relative_path search_dir, @directory_path
90
+ @search_relative_directory = @search_relative_directory_path
91
+ @search_relative_directory_parts = Recls::Ximpl.directory_parts_from_directory @search_relative_directory
92
+
93
+ if 0 != (Recls::MARK_DIRECTORIES & flags) && directory?
94
+ @path = Recls::Ximpl::Util.append_trailing_slash @path
95
+ @search_relative_path = Recls::Ximpl::Util.append_trailing_slash @search_relative_path
96
+ end
97
+
98
+ @dev = @file_stat.dev if @file_stat
99
+ @ino = @file_stat.ino if @file_stat
100
+ @nlink = @file_stat.nlink if @file_stat
101
+
102
+ if Recls::Ximpl::OS::OS_IS_WINDOWS && @file_stat
103
+
104
+ @dev = @file_stat.by_handle_information.volume_id
105
+ @ino = @file_stat.by_handle_information.file_index
106
+ @nlink = @file_stat.by_handle_information.num_links
107
+ @short_path = @file_stat.short_path
108
+ @file_short_name = Recls::Ximpl::Util.split_path(@short_path)[2]
109
+ else
110
+ end
111
+ end
112
+
113
+ # ##########################
114
+ # Name-related attributes
115
+
116
+ # (+String+) A normalised form of #path that can be used in comparisons
117
+ attr_reader :compare_path
118
+
119
+ # (+String+) The full-path of the instance
120
+ attr_reader :path
121
+ # (+String+) The (Windows) short-form of #path, or +nil+ if not on Windows
122
+ attr_reader :short_path
123
+ # (+String+) The (Windows) drive. +nil+ if does not exist
124
+ attr_reader :drive
125
+ # (+String+) The full path of the entry's directory (taking into account the
126
+ # #drive if on Windows)
127
+ attr_reader :directory_path
128
+ alias_method :dirname, :directory_path
129
+ # (+String+) The entry's directory (excluding the #drive if on Windows)
130
+ attr_reader :directory
131
+ # (+[ String ]+) An array of directory parts, where each part ends in Recls::PATH_NAME_SEPARATOR
132
+ attr_reader :directory_parts
133
+ # (+String+) The entry's file name (combination of #stem + #extension)
134
+ attr_reader :file_full_name
135
+ # (+String+) The (Windows) short-form of #basename, or +nil+ if not on Windows
136
+ attr_reader :file_short_name
137
+ alias_method :basename, :file_full_name
138
+ # (+String+) The entry's file stem
139
+ attr_reader :file_name_only
140
+ alias_method :stem, :file_name_only
141
+ # (+String+) The entry's file extension
142
+ attr_reader :file_extension
143
+ alias_method :extension, :file_extension
144
+ # (+String+) The search directory if specified; +nil+ otherwise
145
+ attr_reader :search_directory
146
+ # (+String+) The #path relative to #search_directory; +nil+ if no search directory specified
147
+ attr_reader :search_relative_path
148
+ # (+String+) The #directory relative to #search_directory; +nil+ if no search directory specified
149
+ attr_reader :search_relative_directory
150
+ # (+String+) The #directory_path relative to #search_directory; +nil+ if no search directory specified
151
+ attr_reader :search_relative_directory_path
152
+ # (+[ String ]+) The #directory_parts relative to #search_directory; +nil+ if no search directory specified
153
+ attr_reader :search_relative_directory_parts
154
+
155
+ # ##########################
156
+ # Nature attributes
157
+
158
+ # indicates whether the given entry existed at the time the entry
159
+ # instance was created
160
+ def exist?
161
+
162
+ return false if @file_stat.nil?
152
163
 
153
- # ##########################
154
- # Nature attributes
164
+ not @file_stat.nil?
165
+ end
155
166
 
156
- # indicates whether the given entry existed at the time the entry
157
- # instance was created
158
- def exist?
167
+ # indicates whether the given entry is hidden
168
+ def hidden?
159
169
 
160
- return false if @file_stat.nil?
170
+ return false if @file_stat.nil?
161
171
 
162
- not @file_stat.nil?
163
- end
172
+ @file_stat.hidden?
173
+ end
164
174
 
165
- # indicates whether the given entry is hidden
166
- def hidden?
175
+ # indicates whether the given entry is readonly
176
+ def readonly?
167
177
 
168
- return false if @file_stat.nil?
178
+ return false if @file_stat.nil?
169
179
 
170
- @file_stat.hidden?
171
- end
180
+ not @file_stat.writable?
181
+ end
172
182
 
173
- # indicates whether the given entry is readonly
174
- def readonly?
183
+ if Recls::Ximpl::OS::OS_IS_WINDOWS
175
184
 
176
- return false if @file_stat.nil?
185
+ # [WINDOWS-ONLY] Indicates whether the entry has the *system* bit
186
+ def system?
177
187
 
178
- not @file_stat.writable?
179
- end
188
+ return false if @file_stat.nil?
180
189
 
181
- # ##########################
182
- # Comparison
190
+ @file_stat.system?
191
+ end
183
192
 
184
- if Recls::Ximpl::OS::OS_IS_WINDOWS
193
+ # [WINDOWS-ONLY] Indicates whether the entry has the *archive* bit
194
+ def archive?
185
195
 
186
- # [WINDOWS-ONLY] Indicates whether the entry has the *system* bit
187
- def system?
196
+ return false if @file_stat.nil?
188
197
 
189
- return false if @file_stat.nil?
198
+ @file_stat.archive?
199
+ end
190
200
 
191
- @file_stat.system?
192
- end
201
+ # [WINDOWS-ONLY] Indicates whether the entry is a device
202
+ def device?
193
203
 
194
- # [WINDOWS-ONLY] Indicates whether the entry has the *archive* bit
195
- def archive?
204
+ return false if @file_stat.nil?
196
205
 
197
- return false if @file_stat.nil?
206
+ @file_stat.device?
207
+ end
198
208
 
199
- @file_stat.archive?
200
- end
209
+ # [WINDOWS-ONLY] Indicates whether the entry is *normal*
210
+ def normal?
201
211
 
202
- # [WINDOWS-ONLY] Indicates whether the entry is a device
203
- def device?
212
+ return false if @file_stat.nil?
204
213
 
205
- return false if @file_stat.nil?
214
+ @file_stat.normal?
215
+ end
206
216
 
207
- @file_stat.device?
208
- end
217
+ # [WINDOWS-ONLY] Indicates whether the entry has the *temporary* bit
218
+ def temporary?
209
219
 
210
- # [WINDOWS-ONLY] Indicates whether the entry is *normal*
211
- def normal?
220
+ return false if @file_stat.nil?
212
221
 
213
- return false if @file_stat.nil?
222
+ @file_stat.temporary?
223
+ end
214
224
 
215
- @file_stat.normal?
216
- end
225
+ # [WINDOWS-ONLY] Indicates whether the entry has the *compressed* bit
226
+ def compressed?
217
227
 
218
- # [WINDOWS-ONLY] Indicates whether the entry has the *temporary* bit
219
- def temporary?
228
+ return false if @file_stat.nil?
220
229
 
221
- return false if @file_stat.nil?
230
+ @file_stat.compressed?
231
+ end
222
232
 
223
- @file_stat.temporary?
224
- end
233
+ # [WINDOWS-ONLY] Indicates whether the entry has the *encrypted* bit
234
+ def encrypted?
225
235
 
226
- # [WINDOWS-ONLY] Indicates whether the entry has the *compressed* bit
227
- def compressed?
236
+ return false if @file_stat.nil?
228
237
 
229
- return false if @file_stat.nil?
238
+ @file_stat.encrypted?
239
+ end
240
+ end
230
241
 
231
- @file_stat.compressed?
232
- end
242
+ # indicates whether the given entry represents a directory
243
+ def directory?
233
244
 
234
- # [WINDOWS-ONLY] Indicates whether the entry has the *encrypted* bit
235
- def encrypted?
245
+ return false if @file_stat.nil?
236
246
 
237
- return false if @file_stat.nil?
247
+ @file_stat.directory?
248
+ end
238
249
 
239
- @file_stat.encrypted?
240
- end
241
- end
250
+ alias_method :dir?, :directory?
242
251
 
243
- # indicates whether the given entry represents a directory
244
- def directory?
252
+ # indicates whether the given entry represents a file
253
+ def file?
245
254
 
246
- return false if @file_stat.nil?
255
+ return false if @file_stat.nil?
247
256
 
248
- @file_stat.directory?
249
- end
257
+ @file_stat.file?
258
+ end
250
259
 
251
- alias_method :dir?, :directory?
260
+ # indicates whether the given entry represents a link
261
+ def link?
252
262
 
253
- # indicates whether the given entry represents a file
254
- def file?
263
+ return false if @file_stat.nil?
255
264
 
256
- return false if @file_stat.nil?
265
+ @file_stat.link?
266
+ end
257
267
 
258
- @file_stat.file?
259
- end
268
+ # indicates whether the given entry represents a socket
269
+ def socket?
260
270
 
261
- # indicates whether the given entry represents a link
262
- def link?
271
+ return false if @file_stat.nil?
263
272
 
264
- return false if @file_stat.nil?
273
+ @file_stat.socket?
274
+ end
265
275
 
266
- @file_stat.link?
267
- end
276
+ # ##########################
277
+ # Size attributes
268
278
 
269
- # indicates whether the given entry represents a socket
270
- def socket?
279
+ # indicates the size of the given entry
280
+ def size
271
281
 
272
- return false if @file_stat.nil?
282
+ return 0 if @file_stat.nil?
273
283
 
274
- @file_stat.socket?
275
- end
284
+ @file_stat.size
285
+ end
276
286
 
277
- # ##########################
278
- # Size attributes
287
+ # ##########################
288
+ # File-system entry attributes
279
289
 
280
- # indicates the size of the given entry
281
- def size
290
+ # indicates the device of the given entry
291
+ #
292
+ # On Windows, this will be 0 if the entry cannot be
293
+ # opened
294
+ def dev
282
295
 
283
- return 0 if @file_stat.nil?
296
+ @dev
297
+ end
284
298
 
285
- @file_stat.size
286
- end
299
+ # indicates the ino of the given entry
300
+ #
301
+ # On Windows, this will be 0 if the entry cannot be
302
+ # opened
303
+ def ino
287
304
 
288
- # ##########################
289
- # File-system entry attributes
305
+ @ino
306
+ end
290
307
 
291
- # indicates the device of the given entry
292
- #
293
- # On Windows, this will be 0 if the entry cannot be
294
- # opened
295
- def dev
308
+ # number of links to the given entry
309
+ #
310
+ # On Windows, this will be 0 if the entry cannot be
311
+ # opened
312
+ def nlink
296
313
 
297
- @dev
298
- end
314
+ @nlink
315
+ end
299
316
 
300
- # indicates the ino of the given entry
301
- #
302
- # On Windows, this will be 0 if the entry cannot be
303
- # opened
304
- def ino
317
+ # ##########################
318
+ # Time attributes
305
319
 
306
- @ino
307
- end
320
+ # indicates the last access time of the entry
321
+ def last_access_time
308
322
 
309
- # number of links to the given entry
310
- #
311
- # On Windows, this will be 0 if the entry cannot be
312
- # opened
313
- def nlink
323
+ return nil if @file_stat.nil?
314
324
 
315
- @nlink
316
- end
325
+ @file_stat.atime
326
+ end
317
327
 
318
- # ##########################
319
- # Time attributes
328
+ # indicates the modification time of the entry
329
+ def modification_time
320
330
 
321
- # indicates the last access time of the entry
322
- def last_access_time
331
+ return nil if @file_stat.nil?
323
332
 
324
- return nil if @file_stat.nil?
333
+ @file_stat.mtime
334
+ end
325
335
 
326
- @file_stat.atime
327
- end
336
+ # ##########################
337
+ # Comparison
328
338
 
329
- # indicates the modification time of the entry
330
- def modification_time
339
+ # determines whether rhs is an instance of Entry and
340
+ # refers to the same path
341
+ def eql?(rhs)
331
342
 
332
- return nil if @file_stat.nil?
343
+ case rhs
344
+ when self.class
333
345
 
334
- @file_stat.mtime
335
- end
346
+ return compare_path == rhs.compare_path
347
+ else
336
348
 
337
- # ##########################
338
- # Comparison
349
+ return false
350
+ end
351
+ end
339
352
 
340
- # determines whether rhs is an instance of Entry and
341
- # refers to the same path
342
- def eql?(rhs)
353
+ # determines whether rhs refers to the same path
354
+ def ==(rhs)
343
355
 
344
- case rhs
345
- when self.class
346
- return compare_path == rhs.compare_path
347
- else
348
- return false
349
- end
350
- end
356
+ case rhs
357
+ when String
351
358
 
352
- # determines whether rhs refers to the same path
353
- def ==(rhs)
359
+ return compare_path == Entry.get_compare_path_(rhs)
360
+ when self.class
354
361
 
355
- case rhs
356
- when String
357
- return compare_path == Entry.get_compare_path_(rhs)
358
- when self.class
359
- return compare_path == rhs.compare_path
360
- else
361
- return false
362
- end
363
- end
362
+ return compare_path == rhs.compare_path
363
+ else
364
364
 
365
- # compares this instance with rhs
366
- def <=>(rhs)
365
+ return false
366
+ end
367
+ end
367
368
 
368
- compare_path <=> rhs.compare_path
369
- end
369
+ # compares this instance with rhs
370
+ def <=>(rhs)
370
371
 
371
- # the hash
372
- def hash
372
+ compare_path <=> rhs.compare_path
373
+ end
373
374
 
374
- @hash
375
- end
375
+ # the hash
376
+ def hash
376
377
 
377
- # ##########################
378
- # Conversion
378
+ @hash
379
+ end
379
380
 
380
- # represents the entry as a string (in the form of
381
- # the full path)
382
- def to_s
381
+ # ##########################
382
+ # Conversion
383
383
 
384
- path
385
- end
384
+ # represents the entry as a string (in the form of
385
+ # the full path)
386
+ def to_s
386
387
 
387
- # represents the entry as a string (in the form of
388
- # the full path)
389
- def to_str
388
+ path
389
+ end
390
390
 
391
- path
392
- end
393
- end # class Entry
391
+ # represents the entry as a string (in the form of
392
+ # the full path)
393
+ def to_str
394
+
395
+ path
396
+ end
397
+ end # class Entry
394
398
  end # module Recls
395
399
 
396
- # ############################## end of file ############################# #
397
400
 
401
+ # ############################## end of file ############################# #
398
402