revtree 0.1.4 → 0.1.5

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 +24 -16
  3. data/lib/revtree.rb +116 -81
  4. metadata +62 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7467c75fbcedb571b34585f6f91f6c41454819402da7b476725f0928486f5e7
4
- data.tar.gz: b00a508bafaae9f6cb4e6aea55ea7e83091a7cea7a84bb12f079581465d6e38b
3
+ metadata.gz: 38695028f770cc56588f3101b95f6dfdde959306928750c41ee7b04694b25f93
4
+ data.tar.gz: 4b240bf3d9601e5cbb73592ccaa4b95de20a1164ce8a0506642c394a1d5959c0
5
5
  SHA512:
6
- metadata.gz: ff58e04caa7b1afac85ceb19b2076e2cffbb28f6cd38dfe1b9f8b2b45824a70b80743fe2b6b3c42e1691b945f639f605c531d17a06aa546e26973bbe779c7a76
7
- data.tar.gz: 35cfb5161ae3d0a8edfbf7a80cef8b5d4e7a56f6e80005d5cbabe6ecb430113725a7a68dde43a7efa0b082fb682ef8903e3ea93e15940f7dcfb5e555e2f1298e
6
+ metadata.gz: 1b2db6f9de82d4b0b5adb8ea1fb0f562eec56e5242c97fddefde0240d6f0cbab0ade2f6baff811d579a139c85865d462ff27f94aed24de834d88975cb98277fd
7
+ data.tar.gz: 71c0386cd9c5d64e1881c47e6ab7ac83c5e5e03ceba87ff16c4fc63be1ef07795ac5cc8629ace349cc9315db8c3e955f21a21f488dfce61c0b0e6dbf607b8461
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # RevTree
2
- [![Gem Version](https://badge.fury.io/rb/revtree.svg)](https://badge.fury.io/rb/revtree)
2
+
3
+ [![GitHub Tag](https://img.shields.io/github/v/tag/juliankahlert/revtree)](https://github.com/juliankahlert/revtree)
4
+ [![Gem Version](https://img.shields.io/gem/v/revtree)](https://rubygems.org/gems/revtree)
5
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/ac169e80b46b4d78a1a3e8e15be24c2f)](https://app.codacy.com/gh/juliankahlert/revtree/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
6
+ [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/ac169e80b46b4d78a1a3e8e15be24c2f)](https://app.codacy.com/gh/juliankahlert/revtree/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
3
7
 
4
8
  ## Introduction
5
9
 
@@ -21,16 +25,19 @@ It also provides methods to print and serialize the tree structure, as well as t
21
25
  ## Install
22
26
 
23
27
  The supported tools are:
28
+
24
29
  - gitpack
25
30
  - make
26
31
  - gem
27
32
 
28
33
  ### gitpack
34
+
29
35
  ```sh
30
36
  gitpack add juliankahlert/revtree
31
37
  ```
32
38
 
33
39
  ### make
40
+
34
41
  ```sh
35
42
  git clone https://github.com/juliankahlert/revtree.git
36
43
  cd revtree
@@ -38,11 +45,12 @@ sudo make install
38
45
  ```
39
46
 
40
47
  ### gem (local)
48
+
41
49
  ```sh
42
50
  git clone https://github.com/juliankahlert/revtree.git
43
51
  cd revtree
44
52
  gem build revtree.gemspec
45
- sudo gem install --local revtree-0.1.4.gem
53
+ sudo gem install --local revtree-0.1.5.gem
46
54
  ```
47
55
 
48
56
  ## API Documentation
@@ -50,52 +58,52 @@ sudo gem install --local revtree-0.1.4.gem
50
58
  ### `RevTree.new(path, whitelist = nil)`
51
59
 
52
60
  - **Parameters**:
53
- - `path` (String): The path to the file or directory.
54
- - `whitelist` (Array<String>): List of patterns to include in the tree.
61
+ - `path` (`String`): The path to the file or directory.
62
+ - `whitelist` (`Array<String>`): List of patterns to include in the tree.
55
63
 
56
64
  ### `#print_tree(indent = 0)`
57
65
 
58
66
  - **Parameters**:
59
- - `indent` (Integer): Number of spaces to indent each level of the tree.
67
+ - `indent` (`Integer`): Number of spaces to indent each level of the tree.
60
68
 
61
69
  ### `#to_h`
62
70
 
63
- - **Returns**: A Hash representation of the RevTree object.
71
+ - **Returns**: A `Hash` representation of the `RevTree` object.
64
72
 
65
73
  ### `#to_json`
66
74
 
67
- - **Returns**: A JSON representation of the RevTree object.
75
+ - **Returns**: A `JSON` representation of the `RevTree` object.
68
76
 
69
77
  ### `#for_each(status_whitelist, &block)`
70
78
 
71
79
  - **Parameters**:
72
- - `status_whitelist` (Array<Symbol>): List of statuses to include (e.g., `[:added, :removed]`).
73
- - `&block` (Proc): A block to execute for each file matching the given statuses.
80
+ - `status_whitelist` (`Array<Symbol>`): List of statuses to include (e.g., `[:added, :removed]`).
81
+ - `&block` (`Proc`): A block to execute for each file matching the given statuses.
74
82
  - **Behavior**: Iterates over files in the tree, executing the block for each file whose status matches one of the statuses in the whitelist.
75
83
 
76
84
  ### `#watch(status_whitelist = [:modified, :added, :removed], &block)`
77
85
 
78
86
  - **Parameters**:
79
- - `status_whitelist` (Array<Symbol>): List of statuses to watch (e.g., `[:added, :removed]`).
80
- - `&block` (Proc): A block to execute when a file matching the given statuses is changed.
87
+ - `status_whitelist` (`Array<Symbol>`): List of statuses to watch (e.g., `[:added, :removed]`).
88
+ - `&block` (`Proc`): A block to execute when a file matching the given statuses is changed.
81
89
 
82
90
  ### `#with_interval(interval)`
83
91
 
84
92
  - **Parameters**:
85
- - `interval` (Integer): Interval (in seconds) between checks for changes.
93
+ - `interval` (`Integer`): Interval (in seconds) between checks for changes.
86
94
  - **Returns**: The `RevTree` instance, enabling method chaining.
87
95
 
88
96
  ### `RevTree.from_h(h)`
89
97
 
90
98
  - **Parameters**:
91
- - `h` (Hash): A hash representation of a RevTree object.
92
- - **Returns**: A RevTree object.
99
+ - `h` (`Hash`): A `Hash` representation of a `RevTree` object.
100
+ - **Returns**: A `RevTree` object.
93
101
 
94
102
  ### `RevTree.from_json(json_str)`
95
103
 
96
104
  - **Parameters**:
97
- - `json_str` (String): A JSON string representing a RevTree object.
98
- - **Returns**: A RevTree object.
105
+ - `json_str` (`String`): A `JSON` string representing a `RevTree` object.
106
+ - **Returns**: A `RevTree` object.
99
107
 
100
108
  ## Example Usage
101
109
 
data/lib/revtree.rb CHANGED
@@ -51,11 +51,15 @@ class RevTree
51
51
  #
52
52
  # @param path [String, Pathname] the path to the file or directory
53
53
  # @param whitelist [Array<String>, nil] a list of file patterns to include (optional)
54
- def initialize(path, whitelist = nil)
54
+ def initialize(path, whitelist = ['*'])
55
55
  @path = Pathname.new(path)
56
56
  @name = @path.basename.to_s
57
- @whitelist = whitelist || []
57
+ @whitelist = whitelist
58
58
  @status = :unmodified
59
+ @type = :folder
60
+ @children = []
61
+ @interval = 5
62
+ @rev = ''
59
63
 
60
64
  if @path.directory?
61
65
  init_dir
@@ -69,8 +73,8 @@ class RevTree
69
73
  # @param indent [Integer] the indentation level (default: 0)
70
74
  # @return [void]
71
75
  def print_tree(indent = 0)
72
- status_str = @status ? " (status: #{@status})" : ''
73
- puts "#{' ' * indent}#{@type == :folder ? '[Folder]' : '[File]'} #{@name} (rev: #{@rev})#{status_str}"
76
+ indent_prefix = ' ' * indent
77
+ puts "#{indent_prefix}#{type_to_str()} #{@name} (rev: #{@rev}) #{status_to_str()}"
74
78
  @children.each { |child| child.print_tree(indent + 1) }
75
79
  end
76
80
 
@@ -96,10 +100,12 @@ class RevTree
96
100
 
97
101
  # Reconstructs a `RevTree` object from a hash.
98
102
  #
99
- # @param h [Hash] the hash to deserialize
103
+ # @param hash [Hash] the hash to deserialize
100
104
  # @return [RevTree] the reconstructed `RevTree` object
101
- def self.from_h(h)
102
- new_tree(h[:name], h[:type].to_sym, h[:rev], h[:children], h[:status])
105
+ def self.from_h(hash)
106
+ hash[:status] = hash[:status].to_sym
107
+ hash[:type] = hash[:type].to_sym
108
+ new_tree(hash)
103
109
  end
104
110
 
105
111
  # Reconstructs a `RevTree` object from a JSON string.
@@ -138,23 +144,12 @@ class RevTree
138
144
  # @return [void]
139
145
  def watch(status_whitelist = [:modified, :added, :removed], &block)
140
146
  current_tree = self
141
- @interval ||= 5
147
+ setup_traps
142
148
 
143
- Signal.trap('INT') { exit }
144
- Signal.trap('TERM') { exit }
145
149
  loop do
146
150
  sleep @interval
147
151
 
148
- new_tree = RevTree.new(@path, @whitelist)
149
- diff_tree = RevTree.compare(current_tree, new_tree)
150
-
151
- next if diff_tree.nil?
152
-
153
- diff_tree.for_each(status_whitelist) do |node, full_path|
154
- block.call(node, full_path)
155
- end
156
-
157
- current_tree = new_tree
152
+ current_tree = refresh_tree(current_tree, status_whitelist, block)
158
153
  end
159
154
  end
160
155
 
@@ -169,6 +164,45 @@ class RevTree
169
164
 
170
165
  private
171
166
 
167
+ # Refreshes the tree by comparing the current tree with a new version and executing a block
168
+ # for each file that matches the given statuses.
169
+ #
170
+ # @param current_tree [RevTree] the current RevTree instance
171
+ # @param status_whitelist [Array<Symbol>] the list of statuses to match (e.g., :added, :modified, :removed)
172
+ # @param block [Proc] the block to execute for each file matching the statuses
173
+ # @return [RevTree] the updated RevTree with changes
174
+ def refresh_tree(current_tree, status_whitelist, block)
175
+ new_tree = RevTree.new(@path, @whitelist)
176
+ diff_tree = RevTree.compare(current_tree, new_tree)
177
+ return current_tree unless diff_tree
178
+
179
+ diff_tree.for_each(status_whitelist, &block)
180
+
181
+ new_tree
182
+ end
183
+
184
+ # Setup traps.
185
+ #
186
+ # @return [void]
187
+ def setup_traps
188
+ Signal.trap('INT') { exit }
189
+ Signal.trap('TERM') { exit }
190
+ end
191
+
192
+ # Stringify the type for pretty-printing.
193
+ #
194
+ # @return [String] the type string
195
+ def type_to_str
196
+ @type == :folder ? '[Folder]' : '[File]'
197
+ end
198
+
199
+ # Stringify the status for pretty-printing.
200
+ #
201
+ # @return [String] the status string
202
+ def status_to_str
203
+ @status ? "(status: #{@status})" : ''
204
+ end
205
+
172
206
  # Calculates the MD5 hash for the file.
173
207
  #
174
208
  # @return [String] the MD5 hash of the file
@@ -187,10 +221,9 @@ class RevTree
187
221
  #
188
222
  # @return [void]
189
223
  def init_dir
190
- @type = :folder
191
224
  @children = @path.children
192
- .select { |c| include_in_tree?(c) }
193
- .map { |c| RevTree.new(c, @whitelist) }
225
+ .select { |child| include_in_tree?(child) }
226
+ .map { |child| RevTree.new(child, @whitelist) }
194
227
  @rev = calculate_directory_rev
195
228
  end
196
229
 
@@ -199,43 +232,61 @@ class RevTree
199
232
  # @return [void]
200
233
  def init_file
201
234
  @type = :file
202
- @children = []
203
235
  @rev = calculate_file_rev
204
236
  end
205
237
 
238
+ # Apply attributes from a `Hash` to a `RevTree`.
239
+ #
240
+ # @param revtree [RevTree] the tree node to be modified
241
+ # @param attr_hash [Hash] the hash containing the attributes
242
+ # @return [void]
243
+ def self.apply_attributes(revtree, attr_hash)
244
+ revtree.instance_variable_set(:@name, attr_hash[:name])
245
+ revtree.instance_variable_set(:@type, attr_hash[:type])
246
+ revtree.instance_variable_set(:@rev, attr_hash[:rev])
247
+ revtree.instance_variable_set(:@status, attr_hash[:status])
248
+ revtree.instance_variable_set(:@children, attr_hash[:children])
249
+ end
250
+
251
+ # Recurse into child nodes to deserialize `RevTree`.
252
+ #
253
+ # @param hash [Hash] the hash to deserialize
254
+ # @return [void]
255
+ def self.new_tree_recurse_children(hash)
256
+ children = hash[:children] || []
257
+ hash[:children] = children.map { |child| from_h(child) }
258
+ end
259
+
206
260
  # Rebuilds a `RevTree` from its serialized components.
207
261
  #
208
- # @param name [String] the name of the node
209
- # @param type [Symbol] the type of the node (:folder or :file)
210
- # @param rev [String] the revision hash of the node
211
- # @param children [Array<Hash>] the child nodes (if any)
212
- # @param status [Symbol] the status of the node (:unmodified, :modified, etc.)
262
+ # @param hash [Hash] the hash to deserialize
213
263
  # @return [RevTree] the reconstructed tree
214
- def self.new_tree(name, type, rev, children, status = :unmodified)
264
+ def self.new_tree(hash)
215
265
  tree = allocate
216
- tree.instance_variable_set(:@name, name)
217
- tree.instance_variable_set(:@type, type.to_sym)
218
- tree.instance_variable_set(:@rev, rev)
219
- tree.instance_variable_set(:@status, status.to_sym)
220
- if type == :folder && children
221
- tree.instance_variable_set(:@children, children.map { |c| from_h(c) })
222
- else
223
- tree.instance_variable_set(:@children, [])
224
- end
266
+ new_tree_recurse_children(hash)
267
+ apply_attributes(tree, hash)
225
268
  tree
226
269
  end
227
270
 
271
+ # Determines whether a path is a dot directory.
272
+ #
273
+ # @param path [Pathname] the path to the file or directory
274
+ # @return [Boolean] `true` if path is a dot directory, `false` otherwise
275
+ def self.path_is_dot_dir?(path)
276
+ path.directory? && path.basename.to_s.start_with?('.')
277
+ end
278
+
228
279
  # Determines whether a file or directory should be included in the tree.
229
280
  #
230
281
  # @param path [Pathname] the path to the file or directory
231
282
  # @return [Boolean] `true` if the path should be included, `false` otherwise
232
283
  def include_in_tree?(path)
233
- return false if path.directory? && path.basename.to_s.start_with?('.')
284
+ return false if RevTree.path_is_dot_dir?(path)
234
285
 
235
286
  return true if path.directory?
236
287
  return true if @whitelist.empty?
237
288
 
238
- @whitelist.any? { |p| File.fnmatch?(p, path.basename.to_s) }
289
+ @whitelist.any? { |pattern| File.fnmatch?(pattern, path.basename.to_s) }
239
290
  end
240
291
 
241
292
  # Compares two `RevTree` nodes (old and new) and returns a tree with appropriate status.
@@ -244,16 +295,13 @@ class RevTree
244
295
  # @param new [RevTree, nil] the new version of the tree
245
296
  # @return [RevTree, nil] the resulting tree with status updates or `nil`
246
297
  def self.compare(old, new)
247
- return nil if old.nil? && new.nil?
298
+ return nil unless old || new
248
299
 
249
- return handle_addition(new) if old.nil?
250
- return handle_removal(old) if new.nil?
300
+ return handle_addition(new) unless old
301
+ return handle_removal(old) unless new
251
302
 
252
- if old.rev != new.rev
253
- return handle_modification(old, new)
254
- else
255
- return handle_unmodified(old, new)
256
- end
303
+ status = old.rev != new.rev ? :modified : :unmodified
304
+ handle_modification(old, new, status)
257
305
  end
258
306
 
259
307
  # Handles the addition of a new node.
@@ -280,13 +328,14 @@ class RevTree
280
328
  #
281
329
  # @param old [RevTree] the old node
282
330
  # @param new [RevTree] the new node
331
+ # @param status [Symbol] the status to apply (:modified or :unmodified)
283
332
  # @return [RevTree] the node with the status set to `:modified`
284
- def self.handle_modification(old, new)
333
+ def self.handle_modification(old, new, status)
285
334
  if old.type == :folder && new.type == :folder
286
- compare_folders(old, new, :modified)
335
+ compare_folders(old, new, status)
287
336
  else
288
337
  with_status = new.dup
289
- with_status.instance_variable_set(:@status, :modified)
338
+ with_status.instance_variable_set(:@status, status)
290
339
  with_status
291
340
  end
292
341
  end
@@ -300,7 +349,9 @@ class RevTree
300
349
  def self.compare_folders(old, new, status)
301
350
  combined_children = merge_children(old.children, new.children)
302
351
  with_status = new.dup
303
- merged = combined_children.map { |o, n| compare(o, n) }
352
+ merged = combined_children.map do |old_child, new_child|
353
+ compare(old_child, new_child)
354
+ end
304
355
 
305
356
  folder_status = merged.any? { |child| child.status == :modified } ? :modified : status
306
357
 
@@ -309,33 +360,20 @@ class RevTree
309
360
  with_status
310
361
  end
311
362
 
312
- # Handles the unmodified status of a node.
313
- #
314
- # @param old [RevTree] the old node
315
- # @param new [RevTree] the new node
316
- # @return [RevTree] the node with the status set to `:unmodified`
317
- def self.handle_unmodified(old, new)
318
- if old.type == :folder && new.type == :folder
319
- compare_folders(old, new, :unmodified)
320
- else
321
- with_status = new.dup
322
- with_status.instance_variable_set(:@status, :unmodified)
323
- with_status
324
- end
325
- end
326
-
327
363
  # Merges the children of two nodes.
328
364
  #
329
- # @param old_children [Array<RevTree>] the children of the old node
330
- # @param new_children [Array<RevTree>] the children of the new node
331
365
  # @return [Array<Array<RevTree, RevTree>>] an array of paired old and new children
332
366
  def self.merge_children(old_children, new_children)
333
367
  all_names = (old_children.map(&:name) + new_children.map(&:name)).uniq
334
- all_names.map do |name|
335
- old_child = old_children.find { |child| child.name == name }
336
- new_child = new_children.find { |child| child.name == name }
337
- [old_child, new_child]
338
- end
368
+ all_names.map { |name| find_child_pair(name, old_children, new_children) }
369
+ end
370
+
371
+ # @param old_children [Array<RevTree>] the children of the old node
372
+ # @param new_children [Array<RevTree>] the children of the new node
373
+ def self.find_child_pair(name, old_children, new_children)
374
+ old_child = old_children.find { |old| old.name == name }
375
+ new_child = new_children.find { |new| new.name == name }
376
+ [old_child, new_child]
339
377
  end
340
378
 
341
379
  # Traverses the tree and executes a block for each file matching the provided status whitelist.
@@ -349,14 +387,11 @@ class RevTree
349
387
  # @yieldparam full_path [String] the full path of the current node
350
388
  # @return [void]
351
389
  def self.traverse_tree(node, status_whitelist, root, current_path, &block)
352
- full_path = if current_path
353
- File.join(current_path.to_s, node.name.to_s)
354
- else
355
- root
356
- end
390
+ current_path = current_path.to_s
391
+ full_path = current_path == '' ? root : File.join(current_path, node.name.to_s)
357
392
 
358
393
  if node.type == :file && status_whitelist.include?(node.status)
359
- block.call(node, File.expand_path(current_path.to_s))
394
+ block.call(node, File.expand_path(current_path))
360
395
  end
361
396
 
362
397
  node.children.each do |child|
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.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Kahlert
@@ -10,6 +10,66 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simplecov-simplecov-cobertura
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '2.1'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: simplecov-console
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.9'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.9.1
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.9'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.9.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: simplecov
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.22'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.22.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.22'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.22.0
13
73
  - !ruby/object:Gem::Dependency
14
74
  name: yard
15
75
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +126,7 @@ licenses:
66
126
  - MIT
67
127
  metadata:
68
128
  homepage_uri: https://juliankahlert.github.io/revtree/
69
- documentation_uri: https://www.rubydoc.info/gems/revtree/0.1.4
129
+ documentation_uri: https://www.rubydoc.info/gems/revtree/0.1.5
70
130
  source_code_uri: https://github.com/juliankahlert/revtree
71
131
  post_install_message:
72
132
  rdoc_options: []