build-files 1.9.1 → 1.10.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abffeac84e2e1e1585743ecdc01742332ae8629865701b306b10f1987c6cae8a
4
- data.tar.gz: 03ddfbbc237aa66d472e7cbb108e2e364c0aa95a4ee7b769abcb98c0ba8cb1e4
3
+ metadata.gz: 555dbd01ff6915b1d7a9c11864d95544929e35006094fb0eda4ca7b8d8227006
4
+ data.tar.gz: 6c17197d4bacc772f1e9aed6bce37cfab7ea4dcfb172c07a7ad955dfd8dc25ce
5
5
  SHA512:
6
- metadata.gz: 349d26dd750a8cf993a606502703b22c55b0479ec67b127e64658ac8a44be2ea6a96d0d44bb34751f4a7d1e40659e6af4ce886960ba680b0362316bc02a10a22
7
- data.tar.gz: c93a0c33ec66c7862201b2d386f7133eaa874e3b4b5f87f42da427c21c49cdef6bbc82ad8f642134ed140cf5fecc930ba5fc4476f33ce1d7a9e439ddcc69902f
6
+ metadata.gz: 8078524f809ad559c7c62de94ac98db9e6129e7d97f268fa2440a4732fbd3cba590d37775d9021b5a118c6957b81d87dbfb2321065fcd0eb32e9ab6e099617e8
7
+ data.tar.gz: 951b008d3c8a395024acfa3d83db9dc86cedadb3fbc6af4964f48cf23cc61f4f460eb63df40c7fd89efffaa3f6d6a818f2641a6c49b629d790643b01304c8e49
checksums.yaml.gz.sig CHANGED
Binary file
@@ -7,14 +7,18 @@ require_relative "list"
7
7
 
8
8
  module Build
9
9
  module Files
10
+ # Represents a composite list of files from multiple sources.
10
11
  class Composite < List
12
+ # Initialize a composite list with multiple file lists.
13
+ # @parameter files [Array] The file lists to combine.
14
+ # @parameter roots [Array(Path) | Nil] The root paths, if known.
11
15
  def initialize(files, roots = nil)
12
16
  @files = []
13
17
 
14
18
  files.each do |list|
15
19
  if list.kind_of? Composite
16
20
  @files += list.files
17
- elsif List.kind_of? List
21
+ elsif list.kind_of? List
18
22
  @files << list
19
23
  else
20
24
  # Try to convert into a explicit paths list:
@@ -28,12 +32,16 @@ module Build
28
32
 
29
33
  attr :files
30
34
 
35
+ # Freeze the composite list and its dependencies.
31
36
  def freeze
32
37
  self.roots
33
38
 
34
39
  super
35
40
  end
36
41
 
42
+ # Iterate over all files in the composite list.
43
+ # @yields {|path| ...} Each path in all combined lists.
44
+ # @parameter path [Path] The current file path.
37
45
  def each
38
46
  return to_enum(:each) unless block_given?
39
47
 
@@ -42,18 +50,28 @@ module Build
42
50
  end
43
51
  end
44
52
 
53
+ # Get all root paths for all lists in the composite.
54
+ # @returns [Array(Path)] The unique root paths.
45
55
  def roots
46
56
  @roots ||= @files.collect(&:roots).flatten.uniq
47
57
  end
48
58
 
59
+ # Check equality with another composite list.
60
+ # @parameter other [Composite] The other composite to compare.
61
+ # @returns [Boolean] True if both composites have the same files.
49
62
  def eql?(other)
50
63
  self.class.eql?(other.class) and @files.eql?(other.files)
51
64
  end
52
-
65
+
66
+ # Compute the hash value for this composite.
67
+ # @returns [Integer] The hash value based on files.
53
68
  def hash
54
69
  @files.hash
55
70
  end
56
71
 
72
+ # Combine this composite with another list.
73
+ # @parameter list [List] The list to add.
74
+ # @returns [Composite] A new composite containing both lists.
57
75
  def +(list)
58
76
  if list.kind_of? Composite
59
77
  self.class.new(@files + list.files)
@@ -61,19 +79,29 @@ module Build
61
79
  self.class.new(@files + [list])
62
80
  end
63
81
  end
64
-
82
+
83
+ # Check if the composite includes a specific path.
84
+ # @parameter path [Path] The path to check.
85
+ # @returns [Boolean] True if any list in the composite includes the path.
65
86
  def include?(path)
66
87
  @files.any? {|list| list.include?(path)}
67
88
  end
68
-
89
+
90
+ # Rebase all lists in the composite to a new root.
91
+ # @parameter root [Path] The new root path.
92
+ # @returns [Composite] A new composite with rebased lists.
69
93
  def rebase(root)
70
94
  self.class.new(@files.collect{|list| list.rebase(root)}, [root])
71
95
  end
72
-
96
+
97
+ # Convert all lists in the composite to paths.
98
+ # @returns [Composite] A new composite with all lists converted to paths.
73
99
  def to_paths
74
100
  self.class.new(@files.collect(&:to_paths), roots: @roots)
75
101
  end
76
102
 
103
+ # Generate a string representation for debugging.
104
+ # @returns [String] A debug string showing the composite structure.
77
105
  def inspect
78
106
  "<Composite #{@files.inspect}>"
79
107
  end
@@ -7,7 +7,11 @@ require_relative "list"
7
7
 
8
8
  module Build
9
9
  module Files
10
+ # Represents a list of files with exclusions applied.
10
11
  class Difference < List
12
+ # Initialize a difference list.
13
+ # @parameter list [List] The base list of files.
14
+ # @parameter excludes [List] The list of files to exclude.
11
15
  def initialize(list, excludes)
12
16
  @list = list
13
17
  @excludes = excludes
@@ -15,6 +19,7 @@ module Build
15
19
 
16
20
  attr :files
17
21
 
22
+ # Freeze the difference list and its dependencies.
18
23
  def freeze
19
24
  @list.freeze
20
25
  @excludes.freeze
@@ -22,6 +27,9 @@ module Build
22
27
  super
23
28
  end
24
29
 
30
+ # Iterate over files in the base list, excluding those in the exclusion list.
31
+ # @yields {|path| ...} Each path not in the exclusion list.
32
+ # @parameter path [Path] The current file path.
25
33
  def each
26
34
  return to_enum(:each) unless block_given?
27
35
 
@@ -30,20 +38,31 @@ module Build
30
38
  end
31
39
  end
32
40
 
41
+ # Subtract additional files from this difference.
42
+ # @parameter list [List] Additional files to exclude.
43
+ # @returns [Difference] A new difference with expanded exclusions.
33
44
  def -(list)
34
- self.class.new(@list, Composite.new(@excludes, list))
45
+ self.class.new(@list, Composite.new([@excludes, list]))
35
46
  end
36
47
 
48
+ # Check if the difference includes a specific path.
49
+ # @parameter path [Path] The path to check.
50
+ # @returns [Boolean] True if the path is in the base list but not excluded.
37
51
  def include?(path)
38
- @list.includes?(path) and !@excludes.include?(path)
52
+ @list.include?(path) and !@excludes.include?(path)
39
53
  end
40
54
 
55
+ # Rebase the difference to a new root.
56
+ # @parameter root [Path] The new root path.
57
+ # @returns [Difference] A new difference with rebased files.
41
58
  def rebase(root)
42
- self.class.new(@files.collect{|list| list.rebase(root)}, [root])
59
+ self.class.new(@list.rebase(root), @excludes.rebase(root))
43
60
  end
44
61
 
62
+ # Generate a string representation for debugging.
63
+ # @returns [String] A debug string showing the difference structure.
45
64
  def inspect
46
- "<Difference #{@files.inspect} - #{@excludes.inspect}>"
65
+ "<Difference #{@list.inspect} - #{@excludes.inspect}>"
47
66
  end
48
67
  end
49
68
  end
@@ -7,23 +7,36 @@ require_relative "list"
7
7
 
8
8
  module Build
9
9
  module Files
10
+ # Represents a directory of files.
10
11
  class Directory < List
12
+ # Join path components and create a directory.
13
+ # @parameter args [Array(String)] The path components to join.
14
+ # @returns [Directory] A new directory at the joined path.
11
15
  def self.join(*args)
12
16
  self.new(Path.join(*args))
13
17
  end
14
18
 
19
+ # Initialize a directory with a root path.
20
+ # @parameter root [Path | String] The root path of the directory.
15
21
  def initialize(root)
16
22
  @root = root
17
23
  end
18
24
 
25
+ # Get the root path of the directory.
26
+ # @returns [Path] The root path.
19
27
  def root
20
28
  @root
21
29
  end
22
30
 
31
+ # Get the root paths as an array.
32
+ # @returns [Array(Path)] An array containing the single root path.
23
33
  def roots
24
34
  [root]
25
35
  end
26
36
 
37
+ # Iterate over all files in the directory recursively.
38
+ # @yields {|path| ...} Each file path in the directory.
39
+ # @parameter path [Path] The current file path.
27
40
  def each
28
41
  return to_enum(:each) unless block_given?
29
42
 
@@ -33,32 +46,48 @@ module Build
33
46
  end
34
47
  end
35
48
 
49
+ # Check equality with another directory.
50
+ # @parameter other [Directory] The other directory to compare.
51
+ # @returns [Boolean] True if both directories have the same root.
36
52
  def eql?(other)
37
53
  self.class.eql?(other.class) and @root.eql?(other.root)
38
54
  end
39
55
 
56
+ # Compute the hash value for this directory.
57
+ # @returns [Integer] The hash value based on the root.
40
58
  def hash
41
59
  @root.hash
42
60
  end
43
-
61
+
62
+ # Check if the directory includes a specific path.
63
+ # @parameter path [Path] The path to check.
64
+ # @returns [Boolean] True if the path is within this directory.
44
65
  def include?(path)
45
66
  # Would be true if path is a descendant of full_path.
46
67
  path.start_with?(@root)
47
68
  end
48
-
69
+
70
+ # Rebase the directory to a new root.
71
+ # @parameter root [Path] The new root path.
72
+ # @returns [Directory] A new directory with the rebased root.
49
73
  def rebase(root)
50
74
  self.class.new(@root.rebase(root))
51
75
  end
52
76
 
53
- # Convert a Directory into a String, can be used as an argument to a command.
77
+ # Convert the directory to a string for use as a command argument.
78
+ # @returns [String] The root path as a string.
54
79
  def to_str
55
80
  @root.to_str
56
81
  end
57
82
 
83
+ # Convert the directory to a string.
84
+ # @returns [String] The root path as a string.
58
85
  def to_s
59
86
  to_str
60
87
  end
61
88
 
89
+ # Convert the directory to a path object.
90
+ # @returns [Path] The root path.
62
91
  def to_path
63
92
  @root
64
93
  end
@@ -8,12 +8,19 @@ require_relative "list"
8
8
  module Build
9
9
  module Files
10
10
  class Path
11
+ # Create a glob pattern matcher for files under this path.
12
+ # @parameter pattern [String] The glob pattern to match.
13
+ # @returns [Glob] A glob matcher for the pattern.
11
14
  def glob(pattern)
12
15
  Glob.new(self, pattern)
13
16
  end
14
17
  end
15
18
 
19
+ # Represents a glob pattern for matching files.
16
20
  class Glob < List
21
+ # Initialize a glob with a root path and pattern.
22
+ # @parameter root [Path] The root directory for the glob.
23
+ # @parameter pattern [String] The glob pattern to match.
17
24
  def initialize(root, pattern)
18
25
  @root = root
19
26
  @pattern = pattern
@@ -22,10 +29,14 @@ module Build
22
29
  attr :root
23
30
  attr :pattern
24
31
 
32
+ # Get the root paths for this glob.
33
+ # @returns [Array(Path)] An array containing the root path.
25
34
  def roots
26
35
  [@root]
27
36
  end
28
37
 
38
+ # Get the full pattern including the root path.
39
+ # @returns [String] The complete glob pattern.
29
40
  def full_pattern
30
41
  Path.join(@root, @pattern)
31
42
  end
@@ -42,22 +53,35 @@ module Build
42
53
  end
43
54
  end
44
55
 
56
+ # Check equality with another glob.
57
+ # @parameter other [Glob] The other glob to compare.
58
+ # @returns [Boolean] True if both globs have the same root and pattern.
45
59
  def eql?(other)
46
60
  self.class.eql?(other.class) and @root.eql?(other.root) and @pattern.eql?(other.pattern)
47
61
  end
48
62
 
63
+ # Compute the hash value for this glob.
64
+ # @returns [Integer] The hash value based on root and pattern.
49
65
  def hash
50
66
  [@root, @pattern].hash
51
67
  end
52
68
 
69
+ # Check if a path matches this glob pattern.
70
+ # @parameter path [Path] The path to check.
71
+ # @returns [Boolean] True if the path matches the pattern.
53
72
  def include?(path)
54
73
  File.fnmatch(full_pattern, path)
55
74
  end
56
75
 
76
+ # Rebase the glob to a new root.
77
+ # @parameter root [Path] The new root path.
78
+ # @returns [Glob] A new glob with the same pattern under the new root.
57
79
  def rebase(root)
58
80
  self.class.new(root, @pattern)
59
81
  end
60
82
 
83
+ # Generate a string representation for debugging.
84
+ # @returns [String] A debug string showing the full pattern.
61
85
  def inspect
62
86
  "<Glob #{full_pattern.inspect}>"
63
87
  end
@@ -11,6 +11,8 @@ module Build
11
11
  class List
12
12
  include Enumerable
13
13
 
14
+ # Get all unique root paths from the list.
15
+ # @returns [Array(Path)] Sorted unique root paths.
14
16
  def roots
15
17
  collect{|path| path.root}.sort.uniq
16
18
  end
@@ -20,6 +22,9 @@ module Build
20
22
  Composite.new([self, list])
21
23
  end
22
24
 
25
+ # Subtract a list from this list.
26
+ # @parameter list [List] The list to subtract.
27
+ # @returns [Difference] A difference list excluding the given paths.
23
28
  def -(list)
24
29
  Difference.new(self, list)
25
30
  end
@@ -40,6 +45,8 @@ module Build
40
45
  other.any?{|path| include?(path)}
41
46
  end
42
47
 
48
+ # Check if the list is empty.
49
+ # @returns [Boolean] True if the list contains no paths.
43
50
  def empty?
44
51
  each do
45
52
  return false
@@ -48,6 +55,12 @@ module Build
48
55
  return true
49
56
  end
50
57
 
58
+ # Transform paths with modified attributes.
59
+ # @parameter options [Hash] Options to pass to {Path#with}.
60
+ # @yields {|path, updated_path| ...} Each original and updated path.
61
+ # @parameter path [Path] The original path.
62
+ # @parameter updated_path [Path] The modified path.
63
+ # @returns [Paths] A new paths list with transformed paths.
51
64
  def with(**options)
52
65
  return to_enum(:with, **options) unless block_given?
53
66
 
@@ -64,18 +77,30 @@ module Build
64
77
  return Paths.new(paths)
65
78
  end
66
79
 
80
+ # Rebase all paths in the list to a new root.
81
+ # @parameter root [Path] The new root path.
82
+ # @returns [Paths] A new paths list with rebased paths.
67
83
  def rebase(root)
68
84
  Paths.new(self.collect{|path| path.rebase(root)}, [root])
69
85
  end
70
86
 
87
+ # Convert the list to a Paths instance.
88
+ # @returns [Paths] A paths list containing all items.
71
89
  def to_paths
72
90
  Paths.new(each.to_a)
73
91
  end
74
92
 
93
+ # Map over the list and return a Paths instance.
94
+ # @yields {|path| ...} Each path in the list.
95
+ # @parameter path [Path] The current path.
96
+ # @returns [Paths] A new paths list with mapped values.
75
97
  def map
76
98
  Paths.new(super)
77
99
  end
78
100
 
101
+ # Coerce an argument to a List instance.
102
+ # @parameter arg [List | Object] The object to coerce.
103
+ # @returns [List] A list instance.
79
104
  def self.coerce(arg)
80
105
  if arg.kind_of? self
81
106
  arg
@@ -84,6 +109,8 @@ module Build
84
109
  end
85
110
  end
86
111
 
112
+ # Convert the list to a string.
113
+ # @returns [String] The string representation.
87
114
  def to_s
88
115
  inspect
89
116
  end
@@ -7,10 +7,15 @@ module Build
7
7
  module Files
8
8
  # Represents a file path with an absolute root and a relative offset:
9
9
  class Path
10
+ # Get the current working directory as a path.
11
+ # @returns [Path] The current directory path.
10
12
  def self.current
11
13
  self.new(::Dir.pwd)
12
14
  end
13
15
 
16
+ # Split a path into directory, filename, and extension components.
17
+ # @parameter path [String] The path to split.
18
+ # @returns [Array(String, String, String)] The directory, filename, and extension.
14
19
  def self.split(path)
15
20
  # Effectively dirname and basename:
16
21
  dirname, separator, filename = path.rpartition(File::SEPARATOR)
@@ -33,6 +38,9 @@ module Build
33
38
  end
34
39
  end
35
40
 
41
+ # Get the root directory of a path.
42
+ # @parameter path [Path | String] The path to get the root from.
43
+ # @returns [String] The root directory.
36
44
  def self.root(path)
37
45
  if Path === path
38
46
  path.root
@@ -41,7 +49,10 @@ module Build
41
49
  end
42
50
  end
43
51
 
44
- # Return the shortest relative path to get to path from root. Root should be a directory with which you are computing the relative path.
52
+ # Compute the shortest relative path from root to path.
53
+ # @parameter path [Path | String] The target path.
54
+ # @parameter root [Path | String] The root directory.
55
+ # @returns [String] The shortest relative path.
45
56
  def self.shortest_path(path, root)
46
57
  path_components = Path.components(path)
47
58
  root_components = Path.components(root)
@@ -61,6 +72,10 @@ module Build
61
72
  end
62
73
  end
63
74
 
75
+ # Compute the relative path from root to full path.
76
+ # @parameter root [String] The root directory.
77
+ # @parameter full_path [String] The full path.
78
+ # @returns [String] The relative path.
64
79
  def self.relative_path(root, full_path)
65
80
  relative_offset = root.length
66
81
 
@@ -70,6 +85,9 @@ module Build
70
85
  return full_path.slice(relative_offset..-1)
71
86
  end
72
87
 
88
+ # Convert a path-like object to a Path instance.
89
+ # @parameter path [Path | String] The path to convert.
90
+ # @returns [Path] A Path instance.
73
91
  def self.[] path
74
92
  self === path ? path : self.new(path.to_s)
75
93
  end
@@ -91,20 +109,28 @@ module Build
91
109
  attr :root
92
110
  attr :full_path
93
111
 
112
+ # Get the length of the full path.
113
+ # @returns [Integer] The number of characters in the path.
94
114
  def length
95
115
  @full_path.length
96
116
  end
97
117
 
98
118
  alias size length
99
119
 
120
+ # Get the path components as an array.
121
+ # @returns [Array(String)] The path split by directory separator.
100
122
  def components
101
123
  @components ||= @full_path.split(File::SEPARATOR).freeze
102
124
  end
103
125
 
126
+ # Get the basename of the path.
127
+ # @returns [String] The last component of the path.
104
128
  def basename
105
129
  self.parts.last
106
130
  end
107
131
 
132
+ # Get the parent directory path.
133
+ # @returns [Path] The parent directory.
108
134
  def parent
109
135
  root = @root
110
136
  full_path = File.dirname(@full_path)
@@ -120,22 +146,32 @@ module Build
120
146
  self.class.new(full_path, root)
121
147
  end
122
148
 
149
+ # Check if the path starts with the given prefix.
150
+ # @parameter args [Array(String)] The prefix strings to check.
151
+ # @returns [Boolean] True if the path starts with any of the prefixes.
123
152
  def start_with?(*args)
124
153
  @full_path.start_with?(*args)
125
154
  end
126
155
 
127
156
  alias parts components
128
157
 
158
+ # Get the relative path from the root.
159
+ # @returns [String] The path relative to the root.
129
160
  def relative_path
130
161
  @relative_path ||= Path.relative_path(@root.to_s, @full_path.to_s).freeze
131
162
  end
132
163
 
164
+ # Split the relative path into directory and basename components.
165
+ # @returns [Array(String, String)] The directory and basename.
133
166
  def relative_parts
134
167
  dirname, _, basename = self.relative_path.rpartition(File::SEPARATOR)
135
168
 
136
169
  return dirname, basename
137
170
  end
138
171
 
172
+ # Append an extension to the path.
173
+ # @parameter extension [String] The extension to append.
174
+ # @returns [Path] A new path with the extension appended.
139
175
  def append(extension)
140
176
  self.class.new(@full_path + extension, @root)
141
177
  end
@@ -160,10 +196,18 @@ module Build
160
196
  end
161
197
  end
162
198
 
199
+ # Rebase the path to a new root directory.
200
+ # @parameter root [Path | String] The new root.
201
+ # @returns [Path] A new path with the same relative path under the new root.
163
202
  def rebase(root)
164
203
  self.class.new(File.join(root, relative_path), root)
165
204
  end
166
205
 
206
+ # Create a modified path with new root, extension, or basename.
207
+ # @parameter root [Path | String] The new root directory.
208
+ # @parameter extension [String | Nil] An extension to add.
209
+ # @parameter basename [String | Boolean | Nil] A new basename or `true` to keep existing.
210
+ # @returns [Path] A new path with the specified modifications.
167
211
  def with(root: @root, extension: nil, basename: false)
168
212
  relative_path = self.relative_path
169
213
 
@@ -183,6 +227,10 @@ module Build
183
227
  self.class.new(File.join(root, relative_path), root, relative_path)
184
228
  end
185
229
 
230
+ # Join a root and relative path to create a new Path.
231
+ # @parameter root [String] The root directory.
232
+ # @parameter relative_path [String] The relative path.
233
+ # @returns [Path] A new path combining root and relative path.
186
234
  def self.join(root, relative_path)
187
235
  self.new(File.join(root, relative_path), root)
188
236
  end
@@ -196,37 +244,56 @@ module Build
196
244
  end
197
245
  end
198
246
 
247
+ # Compute the shortest path from this path to a root.
248
+ # @parameter root [Path | String] The root directory.
249
+ # @returns [String] The shortest relative path.
199
250
  def shortest_path(root)
200
251
  self.class.shortest_path(self, root)
201
252
  end
202
253
 
254
+ # Convert the path to a string.
255
+ # @returns [String] The full path as a string.
203
256
  def to_str
204
257
  @full_path.to_str
205
258
  end
206
259
 
260
+ # Convert the path to a path string.
261
+ # @returns [String] The full path.
207
262
  def to_path
208
263
  @full_path
209
264
  end
210
265
 
266
+ # Convert the path to a string representation.
267
+ # @returns [String] The full path as a string.
211
268
  def to_s
212
269
  # It's not guaranteed to be string.
213
270
  @full_path.to_s
214
271
  end
215
272
 
273
+ # Generate a string representation for debugging.
274
+ # @returns [String] A debug string showing root and relative path.
216
275
  def inspect
217
276
  "#{@root.inspect}/#{relative_path.inspect}"
218
277
  end
219
278
 
279
+ # Compute the hash value for this path.
280
+ # @returns [Integer] The hash value based on root and full path.
220
281
  def hash
221
282
  [@root, @full_path].hash
222
283
  end
223
284
 
285
+ # Check equality with another path.
286
+ # @parameter other [Path] The other path to compare.
287
+ # @returns [Boolean] True if both paths have the same root and full path.
224
288
  def eql?(other)
225
289
  self.class.eql?(other.class) and @root.eql?(other.root) and @full_path.eql?(other.full_path)
226
290
  end
227
291
 
228
292
  include Comparable
229
293
 
294
+ # Compare this path with another for sorting.
295
+ # @parameter other [Path] The other path to compare.
296
+ # @returns [Integer] -1, 0, or 1 for less than, equal, or greater than.
230
297
  def <=>(other)
231
298
  self.to_s <=> other.to_s
232
299
  end
@@ -238,14 +305,20 @@ module Build
238
305
  return File.fnmatch(pattern, path, flags)
239
306
  end
240
307
 
308
+ # Get file opening arguments for reading.
309
+ # @returns [Array] The path and file mode for reading.
241
310
  def for_reading
242
311
  [@full_path, File::RDONLY]
243
312
  end
244
313
 
314
+ # Get file opening arguments for writing.
315
+ # @returns [Array] The path and file mode for writing.
245
316
  def for_writing
246
317
  [@full_path, File::CREAT|File::TRUNC|File::WRONLY]
247
318
  end
248
319
 
320
+ # Get file opening arguments for appending.
321
+ # @returns [Array] The path and file mode for appending.
249
322
  def for_appending
250
323
  [@full_path, File::CREAT|File::APPEND|File::WRONLY]
251
324
  end
@@ -7,7 +7,11 @@ require_relative "list"
7
7
 
8
8
  module Build
9
9
  module Files
10
+ # Represents an explicit list of file paths.
10
11
  class Paths < List
12
+ # Initialize a paths list.
13
+ # @parameter list [Array] The array of paths.
14
+ # @parameter roots [Array(Path) | Nil] The root paths, if known.
11
15
  def initialize(list, roots = nil)
12
16
  @list = Array(list).freeze
13
17
  @roots = roots
@@ -20,32 +24,50 @@ module Build
20
24
  @roots ||= super
21
25
  end
22
26
 
27
+ # Get the count of paths in the list.
28
+ # @returns [Integer] The number of paths.
23
29
  def count
24
30
  @list.count
25
31
  end
26
32
 
33
+ # Iterate over all paths in the list.
34
+ # @yields {|path| ...} Each path in the list.
35
+ # @parameter path [Path] The current path.
27
36
  def each
28
37
  return to_enum(:each) unless block_given?
29
38
 
30
39
  @list.each{|path| yield path}
31
40
  end
32
41
 
42
+ # Check equality with another paths list.
43
+ # @parameter other [Paths] The other paths list to compare.
44
+ # @returns [Boolean] True if both have the same paths.
33
45
  def eql?(other)
34
46
  self.class.eql?(other.class) and @list.eql?(other.list)
35
47
  end
36
-
48
+
49
+ # Compute the hash value for this paths list.
50
+ # @returns [Integer] The hash value based on the list.
37
51
  def hash
38
52
  @list.hash
39
53
  end
40
54
 
55
+ # Return this paths list unchanged.
56
+ # @returns [Paths] Self.
41
57
  def to_paths
42
58
  self
43
59
  end
44
60
 
61
+ # Generate a string representation for debugging.
62
+ # @returns [String] A debug string showing the paths.
45
63
  def inspect
46
64
  "<Paths #{@list.inspect}>"
47
65
  end
48
66
 
67
+ # Create a paths list from a directory root and relative paths.
68
+ # @parameter root [Path] The root directory.
69
+ # @parameter relative_paths [Array(String)] The relative paths.
70
+ # @returns [Paths] A new paths list.
49
71
  def self.directory(root, relative_paths)
50
72
  paths = relative_paths.collect do |path|
51
73
  Path.join(root, path)
@@ -56,6 +78,9 @@ module Build
56
78
  end
57
79
 
58
80
  class Path
81
+ # Create a paths list from relative paths under this path.
82
+ # @parameter relative_paths [Array(String)] The relative paths.
83
+ # @returns [Paths] A new paths list.
59
84
  def list(*relative_paths)
60
85
  Paths.directory(self, relative_paths)
61
86
  end
@@ -17,6 +17,9 @@ module Build
17
17
  class FileTime
18
18
  include Comparable
19
19
 
20
+ # Initialize a file time record.
21
+ # @parameter path [Path] The file path.
22
+ # @parameter time [Time] The modification time.
20
23
  def initialize(path, time)
21
24
  @path = path
22
25
  @time = time
@@ -25,15 +28,23 @@ module Build
25
28
  attr :path
26
29
  attr :time
27
30
 
31
+ # Compare file times for ordering.
32
+ # @parameter other [FileTime] The other file time to compare.
33
+ # @returns [Integer] -1, 0, or 1 for less than, equal, or greater than.
28
34
  def <=> other
29
35
  @time <=> other.time
30
36
  end
31
37
 
38
+ # Generate a string representation for debugging.
39
+ # @returns [String] A debug string showing path and time.
32
40
  def inspect
33
41
  "<FileTime #{@path.inspect} #{@time.inspect}>"
34
42
  end
35
43
  end
36
44
 
45
+ # Initialize file state tracking.
46
+ # @parameter files [List] The list of files to track.
47
+ # @raises [ArgumentError] If files is not a Files::List.
37
48
  def initialize(files)
38
49
  raise ArgumentError.new("Invalid files list: #{files}") unless Files::List === files
39
50
 
@@ -55,6 +66,8 @@ module Build
55
66
 
56
67
  def_delegators :@files, :each, :roots, :count
57
68
 
69
+ # Update the state by checking all files for changes.
70
+ # @returns [Boolean] True if any files were added, changed, removed, or are missing.
58
71
  def update!
59
72
  last_times = @times
60
73
  @times = {}
@@ -72,7 +85,7 @@ module Build
72
85
 
73
86
  if File.exist?(path)
74
87
  modified_time = File.mtime(path)
75
-
88
+
76
89
  if last_time = last_times.delete(path)
77
90
  # Path was valid last update:
78
91
  if modified_time != last_time
@@ -86,9 +99,9 @@ module Build
86
99
 
87
100
  # puts "Added: #{path}"
88
101
  end
89
-
102
+
90
103
  @times[path] = modified_time
91
-
104
+
92
105
  unless File.directory?(path)
93
106
  file_times << FileTime.new(path, modified_time)
94
107
  end
@@ -111,14 +124,20 @@ module Build
111
124
  attr :oldest_time
112
125
  attr :newest_time
113
126
 
127
+ # Check if any files are missing.
128
+ # @returns [Boolean] True if any files do not exist.
114
129
  def missing?
115
130
  !@missing.empty?
116
131
  end
117
132
 
133
+ # Check if the state is empty.
134
+ # @returns [Boolean] True if no files are being tracked.
118
135
  def empty?
119
136
  @times.empty?
120
137
  end
121
138
 
139
+ # Generate a string representation for debugging.
140
+ # @returns [String] A debug string showing state changes.
122
141
  def inspect
123
142
  "<State Added:#{@added} Removed:#{@removed} Changed:#{@changed} Missing:#{@missing}>"
124
143
  end
@@ -149,6 +168,10 @@ module Build
149
168
  return true
150
169
  end
151
170
 
171
+ # Check if outputs are dirty with respect to inputs.
172
+ # @parameter inputs [State] The input files state.
173
+ # @parameter outputs [State] The output files state.
174
+ # @returns [Boolean] True if outputs need to be regenerated.
152
175
  def self.dirty?(inputs, outputs)
153
176
  outputs.dirty?(inputs)
154
177
  end
@@ -30,6 +30,8 @@ module Build
30
30
  end
31
31
  end
32
32
 
33
+ # Copy the path to a destination.
34
+ # @parameter destination [Path] The destination path.
33
35
  def copy(destination)
34
36
  if directory?
35
37
  destination.create
@@ -43,6 +45,8 @@ module Build
43
45
  FileUtils.touch(self.to_s)
44
46
  end
45
47
 
48
+ # Get file statistics.
49
+ # @returns [File::Stat] The file statistics.
46
50
  def stat
47
51
  File.stat(self.to_s)
48
52
  end
@@ -57,14 +61,20 @@ module Build
57
61
  File.directory?(self.to_s)
58
62
  end
59
63
 
64
+ # Check if the path refers to a regular file.
65
+ # @returns [Boolean] True if the path is a file.
60
66
  def file?
61
67
  File.file?(self.to_s)
62
68
  end
63
69
 
70
+ # Check if the path is a symbolic link.
71
+ # @returns [Boolean] True if the path is a symlink.
64
72
  def symlink?
65
73
  File.symlink?(self.to_s)
66
74
  end
67
75
 
76
+ # Check if the file is readable.
77
+ # @returns [Boolean] True if the file can be read.
68
78
  def readable?
69
79
  File.readable?(self.to_s)
70
80
  end
@@ -110,6 +120,8 @@ module Build
110
120
  each(&:delete)
111
121
  end
112
122
 
123
+ # Copy all files in the list to a destination.
124
+ # @parameter destination [Path] The destination root path.
113
125
  def copy(destination)
114
126
  each do |path|
115
127
  path.copy(destination / path.relative_path)
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2014-2023, by Samuel Williams.
4
+ # Copyright, 2014-2025, by Samuel Williams.
5
5
 
6
+ # @namespace
6
7
  module Build
8
+ # @namespace
7
9
  module Files
8
- VERSION = "1.9.1"
10
+ VERSION = "1.10.0"
9
11
  end
10
12
  end
data/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Build::Files is a set of idiomatic classes for dealing with paths and monitoring directories. File paths are represented with both root and relative parts which makes copying directory structures intuitive.
4
4
 
5
- [![Development Status](/workflows/Test/badge.svg)](/actions?workflow=Test)
5
+ [![Development Status](https://github.com/ioquatix/build-files/workflows/Test/badge.svg)](https://github.com/ioquatix/build-files/actions?workflow=Test)
6
6
 
7
7
  ## Installation
8
8
 
@@ -20,19 +20,13 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- The basic structure is the `Path`. Paths are stored with a root and relative part. By default, if no root is specified, it is the `dirname` part.
23
+ Please see the [project documentation](https://github.com/ioquatix/build-files) for more details.
24
24
 
25
- require 'build/files'
26
-
27
- path = Build::Files::Path("/foo/bar/baz")
28
- => "/foo/bar"/"baz"
29
-
30
- > path.root
31
- => "/foo/bar"
32
- > path.relative_path
33
- => "baz"
25
+ ## Releases
34
26
 
35
- Paths can be coerced to strings and thus are suitable arguments to `exec`/`system` functions.
27
+ Please see the [project releases](https://github.com/ioquatix/build-filesreleases/index) for all releases.
28
+
29
+ ### v1.10.0
36
30
 
37
31
  ## Contributing
38
32
 
data/releases.md ADDED
@@ -0,0 +1,3 @@
1
+ # Releases
2
+
3
+ ## v1.10.0
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build-files
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.1
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -36,7 +36,7 @@ cert_chain:
36
36
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
37
37
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
38
38
  -----END CERTIFICATE-----
39
- date: 2025-03-30 00:00:00.000000000 Z
39
+ date: 1980-01-02 00:00:00.000000000 Z
40
40
  dependencies: []
41
41
  executables: []
42
42
  extensions: []
@@ -55,6 +55,7 @@ files:
55
55
  - lib/build/files/version.rb
56
56
  - license.md
57
57
  - readme.md
58
+ - releases.md
58
59
  homepage: https://github.com/ioquatix/build-files
59
60
  licenses:
60
61
  - MIT
@@ -68,14 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
69
  requirements:
69
70
  - - ">="
70
71
  - !ruby/object:Gem::Version
71
- version: '3.1'
72
+ version: '3.2'
72
73
  required_rubygems_version: !ruby/object:Gem::Requirement
73
74
  requirements:
74
75
  - - ">="
75
76
  - !ruby/object:Gem::Version
76
77
  version: '0'
77
78
  requirements: []
78
- rubygems_version: 3.6.2
79
+ rubygems_version: 3.7.2
79
80
  specification_version: 4
80
81
  summary: Abstractions for handling and mapping paths.
81
82
  test_files: []
metadata.gz.sig CHANGED
Binary file