staticky-files 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff9719d82a9de8cde1777bad0d9c2bbcfc9b2aafd747cbdef4e550041a1b2ce9
4
+ data.tar.gz: 78d26cfd1220fd7ce8abde206d60f2f38d152ac35b9b45246f5a3026c302cb54
5
+ SHA512:
6
+ metadata.gz: 7b60b8cf0c46b51fd200edeb6bf6441422318d6a7f4b9ddf2183758c5341ce03b9ac00596aaa2adb99026c928ebcdcd0593ccd990ab32fdbc95de12b787a001c
7
+ data.tar.gz: e7d118cf6aa846809deab019a02f538284e52ea77d5c99db88f4bab2063bceae676ba7cb76db86e363ed8ad61658b0be2aef42535b8d62686b83938b66031e88
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --order random
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ require:
2
+ - rubocop-inhouse
3
+
4
+ inherit_gem:
5
+ rubocop-inhouse:
6
+ - config/default.yml
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 3.1
10
+
11
+ Naming/FileName:
12
+ Exclude:
13
+ - lib/staticky-files.rb
14
+
15
+ Style/StaticClass:
16
+ Enabled: false
17
+
18
+ Metrics/ParameterLists:
19
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-08-14
4
+
5
+ - Initial release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Nolan J Tait
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Staticky files
2
+
3
+ This is a hard fork of `dry-files` that adds extensions for:
4
+
5
+ - `entries` to walk entries in a directory
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add staticky-files
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install staticky-files
16
+
17
+ ## Usage
18
+
19
+ See the documentation for [`dry-files`](https://dry-rb.org/gems/dry-files)
20
+
21
+ ## Development
22
+
23
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
24
+ `bin/rspec` to run the tests. You can also run `bin/console` for an interactive
25
+ prompt that will allow you to experiment.
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To
28
+ release a new version, update the version number in `version.rb`, and then run
29
+ `bundle exec rake release`, which will create a git tag for the version, push
30
+ git commits and the created tag, and push the `.gem` file to
31
+ [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nolantait/staticky.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Staticky
4
+ class Files
5
+ class Adapter
6
+ def self.call(memory:)
7
+ if memory
8
+ require_relative "memory_file_system"
9
+ MemoryFileSystem.new
10
+ else
11
+ require_relative "file_system"
12
+ FileSystem.new
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Staticky
4
+ class Files
5
+ # Staticky::Files base error
6
+ class Error < StandardError
7
+ end
8
+
9
+ # Wraps low level I/O errors
10
+ #
11
+ # @see https://ruby-doc.org/core/Errno.html
12
+ class IOError < Error
13
+ # Instantiate a new `Staticky::Files::IOError`
14
+ #
15
+ # @param cause [Exception] the low level exception
16
+ #
17
+ # @return [Staticky::Files::IOError] the new error
18
+ def initialize(cause)
19
+ super(cause.message)
20
+ @_cause = cause
21
+ end
22
+
23
+ # The original exception
24
+ #
25
+ # @see https://ruby-doc.org/core/Exception.html#method-i-cause
26
+ def cause
27
+ @_cause
28
+ end
29
+ end
30
+
31
+ # File manipulations error.
32
+ # Raised when the given `target` cannot be found in `path`.
33
+ class MissingTargetError < Error
34
+ # @param target [String,Regexp] the missing target
35
+ # @param path [String,Pathname] the file
36
+ #
37
+ # @return [Staticky::Files::MissingTargetError] the new error
38
+ def initialize(target, path)
39
+ super("cannot find `#{target}' in `#{path}'")
40
+
41
+ @_target = target
42
+ @_path = path
43
+ end
44
+
45
+ # The missing target
46
+ #
47
+ # @return [String, Regexp] the missing target
48
+ def target
49
+ @_target
50
+ end
51
+
52
+ # The missing target
53
+ #
54
+ # @return [String,Pathname] the file
55
+ def path
56
+ @_path
57
+ end
58
+ end
59
+
60
+ # Unknown memory node
61
+ #
62
+ # Raised by the memory adapter (used for testing purposes)
63
+ class UnknownMemoryNodeError < Error
64
+ # Instantiate a new error
65
+ #
66
+ # @param node [String] node name
67
+ def initialize(node)
68
+ super("unknown memory node `#{node}'")
69
+ end
70
+ end
71
+
72
+ # Not a memory file
73
+ #
74
+ # Raised by the memory adapter (used for testing purposes)
75
+ class NotMemoryFileError < Error
76
+ # Instantiate a new error
77
+ #
78
+ # @param path [String] path name
79
+ def initialize(path)
80
+ super("not a memory file `#{path}'")
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Staticky
6
+ class Files
7
+ # File System abstraction to support `Staticky::Files`
8
+ class FileSystem
9
+ attr_reader :file, :file_utils, :dir
10
+
11
+ # Creates a new instance
12
+ #
13
+ # @param file [Class]
14
+ # @param file_utils [Class]
15
+ #
16
+ # @return [Staticky::Files::FileSystem]
17
+ def initialize(file: File, file_utils: FileUtils, dir: Dir)
18
+ @file = file
19
+ @file_utils = file_utils
20
+ @dir = dir
21
+ end
22
+
23
+ # Opens (or creates) a new file for both read/write operations.
24
+ #
25
+ # If the file doesn't exist, it creates a new one.
26
+ #
27
+ # @see https://ruby-doc.org/core/File.html#method-c-open
28
+ #
29
+ # @param path [String] the target file
30
+ # @param mode [String,Integer] Ruby file open mode
31
+ # @param args [Array<Object>] ::File.open args
32
+ # @param blk [Proc] the block to yield
33
+ #
34
+ # @yieldparam [::File] the opened file
35
+ #
36
+ # @raise [Staticky::Files::IOError] in case of I/O error
37
+ def open(path, mode, ...)
38
+ touch(path)
39
+
40
+ with_error_handling do
41
+ file.open(path, mode, ...)
42
+ end
43
+ end
44
+
45
+ # Opens the file, optionally seeks to the given offset, then returns
46
+ # length bytes (defaulting to the rest of the file).
47
+ #
48
+ # Read ensures the file is closed before returning.
49
+ #
50
+ # @see https://ruby-doc.org/core/IO.html#method-c-read
51
+ #
52
+ # @param path [String, Array<String>] the target path
53
+ #
54
+ # @raise [Staticky::Files::IOError] in case of I/O error
55
+ def read(path, *args, **kwargs)
56
+ with_error_handling do
57
+ file.read(path, *args, **kwargs)
58
+ end
59
+ end
60
+
61
+ # Reads the entire file specified by name as individual lines,
62
+ # and returns those lines in an array
63
+ #
64
+ # @see https://ruby-doc.org/core/IO.html#method-c-readlines
65
+ #
66
+ # @param path [String] the file to read
67
+ #
68
+ # @raise [Staticky::Files::IOError] in case of I/O error
69
+ def readlines(path, *args)
70
+ with_error_handling do
71
+ file.readlines(path, *args)
72
+ end
73
+ end
74
+
75
+ # Updates modification time (mtime) and access time (atime) of file(s)
76
+ # in list.
77
+ #
78
+ # Files are created if they don’t exist.
79
+ #
80
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-touch
81
+ #
82
+ # @param path [String, Array<String>] the target path
83
+ #
84
+ # @raise [Staticky::Files::IOError] in case of I/O error
85
+ def touch(path, **kwargs)
86
+ raise IOError, Errno::EISDIR.new(path.to_s) if directory?(path)
87
+
88
+ with_error_handling do
89
+ mkdir_p(path)
90
+ file_utils.touch(path, **kwargs)
91
+ end
92
+ end
93
+
94
+ # Creates a new file or rewrites the contents
95
+ # of an existing file for the given path and content
96
+ # All the intermediate directories are created.
97
+ #
98
+ # @param path [String,Pathname] the path to file
99
+ # @param content [String, Array<String>] the content to write
100
+ #
101
+ # @raise [Staticky::Files::IOError] in case of I/O error
102
+ def write(path, *content)
103
+ mkdir_p(path)
104
+
105
+ self.open(path, WRITE_MODE) do |f|
106
+ f.write(Array(content).flatten.join)
107
+ end
108
+ end
109
+
110
+ # Sets UNIX permissions of the file at the given path.
111
+ #
112
+ # Accepts permissions in numeric mode only, best provided as octal numbers matching the
113
+ # standard UNIX octal permission modes, such as `0o544` for a file writeable by its owner and
114
+ # readable by others, or `0o755` for a file writeable by its owner and executable by everyone.
115
+ #
116
+ # @param path [String,Pathname] the path to the file
117
+ # @param mode [Integer] the UNIX permissions mode
118
+ #
119
+ # @raise [Staticky::Files::IOError] in case of I/O error
120
+ def chmod(path, mode)
121
+ with_error_handling do
122
+ file_utils.chmod(mode, path)
123
+ end
124
+ end
125
+
126
+ # Returns a new string formed by joining the strings using Operating
127
+ # System path separator
128
+ #
129
+ # @see https://ruby-doc.org/core/File.html#method-c-join
130
+ #
131
+ # @param path [Array<String,Pathname>] path tokens
132
+ #
133
+ # @return [String] the joined path
134
+ def join(*path)
135
+ file.join(*path)
136
+ end
137
+
138
+ # Converts a path to an absolute path.
139
+ #
140
+ # @see https://ruby-doc.org/core/File.html#method-c-expand_path
141
+ #
142
+ # @param path [String,Pathname] the path to the file
143
+ # @param dir [String,Pathname] the base directory
144
+ def expand_path(path, dir)
145
+ file.expand_path(path, dir)
146
+ end
147
+
148
+ # Returns the name of the current working directory.
149
+ #
150
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-pwd
151
+ #
152
+ # @return [String] the current working directory.
153
+ def pwd
154
+ file_utils.pwd
155
+ end
156
+
157
+ # Temporary changes the current working directory of the process to the
158
+ # given path and yield the given block.
159
+ #
160
+ # The argument `path` is intended to be a **directory**.
161
+ #
162
+ # @see https://ruby-doc.org/stdlib-3.0.0/libdoc/fileutils/rdoc/FileUtils.html#method-i-cd
163
+ #
164
+ # @param path [String,Pathname] the target directory
165
+ # @param blk [Proc] the code to execute with the target directory
166
+ #
167
+ # @raise [Staticky::Files::IOError] in case of I/O error
168
+ def chdir(path, &blk)
169
+ with_error_handling do
170
+ file_utils.chdir(path, &blk)
171
+ end
172
+ end
173
+
174
+ # Creates a directory and all its parent directories.
175
+ #
176
+ # The argument `path` is intended to be a **directory** that you want to
177
+ # explicitly create.
178
+ #
179
+ # @see #mkdir_p
180
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-mkdir_p
181
+ #
182
+ # @param path [String] the directory to create
183
+ #
184
+ # @raise [Staticky::Files::IOError] in case of I/O error
185
+ #
186
+ # @example
187
+ # require "dry/cli/utils/files/file_system"
188
+ #
189
+ # fs = Staticky::Files::FileSystem.new
190
+ # fs.mkdir("/usr/var/project")
191
+ # # creates all the directory structure (/usr/var/project)
192
+ def mkdir(path, **kwargs)
193
+ with_error_handling do
194
+ file_utils.mkdir_p(path, **kwargs)
195
+ end
196
+ end
197
+
198
+ # Creates a directory and all its parent directories.
199
+ #
200
+ # The argument `path` is intended to be a **file**, where its
201
+ # directory ancestors will be implicitly created.
202
+ #
203
+ # @see #mkdir
204
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-mkdir
205
+ #
206
+ # @param path [String] the file that will be in the directories that
207
+ # this method creates
208
+ #
209
+ # @raise [Staticky::Files::IOError] in case of I/O error
210
+ #
211
+ # @example
212
+ # require "dry/cli/utils/files/file_system"
213
+ #
214
+ # fs = Staticky::Files::FileSystem.new
215
+ # fs.mkdir("/usr/var/project/file.rb")
216
+ # # creates all the directory structure (/usr/var/project)
217
+ # # where file.rb will eventually live
218
+ def mkdir_p(path, **kwargs)
219
+ mkdir(
220
+ file.dirname(path), **kwargs
221
+ )
222
+ end
223
+
224
+ # Copies file content from `source` to `destination`
225
+ # All the intermediate `destination` directories are created.
226
+ #
227
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-cp
228
+ #
229
+ # @param source [String] the file(s) or directory to copy
230
+ # @param destination [String] the directory destination
231
+ #
232
+ # @raise [Staticky::Files::IOError] in case of I/O error
233
+ def cp(source, destination, **kwargs)
234
+ mkdir_p(destination)
235
+
236
+ with_error_handling do
237
+ file_utils.cp(source, destination, **kwargs)
238
+ end
239
+ end
240
+
241
+ # Removes (deletes) a file
242
+ #
243
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-rm
244
+ #
245
+ # @see #rm_rf
246
+ #
247
+ # @param path [String] the file to remove
248
+ #
249
+ # @raise [Staticky::Files::IOError] in case of I/O error
250
+ def rm(path, **kwargs)
251
+ with_error_handling do
252
+ file_utils.rm(path, **kwargs)
253
+ end
254
+ end
255
+
256
+ # Removes (deletes) a directory
257
+ #
258
+ # @see https://ruby-doc.org/stdlib/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure
259
+ #
260
+ # @param path [String] the directory to remove
261
+ #
262
+ # @raise [Staticky::Files::IOError] in case of I/O error
263
+ def rm_rf(path, *args)
264
+ with_error_handling do
265
+ file_utils.remove_entry_secure(path, *args)
266
+ end
267
+ end
268
+
269
+ # Check if the given path exist.
270
+ #
271
+ # @see https://ruby-doc.org/core/File.html#method-c-exist-3F
272
+ #
273
+ # @param path [String,Pathname] the file to check
274
+ #
275
+ # @return [TrueClass,FalseClass] the result of the check
276
+ def exist?(path)
277
+ file.exist?(path)
278
+ end
279
+
280
+ # Check if the given path is a directory.
281
+ #
282
+ # @see https://ruby-doc.org/core/File.html#method-c-directory-3F
283
+ #
284
+ # @param path [String,Pathname] the directory to check
285
+ #
286
+ # @return [TrueClass,FalseClass] the result of the check
287
+ def directory?(path)
288
+ file.directory?(path)
289
+ end
290
+
291
+ # Check if the given path is an executable.
292
+ #
293
+ # @see https://ruby-doc.org/core/File.html#method-c-executable-3F
294
+ #
295
+ # @param path [String,Pathname] the path to check
296
+ #
297
+ # @return [TrueClass,FalseClass] the result of the check
298
+ def executable?(path)
299
+ file.executable?(path)
300
+ end
301
+
302
+ # Get entries from a directory
303
+ #
304
+ # @see https://ruby-doc.org/3.2.2/Dir.html#method-c-entries
305
+ #
306
+ # @param [String,Pathname] the path to list entries for
307
+ #
308
+ # @raise [Staticky::Files::IOError] in case of I/O error
309
+ def entries(path)
310
+ with_error_handling do
311
+ dir.entries(path)
312
+ end
313
+ end
314
+
315
+ private
316
+
317
+ # Catch `SystemCallError` and re-raise a `Staticky::Files::IOError`.
318
+ #
319
+ # `SystemCallError` is parent for all the `Errno::*` Ruby exceptions.
320
+ # These class of exceptions are raised in case of I/O error.
321
+ #
322
+ # @see https://ruby-doc.org/core/SystemCallError.html
323
+ # @see https://ruby-doc.org/core/Errno.html
324
+ #
325
+ # @raise [Staticky::Files::IOError] in case of I/O error
326
+ def with_error_handling
327
+ yield
328
+ rescue SystemCallError => e
329
+ raise IOError, e
330
+ end
331
+ end
332
+ end
333
+ end