stashify 3.2.0 → 3.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.
- checksums.yaml +4 -4
- data/.reek.yml +0 -3
- data/.rubocop.yml +0 -3
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/lib/stashify/directory/local.rb +7 -1
- data/lib/stashify/directory.rb +110 -7
- data/lib/stashify/file/local.rb +4 -0
- data/lib/stashify/file.rb +63 -2
- data/lib/stashify/version.rb +1 -1
- data/lib/stashify.rb +2 -0
- metadata +2 -3
- data/lib/stashify/local.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 035b4f42412c865a6fcabf7944cd6a49169034b974054e20a8eb67ea1f06a4a4
|
4
|
+
data.tar.gz: 4a393454a48b04bc1769fe29a3ea21fe5e4ce501c3443f903e777c7a44b8478e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f3f849fff674adea33a49fbd2c9495cda7d21a64690cf09a828800acfaea5e70cd223ba3400a785e7e8f44f8e1daa3fa5047a44a3de9c0bfe936b91a7099c91
|
7
|
+
data.tar.gz: a13e678a94cdf0844d3d537310af37a0f21e9b55075600cfe47ce186cabee8c52c3ff3981459a630ca7163c1e3d7664aa6b36d0390afe1cfd02df3fd8ed04e37
|
data/.reek.yml
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -108,6 +108,8 @@ This consistency allows a lot of portability. For instance, pulling in a couple
|
|
108
108
|
> adir.files.map(&:name)
|
109
109
|
=> ["baz"]
|
110
110
|
|
111
|
+
As you can see in the above examples, `Stashify::File` and `Stashify::Directory` can be created directly to define in-memory objects. This helps avoid the need to do silly things like write files to disk in order to get them to the desired destination.
|
112
|
+
|
111
113
|
## Development
|
112
114
|
|
113
115
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -5,7 +5,13 @@ require "stashify/directory"
|
|
5
5
|
|
6
6
|
module Stashify
|
7
7
|
class Directory
|
8
|
+
# An implementation for interacting with local directories. The
|
9
|
+
# constructor needs no information on top of what is included
|
10
|
+
# {Stashify::Directory#initialize}, although it's important to
|
11
|
+
# note that setting the files parameter will not do anything.
|
8
12
|
class Local < Stashify::Directory
|
13
|
+
# Mostly uses the default implementaiton, but needs to create
|
14
|
+
# the directory first so it has a valid destination.
|
9
15
|
def write_directory(directory)
|
10
16
|
FileUtils.mkdir(path_of(directory.name))
|
11
17
|
super
|
@@ -21,7 +27,7 @@ module Stashify
|
|
21
27
|
|
22
28
|
def files
|
23
29
|
Dir.entries(path).grep_v(/^[.][.]?$/).map do |file_name|
|
24
|
-
find(
|
30
|
+
find(file_name)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
data/lib/stashify/directory.rb
CHANGED
@@ -1,9 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Stashify
|
4
|
+
# A common abstraction for interacting with directories. All methods
|
5
|
+
# that need to interact with directories are assumed to adhere to
|
6
|
+
# the public methods defined here. Specifically, the methods
|
7
|
+
# {#find}, {#write}, {#delete}, and {#files} are guaranteed to exist
|
8
|
+
# and behave in a way that is consistent across all gems. Unless
|
9
|
+
# called out separately, documentation for those methods here will
|
10
|
+
# hold true of any implementations of this class.
|
4
11
|
class Directory
|
5
|
-
|
12
|
+
# Provides the files and subdirectories of this directory. In the
|
13
|
+
# base class, this is implemented as an attribute which defaults
|
14
|
+
# to an empty list, but most implementations will override this
|
15
|
+
# with a method. In most implementations, the performance cost of
|
16
|
+
# reading all of thie names in a directory to construct these
|
17
|
+
# objects is high enough that we only want to pay it if it's
|
18
|
+
# actually needed.
|
19
|
+
#
|
20
|
+
# @return [Array<Stashify::File and Stashify::Directory>] Returns
|
21
|
+
# an Enumerable of Stashify::File and Stashify::Directory
|
22
|
+
# objects.
|
23
|
+
attr_reader :files
|
6
24
|
|
25
|
+
# The name of the directory. It is everything that follows the
|
26
|
+
# final "/" in the {#path}. This is always guaranteed to be
|
27
|
+
# populated.
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
# The full path to the directory this represents. Anything after the
|
31
|
+
# final "/" will also be returned from {#name}. This is not
|
32
|
+
# necessarily guaranteed to be populated, but usually will be.
|
33
|
+
attr_reader :path
|
34
|
+
|
35
|
+
# Basic information associated with a directory that is necessary
|
36
|
+
# to enable memory-based interactions.
|
37
|
+
#
|
38
|
+
# @param name [String not containing a "/"] The name of the file. Either this or path must be defined.
|
39
|
+
# @param path [String] The path of the file, will populate name with everything following the final "/".
|
40
|
+
# @param files An array of Stashify::File and Stashify::Directory
|
41
|
+
# objects representing the contents of this directory.
|
7
42
|
def initialize(name: nil, path: nil, files: [])
|
8
43
|
raise StandardError, "name or path must be defined" unless name || path
|
9
44
|
|
@@ -12,6 +47,19 @@ module Stashify
|
|
12
47
|
@files = files
|
13
48
|
end
|
14
49
|
|
50
|
+
# Look up the item in this directory represented by the provided
|
51
|
+
# name.
|
52
|
+
#
|
53
|
+
# For those looking to implement this method, it's typically more
|
54
|
+
# effective to override {#directory?}, {#directory}, {#exists?}
|
55
|
+
# and {#file}. Unless there are performance concerns with calling
|
56
|
+
# those, the default implementation will work pretty well.
|
57
|
+
#
|
58
|
+
# @param name [String with no "/"] The name of the desired item in
|
59
|
+
# this directory.
|
60
|
+
#
|
61
|
+
# @return Either a Stashify::File or Stashify::Directory object,
|
62
|
+
# depending on what that name represents.
|
15
63
|
def find(name)
|
16
64
|
if directory?(name)
|
17
65
|
directory(name)
|
@@ -20,23 +68,59 @@ module Stashify
|
|
20
68
|
end
|
21
69
|
end
|
22
70
|
|
23
|
-
|
24
|
-
|
25
|
-
|
71
|
+
# Write the provided item into the directory. If the item is a
|
72
|
+
# directory itself, then all of the contents will be copied.
|
73
|
+
#
|
74
|
+
# For those looking to implement this method, it's typically
|
75
|
+
# easier to implement {#write_file} and {#write_directory}. This
|
76
|
+
# helps you avoid having to know what type of object you're
|
77
|
+
# dealing with.
|
78
|
+
#
|
79
|
+
# @param item Either a Stashify::File or Stashify::Directory
|
80
|
+
# object. Note that these can be any implementation of these
|
81
|
+
# base classes, it's not limited to the classes from the same
|
82
|
+
# provider.
|
83
|
+
def write(item)
|
84
|
+
if item.is_a?(Stashify::Directory)
|
85
|
+
write_directory(item)
|
26
86
|
else
|
27
|
-
write_file(
|
87
|
+
write_file(item)
|
28
88
|
end
|
29
89
|
end
|
30
90
|
|
91
|
+
# Writes the provided directory. Typically you will want to
|
92
|
+
# interact with this functionality through {#write} rather than
|
93
|
+
# directly, as it protects you from errors related to accidentally
|
94
|
+
# passing a Stashify::File value in. It is primarily implemented
|
95
|
+
# separately to give a more specific hook for various
|
96
|
+
# implementations.
|
97
|
+
#
|
98
|
+
# The default implementation might work for you, as it iterates
|
99
|
+
# through {#files} and writes them to the new subdirectory.
|
31
100
|
def write_directory(directory)
|
32
101
|
subdir = self.directory(directory.name)
|
33
102
|
directory.files.each { |file| subdir.write(file) }
|
34
103
|
end
|
35
104
|
|
105
|
+
# Writes the provided file. Typically you will want to interact
|
106
|
+
# with this functionality through {#write} rather than directly,
|
107
|
+
# as it protects you from errors related to accidentally passing a
|
108
|
+
# Stashify::Directory value in. It is primarily implemented
|
109
|
+
# separately to give a more specific hook for various
|
110
|
+
# implementations.
|
36
111
|
def write_file(file)
|
37
112
|
file(file.name).write(file.contents)
|
38
113
|
end
|
39
114
|
|
115
|
+
# Delete provided name from the directory. If the item is a
|
116
|
+
# directory itself, then all of the contents will be copied.
|
117
|
+
#
|
118
|
+
# For those looking to implement this method, it's typically
|
119
|
+
# easier to implement {#directory?}, {#delete_directory} and
|
120
|
+
# {#delete_file}. The primary reason to override this method would
|
121
|
+
# be for performance reasons.
|
122
|
+
#
|
123
|
+
# @param name [String] Name of the item to be deleted.
|
40
124
|
def delete(name)
|
41
125
|
if directory?(name)
|
42
126
|
delete_directory(name)
|
@@ -45,29 +129,48 @@ module Stashify
|
|
45
129
|
end
|
46
130
|
end
|
47
131
|
|
132
|
+
# Deletes the provided directory name. Typically you will want to
|
133
|
+
# interact with this functionality through {#delete} rather than
|
134
|
+
# directly, as it protects you from errors related to accidentally
|
135
|
+
# asking to delete a file as a directory.
|
48
136
|
def delete_directory(name)
|
49
137
|
subdir = directory(name)
|
50
138
|
subdir.files.each { |file| subdir.delete(file.name) }
|
51
139
|
end
|
52
140
|
|
141
|
+
# Deletes the provided file name. Typically you will want to
|
142
|
+
# interact with this functionality through {#delete} rather than
|
143
|
+
# directly, as it protects you from errors related to accidentally
|
144
|
+
# asking to delete a directory as a file.
|
53
145
|
def delete_file(name)
|
54
146
|
file(name).delete
|
55
147
|
end
|
56
148
|
|
149
|
+
# Two directories are equal if their files are equal. This is
|
150
|
+
# distinct from being the same directory, which is served by the
|
151
|
+
# {#eql?} method.
|
57
152
|
def ==(other)
|
58
153
|
files == other.files
|
59
154
|
end
|
60
155
|
|
156
|
+
# This answers if the two directories are the same, which is
|
157
|
+
# usually more specific than you want. If you wish to determine if
|
158
|
+
# all of the files are equal, consider {#==} instead..
|
61
159
|
def eql?(other)
|
62
160
|
self.class == other.class && name == other.name && path == other.path
|
63
161
|
end
|
64
162
|
|
163
|
+
# @return [Stashify::File] Return an object representing a single
|
164
|
+
# file in this directory.
|
65
165
|
def file(name)
|
66
166
|
Stashify::File.new(path: path_of(name))
|
67
167
|
end
|
68
168
|
|
69
|
-
|
70
|
-
|
169
|
+
# The full path to the item in this directory provided by the
|
170
|
+
# names. Any number of names can be provided, allowing arbitrarily
|
171
|
+
# deep paths to be constructed below this directory.
|
172
|
+
def path_of(*names)
|
173
|
+
::File.join(path, *names)
|
71
174
|
end
|
72
175
|
end
|
73
176
|
end
|
data/lib/stashify/file/local.rb
CHANGED
@@ -4,6 +4,10 @@ require "stashify/file"
|
|
4
4
|
|
5
5
|
module Stashify
|
6
6
|
class File
|
7
|
+
# An implementation for interacting with local files. The
|
8
|
+
# constructor needs no information on top of what is included
|
9
|
+
# {Stashify::File#initialize}, although it's important to note
|
10
|
+
# that setting the contents parameter will not do anything.
|
7
11
|
class Local < Stashify::File
|
8
12
|
def contents
|
9
13
|
::File.read(path)
|
data/lib/stashify/file.rb
CHANGED
@@ -3,10 +3,38 @@
|
|
3
3
|
require "stashify"
|
4
4
|
|
5
5
|
module Stashify
|
6
|
+
# A common abstraction for interacting with files. All methods that
|
7
|
+
# need to interact with files are assumed to adhere to the methods
|
8
|
+
# defined here. Specifically the methods {#write}, {#delete},
|
9
|
+
# {#contents} and {#exists?} are guaranteed to exist and behave in a
|
10
|
+
# way that is consistent across all gems. Unless called out
|
11
|
+
# separately, documentation for those methods here will hold true of
|
12
|
+
# any implementations of this class.
|
6
13
|
class File
|
7
|
-
|
14
|
+
# Provides the contents of this file. In the base class, this is
|
15
|
+
# implemented as an attribute, but most implementations will
|
16
|
+
# override this with a method. In most implementations, the
|
17
|
+
# performance cost of reading the file is high enough that we only
|
18
|
+
# want to pay it if it's actually needed.
|
19
|
+
attr_reader :contents
|
8
20
|
|
9
|
-
|
21
|
+
# The name of the file is the actual filename in a directory. In
|
22
|
+
# other words, it is everything that follows the final "/" in the
|
23
|
+
# {#path}. This is always guaranteed to be populated.
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
# The full path to the file this represents. Anything after the
|
27
|
+
# final "/" will also be returned from {#name}. This is not
|
28
|
+
# necessarily guaranteed to be populated, but usually will be.
|
29
|
+
attr_reader :path
|
30
|
+
|
31
|
+
# Basic information associated with a file that is necessary to
|
32
|
+
# enable memory-based interactions.
|
33
|
+
#
|
34
|
+
# @param name [String not containing a "/"] The name of the file. Either this or path must be defined.
|
35
|
+
# @param path [String] The path of the file, will populate name with everything following the final "/".
|
36
|
+
# @param contents [String] The contents of the file, if nil this object will mimic a missing file.
|
37
|
+
def initialize(name: nil, path: nil, contents: nil)
|
10
38
|
raise StandardError, "name or path must be defined" unless name || path
|
11
39
|
raise Stashify::InvalidFile, "Name '#{name}' contains a /" if name && name =~ %r{/}
|
12
40
|
|
@@ -15,18 +43,51 @@ module Stashify
|
|
15
43
|
@contents = contents
|
16
44
|
end
|
17
45
|
|
46
|
+
# Persists the provided contents into {#path}. If that file does
|
47
|
+
# not exist, it creates it in the process. Otherwise it updates
|
48
|
+
# the existing file.
|
49
|
+
#
|
50
|
+
# In general, if {#exists?} returns false before this is called it
|
51
|
+
# will return true after this is called.
|
52
|
+
#
|
53
|
+
# @note For the base implementation, it will assign something to
|
54
|
+
# @contents. The value of this instance variable should not be
|
55
|
+
# relied upon outside of the base implementation though, every
|
56
|
+
# other implementation so far overrides to an action more
|
57
|
+
# appropriate to its storage medium.
|
58
|
+
#
|
59
|
+
# @param contents [String] A String describing the contents of the file.
|
60
|
+
# @return No guarantees are made as to the return value of this method,
|
61
|
+
# it will largely depend on the implementation of the implementing class.
|
18
62
|
def write(contents)
|
19
63
|
@contents = contents
|
20
64
|
end
|
21
65
|
|
66
|
+
# Deletes the underlying file.
|
67
|
+
#
|
68
|
+
# In general, if {#exists?} returns true prior to this method
|
69
|
+
# being called, it will no longer return true after this method is
|
70
|
+
# called.
|
71
|
+
#
|
72
|
+
# @return No guarantees are made as to the return value of this method,
|
73
|
+
# it will largely depend on the implementation of the implementing class.
|
22
74
|
def delete
|
23
75
|
@contents = nil
|
24
76
|
end
|
25
77
|
|
78
|
+
# Answers if the file exists. In general, it will always return
|
79
|
+
# true after {#write} is called and always return false after
|
80
|
+
# {#delete} is called.
|
81
|
+
#
|
82
|
+
# @note The base class checks if {#contents} returns nil, but this
|
83
|
+
# is extremely unlikely for other implementations.
|
26
84
|
def exists?
|
27
85
|
!contents.nil?
|
28
86
|
end
|
29
87
|
|
88
|
+
# Two files are considered equal if they have the same name and
|
89
|
+
# contents. This means that equality holds between files in two
|
90
|
+
# separate directories.
|
30
91
|
def ==(other)
|
31
92
|
name == other.name && contents == other.contents
|
32
93
|
end
|
data/lib/stashify/version.rb
CHANGED
data/lib/stashify.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stashify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lambda Null
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Provides an abstraction to various services (local filesystem, S3, etc)
|
14
14
|
email:
|
@@ -35,7 +35,6 @@ files:
|
|
35
35
|
- lib/stashify/directory/local.rb
|
36
36
|
- lib/stashify/file.rb
|
37
37
|
- lib/stashify/file/local.rb
|
38
|
-
- lib/stashify/local.rb
|
39
38
|
- lib/stashify/version.rb
|
40
39
|
- sig/stashify.rbs
|
41
40
|
- stashify.gemspec
|