stashify 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8498e1f869ce0f940cbf5e1f1eb65d77fb0692b1df9446b86547a070dcaa6ae
4
- data.tar.gz: f27dc8f8accaa1ec01c6aee2705cc3919205d168d82b8fab5b81aa452f90e24a
3
+ metadata.gz: 035b4f42412c865a6fcabf7944cd6a49169034b974054e20a8eb67ea1f06a4a4
4
+ data.tar.gz: 4a393454a48b04bc1769fe29a3ea21fe5e4ce501c3443f903e777c7a44b8478e
5
5
  SHA512:
6
- metadata.gz: d8123084aca3264108000f72216018ca1c6e4a7a6a99bdd82f4f7f4082515bc1fe9ce0d7f268a2bba73e5165e21de903e6c973965728e00dbc7fd4ae0d94a610
7
- data.tar.gz: 6f42c931c5dd653fe30a252ff513c3d66ded53c43df31d7aae877eafca20c87e0c2e01d90d0f1df0cab16d2fe85c75eccf5976cec2e61113252f6df06f555f35
6
+ metadata.gz: 3f3f849fff674adea33a49fbd2c9495cda7d21a64690cf09a828800acfaea5e70cd223ba3400a785e7e8f44f8e1daa3fa5047a44a3de9c0bfe936b91a7099c91
7
+ data.tar.gz: a13e678a94cdf0844d3d537310af37a0f21e9b55075600cfe47ce186cabee8c52c3ff3981459a630ca7163c1e3d7664aa6b36d0390afe1cfd02df3fd8ed04e37
data/.reek.yml CHANGED
@@ -1,7 +1,4 @@
1
1
  detectors:
2
- IrresponsibleModule:
3
- enabled: false
4
-
5
2
  TooManyStatements:
6
3
  exclude:
7
4
  - properties
data/.rubocop.yml CHANGED
@@ -2,9 +2,6 @@ AllCops:
2
2
  TargetRubyVersion: 2.6
3
3
  NewCops: enable
4
4
 
5
- Style/Documentation:
6
- Enabled: false
7
-
8
5
  Style/StringLiterals:
9
6
  Enabled: true
10
7
  EnforcedStyle: double_quotes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stashify (3.2.0)
4
+ stashify (3.2.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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(::File.basename(file_name))
30
+ find(file_name)
25
31
  end
26
32
  end
27
33
 
@@ -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
- attr_reader :name, :files, :path
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
- def write(file)
24
- if file.is_a?(Stashify::Directory)
25
- write_directory(file)
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(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
- def path_of(*name)
70
- ::File.join(path, *name)
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
@@ -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
- attr_reader :name, :path, :contents
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
- def initialize(name: nil, path: nil, contents: "")
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stashify
4
- VERSION = "3.2.0"
4
+ VERSION = "3.2.1"
5
5
  end
data/lib/stashify.rb CHANGED
@@ -3,5 +3,7 @@
3
3
  require_relative "stashify/version"
4
4
 
5
5
  module Stashify
6
+ # Error raised when the filename given is invalid. This most likely
7
+ # means the name parameter contains a "/".
6
8
  class InvalidFile < StandardError; end
7
9
  end
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.0
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-03 00:00:00.000000000 Z
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
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Stashify
4
- class Local
5
- def initialize(path)
6
- @path = path
7
- end
8
- end
9
- end