revtree 0.1.0 → 0.1.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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/revtree.rb +125 -12
  4. metadata +21 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7c82aecb58c070a313c7d7e7897c7c038d66dfa35d717fae991eeeb19245f6f
4
- data.tar.gz: 6ffc2b90332f026b0cd32c7f6daf7af377e28ced7c679633d6807416d1e9e1ff
3
+ metadata.gz: 3cfacc4513023ac62b90be3f9eed6fe2ab45af739aa6676413c947a214b7595f
4
+ data.tar.gz: cd7763aed7ca500ef2aaa1103d82e33667b9ad6d732839768b41100f3af435bb
5
5
  SHA512:
6
- metadata.gz: b21ee3950eae8d1c09f2d42124d68653c0c21f1f4c0efe1e582d9444cb4bcc90620cb8778a7ed900aeba9f3beab85ca6cca45dfa596ec3f49f29240b7a33cb13
7
- data.tar.gz: 2c0762cb314b65c1c14b8904cef4c18d0d434001193fe84d7f136fe9923de4cfa3bf73bcc253ce295dacb6ecb941479f8f84547fa3760c49006b305c31e720e0
6
+ metadata.gz: b723f8f00a74e68176bb3b9c60cfd09458cd0b67029ad903c76aee21a411394de498f04285fff7ae07436b35d2b55701e16a6f68fea1645c80acb1ebc6d1111d
7
+ data.tar.gz: c6d506353323eb333c849460132257f93abe1426c8fb8b3e6724c16499942409d99db0311c2e7ccd36da8bd401b8396e1689928ac3951b1aa9cc3fcff70a06fa
data/README.md CHANGED
@@ -39,7 +39,7 @@ sudo make install
39
39
  git clone https://github.com/juliankahlert/revtree.git
40
40
  cd revtree
41
41
  gem build revtree.gemspec
42
- sudo gem install --local revtree-0.1.0.gem
42
+ sudo gem install --local revtree-0.1.1.gem
43
43
  ```
44
44
 
45
45
  ## API Documentation
@@ -107,7 +107,7 @@ end
107
107
 
108
108
  ## Encouragement for Contribution
109
109
 
110
- Vontributions from the community are welcome!
110
+ Contributions from the community are welcome!
111
111
  If you find any issues or have ideas for new features, please feel free to submit a pull request or open an issue.
112
112
  Your input helps make RevTree better for everyone.
113
113
 
data/lib/revtree.rb CHANGED
@@ -26,9 +26,31 @@ require 'digest'
26
26
  require 'pathname'
27
27
  require 'json'
28
28
 
29
+ # The `RevTree` class provides a tree structure representing file directories and
30
+ # files, allowing for version tracking based on MD5 hashes.
31
+ #
32
+ # This class can traverse directories, compare versions of trees, and serialize/deserialize
33
+ # itself to/from JSON.
29
34
  class RevTree
30
- attr_reader :children, :type, :name, :rev, :status
35
+ # @return [Array<RevTree>] the list of children in the tree (empty for files)
36
+ attr_reader :children
37
+
38
+ # @return [Symbol] the type of the node (:folder or :file)
39
+ attr_reader :type
40
+
41
+ # @return [String] the name of the file or directory
42
+ attr_reader :name
31
43
 
44
+ # @return [String] the revision (MD5 hash) of the file or directory
45
+ attr_reader :rev
46
+
47
+ # @return [Symbol] the status of the file or directory (:unmodified, :modified, :added, :removed)
48
+ attr_reader :status
49
+
50
+ # Initializes a new `RevTree` object representing a directory or file.
51
+ #
52
+ # @param path [String, Pathname] the path to the file or directory
53
+ # @param whitelist [Array<String>, nil] a list of file patterns to include (optional)
32
54
  def initialize(path, whitelist = nil)
33
55
  @path = Pathname.new(path)
34
56
  @name = @path.basename.to_s
@@ -42,21 +64,19 @@ class RevTree
42
64
  end
43
65
  end
44
66
 
45
- def calculate_file_rev
46
- Digest::MD5.file(@path).hexdigest
47
- end
48
-
49
- def calculate_directory_rev
50
- Digest::MD5.hexdigest(@children.map(&:rev).join)
51
- end
52
-
67
+ # Prints the tree structure, including file names and statuses, to the console.
68
+ #
69
+ # @param indent [Integer] the indentation level (default: 0)
70
+ # @return [void]
53
71
  def print_tree(indent = 0)
54
72
  status_str = @status ? " (status: #{@status})" : ''
55
73
  puts "#{' ' * indent}#{@type == :folder ? '[Folder]' : '[File]'} #{@name} (rev: #{@rev})#{status_str}"
56
74
  @children.each { |child| child.print_tree(indent + 1) }
57
75
  end
58
76
 
59
- # Serialize the RevTree object to JSON
77
+ # Serializes the `RevTree` object to a hash.
78
+ #
79
+ # @return [Hash] a hash representing the object
60
80
  def to_h
61
81
  {
62
82
  type: @type,
@@ -67,14 +87,25 @@ class RevTree
67
87
  }
68
88
  end
69
89
 
70
- def to_json(*_args)
90
+ # Converts the `RevTree` object to JSON format.
91
+ #
92
+ # @return [String] a JSON string representing the object
93
+ def to_json
71
94
  JSON.pretty_generate(self.to_h)
72
95
  end
73
96
 
97
+ # Reconstructs a `RevTree` object from a hash.
98
+ #
99
+ # @param h [Hash] the hash to deserialize
100
+ # @return [RevTree] the reconstructed `RevTree` object
74
101
  def self.from_h(h)
75
102
  new_tree(h[:name], h[:type].to_sym, h[:rev], h[:children], h[:status])
76
103
  end
77
104
 
105
+ # Reconstructs a `RevTree` object from a JSON string.
106
+ #
107
+ # @param json_str [String] the JSON string to deserialize
108
+ # @return [RevTree] the reconstructed `RevTree` object
78
109
  def self.from_json(json_str)
79
110
  data = JSON.parse(json_str, symbolize_names: true)
80
111
  file_tree = from_h(data)
@@ -82,7 +113,14 @@ class RevTree
82
113
  file_tree
83
114
  end
84
115
 
85
- def for_each(status_whitelist, &block)
116
+ # Executes a block of code for each file matching the provided status whitelist.
117
+ #
118
+ # @param status_whitelist [Array<Symbol>] the list of statuses to match (:added, :modified, etc.)
119
+ # @yield [node, full_path] the block to be executed for each matching file
120
+ # @yieldparam node [RevTree] the current node being traversed
121
+ # @yieldparam full_path [String] the full path of the current node
122
+ # @return [void]
123
+ def for_each(status_whitelist = [:unmodified, :modified, :added, :removed], &block)
86
124
  return unless block_given?
87
125
 
88
126
  RevTree.traverse_tree(self, status_whitelist, @path, &block)
@@ -90,6 +128,23 @@ class RevTree
90
128
 
91
129
  private
92
130
 
131
+ # Calculates the MD5 hash for the file.
132
+ #
133
+ # @return [String] the MD5 hash of the file
134
+ def calculate_file_rev
135
+ Digest::MD5.file(@path).hexdigest
136
+ end
137
+
138
+ # Calculates the MD5 hash for the directory based on its children.
139
+ #
140
+ # @return [String] the MD5 hash of the directory
141
+ def calculate_directory_rev
142
+ Digest::MD5.hexdigest(@children.map(&:rev).join)
143
+ end
144
+
145
+ # Initializes the directory node by traversing its children.
146
+ #
147
+ # @return [void]
93
148
  def init_dir
94
149
  @type = :folder
95
150
  @children = @path.children
@@ -98,12 +153,23 @@ class RevTree
98
153
  @rev = calculate_directory_rev
99
154
  end
100
155
 
156
+ # Initializes the file node by calculating its revision.
157
+ #
158
+ # @return [void]
101
159
  def init_file
102
160
  @type = :file
103
161
  @children = []
104
162
  @rev = calculate_file_rev
105
163
  end
106
164
 
165
+ # Rebuilds a `RevTree` from its serialized components.
166
+ #
167
+ # @param name [String] the name of the node
168
+ # @param type [Symbol] the type of the node (:folder or :file)
169
+ # @param rev [String] the revision hash of the node
170
+ # @param children [Array<Hash>] the child nodes (if any)
171
+ # @param status [Symbol] the status of the node (:unmodified, :modified, etc.)
172
+ # @return [RevTree] the reconstructed tree
107
173
  def self.new_tree(name, type, rev, children, status = :unmodified)
108
174
  tree = allocate
109
175
  tree.instance_variable_set(:@name, name)
@@ -118,6 +184,10 @@ class RevTree
118
184
  tree
119
185
  end
120
186
 
187
+ # Determines whether a file or directory should be included in the tree.
188
+ #
189
+ # @param path [Pathname] the path to the file or directory
190
+ # @return [Boolean] `true` if the path should be included, `false` otherwise
121
191
  def include_in_tree?(path)
122
192
  return false if path.directory? && path.basename.to_s.start_with?('.')
123
193
 
@@ -127,6 +197,11 @@ class RevTree
127
197
  @whitelist.any? { |p| File.fnmatch?(p, path.basename.to_s) }
128
198
  end
129
199
 
200
+ # Compares two `RevTree` nodes (old and new) and returns a tree with appropriate status.
201
+ #
202
+ # @param old [RevTree, nil] the old version of the tree
203
+ # @param new [RevTree, nil] the new version of the tree
204
+ # @return [RevTree, nil] the resulting tree with status updates or `nil`
130
205
  def self.compare(old, new)
131
206
  return nil if old.nil? && new.nil?
132
207
 
@@ -140,18 +215,31 @@ class RevTree
140
215
  end
141
216
  end
142
217
 
218
+ # Handles the addition of a new node.
219
+ #
220
+ # @param new [RevTree] the new node
221
+ # @return [RevTree] the node with the status set to `:added`
143
222
  def self.handle_addition(new)
144
223
  with_status = new.dup
145
224
  with_status.instance_variable_set(:@status, :added)
146
225
  with_status
147
226
  end
148
227
 
228
+ # Handles the removal of an old node.
229
+ #
230
+ # @param old [RevTree] the old node
231
+ # @return [RevTree] the node with the status set to `:removed`
149
232
  def self.handle_removal(old)
150
233
  with_status = old.dup
151
234
  with_status.instance_variable_set(:@status, :removed)
152
235
  with_status
153
236
  end
154
237
 
238
+ # Handles the modification of a node.
239
+ #
240
+ # @param old [RevTree] the old node
241
+ # @param new [RevTree] the new node
242
+ # @return [RevTree] the node with the status set to `:modified`
155
243
  def self.handle_modification(old, new)
156
244
  if old.type == :folder && new.type == :folder
157
245
  compare_folders(old, new, :modified)
@@ -162,6 +250,12 @@ class RevTree
162
250
  end
163
251
  end
164
252
 
253
+ # Compares two folder nodes and returns a merged node with status updates.
254
+ #
255
+ # @param old [RevTree] the old folder node
256
+ # @param new [RevTree] the new folder node
257
+ # @param status [Symbol] the status to apply (:modified or :unmodified)
258
+ # @return [RevTree] the resulting folder node with status updates
165
259
  def self.compare_folders(old, new, status)
166
260
  combined_children = merge_children(old.children, new.children)
167
261
  with_status = new.dup
@@ -174,6 +268,11 @@ class RevTree
174
268
  with_status
175
269
  end
176
270
 
271
+ # Handles the unmodified status of a node.
272
+ #
273
+ # @param old [RevTree] the old node
274
+ # @param new [RevTree] the new node
275
+ # @return [RevTree] the node with the status set to `:unmodified`
177
276
  def self.handle_unmodified(old, new)
178
277
  if old.type == :folder && new.type == :folder
179
278
  compare_folders(old, new, :unmodified)
@@ -184,6 +283,11 @@ class RevTree
184
283
  end
185
284
  end
186
285
 
286
+ # Merges the children of two nodes.
287
+ #
288
+ # @param old_children [Array<RevTree>] the children of the old node
289
+ # @param new_children [Array<RevTree>] the children of the new node
290
+ # @return [Array<Array<RevTree, RevTree>>] an array of paired old and new children
187
291
  def self.merge_children(old_children, new_children)
188
292
  all_names = (old_children.map(&:name) + new_children.map(&:name)).uniq
189
293
  all_names.map do |name|
@@ -193,6 +297,15 @@ class RevTree
193
297
  end
194
298
  end
195
299
 
300
+ # Traverses the tree and executes a block for each file matching the provided status whitelist.
301
+ #
302
+ # @param node [RevTree] the current node being traversed
303
+ # @param status_whitelist [Array<Symbol>] the list of statuses to match
304
+ # @param current_path [Pathname] the current path
305
+ # @yield [node, full_path] the block to be executed for each matching file
306
+ # @yieldparam node [RevTree] the current node being traversed
307
+ # @yieldparam full_path [String] the full path of the current node
308
+ # @return [void]
196
309
  def self.traverse_tree(node, status_whitelist, current_path, &block)
197
310
  if node.type == :file && status_whitelist.include?(node.status)
198
311
  block.call(node, File.expand_path(current_path.to_s))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: revtree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Kahlert
@@ -10,6 +10,26 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.37
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.37
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: rspec
15
35
  requirement: !ruby/object:Gem::Requirement