revtree 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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