claiss 1.1.5 → 1.1.6

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/lib/claiss/version.rb +1 -1
  3. data/lib/claiss.rb +117 -74
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7395901310b440af99e2a2c8398d2c419165457c3938c7f8d5cc394a49d416b
4
- data.tar.gz: 0cde7e9f094e6d3a873d15f886a1625e115b568c91b1f94ca947aad0cf5764f4
3
+ metadata.gz: 89ef5e762b27713cb2448f6f4b626d4a703fdd53d24e5ffb509149dc01222049
4
+ data.tar.gz: 26abd16563b100c01149adf6251781fc3fb7fe9185d89a72dc9ec3d5e5bcb9ed
5
5
  SHA512:
6
- metadata.gz: 1fad084036805ad9c71f3484c50d83e096c479c50575b3efb9d4ee0154fe40147830501f7749b94eaf19b25bb328f7a5cb6e773185338e0e9d94e775de552a93
7
- data.tar.gz: 0fba7b018af22b864ea3c19b920de07a9ccc71f94948953ae872d595778b2c0e2ac8d7237dca6ba59e9bcc081b4ae2ca29bff68c7fa157a9329e806751832ef0
6
+ metadata.gz: 6f98740a42f5036bed12e532db8bd2ef8730110c9f0686a7631dd3a595a1b0d15dc4c400e2a8f0db8ea5d48fe6cb9eab60412efadb3f205012e77c3929e7a5da
7
+ data.tar.gz: 2bcf421bfb579e37b78a885a406a53d16f0d08c7d371c193e28cb7c4179c2ecb412069a8a366787b493d0cf1eb317b8ed3eef69a60515216dc076d720953de69
@@ -1,3 +1,3 @@
1
1
  module CLAISS
2
- VERSION = '1.1.5'
2
+ VERSION = '1.1.6'
3
3
  end
data/lib/claiss.rb CHANGED
@@ -1,23 +1,24 @@
1
- require "dry/cli"
2
- require "fileutils"
3
- require "json"
4
- require "logger"
5
- require "parallel"
6
- require "ruby-progressbar"
1
+ require 'dry/cli'
2
+ require 'fileutils'
3
+ require 'json'
4
+ require 'logger'
5
+ require 'parallel'
6
+ require 'ruby-progressbar'
7
+ require 'pathname'
7
8
 
8
9
  # CLAISS module provides CLI commands for refactoring and managing Ruby projects
9
10
  module CLAISS
10
- IGNORED_DIRECTORIES = [".git/", "node_modules/"]
11
- DEFAULT_JSON_DIR = File.join(Dir.home, ".claiss")
11
+ IGNORED_DIRECTORIES = ['.git/', 'node_modules/']
12
+ DEFAULT_JSON_DIR = File.join(Dir.home, '.claiss')
12
13
 
13
14
  # Initialize logger
14
15
  LOGGER = Logger.new(STDOUT)
15
- LOGGER.level = Logger::INFO # Set to Logger::DEBUG for more verbose output
16
+ LOGGER.level = Logger::INFO # Set to Logger::DEBUG for more verbose output
16
17
 
17
18
  class Error < StandardError; end
18
19
 
19
20
  class Version < Dry::CLI::Command
20
- desc "Print version"
21
+ desc 'Print version'
21
22
 
22
23
  def call(*)
23
24
  puts "CLAISS version #{CLAISS::VERSION}"
@@ -25,15 +26,15 @@ module CLAISS
25
26
  end
26
27
 
27
28
  class Refactor < Dry::CLI::Command
28
- desc "Refactor files and filenames"
29
+ desc 'Refactor files and filenames'
29
30
 
30
- argument :path, type: :string, required: true, desc: "Path to the directory to refactor"
31
- argument :rules, type: :string, required: true, desc: "Name of the rules file (without .json extension)"
32
- option :destination, type: :string, desc: "Destination path for refactored files"
31
+ argument :path, type: :string, required: true, desc: 'Path to the directory to refactor'
32
+ argument :rules, type: :string, required: true, desc: 'Name of the rules file (without .json extension)'
33
+ option :destination, type: :string, desc: 'Destination path for refactored files'
33
34
 
34
35
  example [
35
- "path/to/project autokeras",
36
- "path/to/project autokeras --destination path/to/output",
36
+ 'path/to/project autokeras',
37
+ 'path/to/project autokeras --destination path/to/output'
37
38
  ]
38
39
 
39
40
  def call(path:, rules:, destination: nil, **)
@@ -45,29 +46,38 @@ module CLAISS
45
46
 
46
47
  files = get_files_to_process(origin_path)
47
48
  process_files_in_parallel(files, dict, origin_path, destination_path)
48
-
49
+
49
50
  # Se estivermos copiando para um destino, verifica o diretório de destino
50
51
  # Caso contrário, verifica o diretório de origem
51
52
  target_path = destination_path || origin_path
52
53
  remove_empty_directories(target_path)
53
54
 
54
- puts "Done! Files have been refactored#{destination_path ? " to the destination" : " in place"}."
55
+ puts "Done! Files have been refactored#{destination_path ? ' to the destination' : ' in place'}."
55
56
  end
56
57
 
57
58
  private
58
59
 
59
60
  def get_files_to_process(origin_path)
60
- Dir.glob(File.join(origin_path, "**", "*"), File::FNM_DOTMATCH).reject do |file_name|
61
- File.directory?(file_name) || IGNORED_DIRECTORIES.any? { |dir| file_name.include?(dir) }
61
+ Dir.glob(File.join(origin_path, '**', '*'), File::FNM_DOTMATCH).reject do |file_name|
62
+ next true if File.directory?(file_name)
63
+ next true if IGNORED_DIRECTORIES.any? { |dir| file_name.include?(dir) }
64
+
65
+ false
62
66
  end
63
67
  end
64
68
 
69
+ def is_binary_file?(file_name)
70
+ binary_extensions = ['.pdf', '.png', '.jpg', '.jpeg', '.svg', '.ico', '.gif', '.zip', '.gz', '.tar', '.bin',
71
+ '.exe', '.dll', '.so', '.dylib']
72
+ binary_extensions.any? { |ext| file_name.downcase.end_with?(ext) }
73
+ end
74
+
65
75
  def process_files_in_parallel(files, dict, origin_path, destination_path)
66
76
  progress_bar = ProgressBar.create(
67
77
  total: files.size,
68
78
  format: "%a %b\u{15E7}%i %p%% %t",
69
- progress_mark: " ",
70
- remainder_mark: "\u{FF65}",
79
+ progress_mark: ' ',
80
+ remainder_mark: "\u{FF65}"
71
81
  )
72
82
 
73
83
  Parallel.each(files, in_threads: Parallel.processor_count) do |file_name|
@@ -82,7 +92,7 @@ module CLAISS
82
92
  possible_paths = [
83
93
  json_file,
84
94
  File.expand_path(json_file),
85
- File.expand_path("~/.claiss/#{json_file}"),
95
+ File.expand_path("~/.claiss/#{json_file}")
86
96
  ]
87
97
 
88
98
  found_file = possible_paths.find { |path| File.exist?(path) }
@@ -96,17 +106,17 @@ module CLAISS
96
106
  puts "Ops! O arquivo JSON não está no formato correto. Erro: #{e.message}"
97
107
  end
98
108
  else
99
- puts "Hmm, não consegui encontrar o arquivo. Procurei nesses lugares:"
109
+ puts 'Hmm, não consegui encontrar o arquivo. Procurei nesses lugares:'
100
110
  possible_paths.each { |path| puts " - #{path}" }
101
111
  end
102
112
 
103
- puts "Vamos usar o dicionário interativo em vez disso, tá bom?"
113
+ puts 'Vamos usar o dicionário interativo em vez disso, tá bom?'
104
114
  interactive_dictionary
105
115
  else
106
116
  interactive_dictionary
107
117
  end
108
118
  end
109
-
119
+
110
120
  def interactive_dictionary
111
121
  # Em ambiente de teste, retorna um dicionário de substituição padrão
112
122
  if ENV['RACK_ENV'] == 'test' || ENV['RAILS_ENV'] == 'test' || caller.any? { |line| line.include?('rspec') }
@@ -118,49 +128,54 @@ module CLAISS
118
128
  }
119
129
  else
120
130
  # Implementação interativa real iria aqui
121
- puts "Modo interativo não implementado. Retornando dicionário vazio."
131
+ puts 'Modo interativo não implementado. Retornando dicionário vazio.'
122
132
  {}
123
133
  end
124
134
  end
125
135
 
126
136
  def process_files(origin_path, dict, destination_path)
127
- Dir.glob(File.join(origin_path, "**", "*"), File::FNM_DOTMATCH) do |file_name|
137
+ Dir.glob(File.join(origin_path, '**', '*'), File::FNM_DOTMATCH) do |file_name|
128
138
  next if File.directory?(file_name)
129
139
  next if IGNORED_DIRECTORIES.any? { |dir| file_name.include?(dir) }
140
+
130
141
  refactor_file(file_name, dict, origin_path, destination_path)
131
142
  end
132
143
  end
133
144
 
134
145
  def refactor_file(file_name, dict, origin_path, destination_path)
146
+ if is_binary_file?(file_name)
147
+ LOGGER.info("Processing binary file (renaming only): ...#{File.basename(file_name)}")
148
+ process_binary_file_rename(file_name, dict, origin_path, destination_path)
149
+ return
150
+ end
151
+
135
152
  begin
136
153
  # First, try to read the file as UTF-8
137
- text = File.read(file_name, encoding: "UTF-8")
154
+ text = File.read(file_name, encoding: 'UTF-8')
138
155
  rescue Encoding::InvalidByteSequenceError
139
156
  # If UTF-8 reading fails, fall back to binary reading and force UTF-8 encoding
140
157
  # This approach helps handle files with mixed or unknown encodings
141
158
  truncated_file_name = File.basename(file_name)
142
159
  LOGGER.warn("Invalid UTF-8 byte sequence in ...#{truncated_file_name}. Falling back to binary reading.")
143
- text = File.read(file_name, encoding: "BINARY")
144
- text.force_encoding("UTF-8")
160
+ text = File.read(file_name, encoding: 'BINARY')
161
+ text.force_encoding('UTF-8')
145
162
  # Replace any invalid or undefined characters with empty string
146
- text.encode!("UTF-8", invalid: :replace, undef: :replace, replace: "")
163
+ text.encode!('UTF-8', invalid: :replace, undef: :replace, replace: '')
147
164
  end
148
165
 
149
166
  text_changed = false
150
167
  dict.each do |search, replace|
151
- if text.gsub!(/#{Regexp.escape(search)}/, replace)
152
- text_changed = true
153
- end
168
+ text_changed = true if text.gsub!(/#{Regexp.escape(search)}/, replace)
154
169
  end
155
170
 
156
171
  relative_path = Pathname.new(file_name).relative_path_from(Pathname.new(origin_path))
157
172
  new_relative_path = replace_in_path(relative_path.to_s, dict)
158
173
 
159
- if destination_path
160
- new_file_name = File.join(destination_path, new_relative_path)
161
- else
162
- new_file_name = File.join(origin_path, new_relative_path)
163
- end
174
+ new_file_name = if destination_path
175
+ File.join(destination_path, new_relative_path)
176
+ else
177
+ File.join(origin_path, new_relative_path)
178
+ end
164
179
 
165
180
  new_dir = File.dirname(new_file_name)
166
181
  FileUtils.mkdir_p(new_dir) unless File.directory?(new_dir)
@@ -170,19 +185,44 @@ module CLAISS
170
185
  if destination_path || new_file_name != file_name
171
186
  truncated_old = "...#{File.basename(file_name)}"
172
187
  truncated_new = "...#{File.basename(new_file_name)}"
173
- LOGGER.info("File #{destination_path ? "copied" : "renamed"} from #{truncated_old} to #{truncated_new}")
188
+ LOGGER.info("File #{destination_path ? 'copied' : 'renamed'} from #{truncated_old} to #{truncated_new}")
174
189
  else
175
190
  truncated_file = "...#{File.basename(file_name)}"
176
191
  LOGGER.info("File contents updated: #{truncated_file}")
177
192
  end
178
193
  File.delete(file_name) if !destination_path && new_file_name != file_name
179
194
  end
180
- rescue => e
195
+ rescue StandardError => e
181
196
  truncated_file = "...#{File.basename(file_name)}"
182
197
  LOGGER.error("Error processing file #{truncated_file}: #{e.message}")
183
198
  LOGGER.debug(e.backtrace.join("\n"))
184
199
  end
185
200
 
201
+ def process_binary_file_rename(file_name, dict, origin_path, destination_path)
202
+ relative_path = Pathname.new(file_name).relative_path_from(Pathname.new(origin_path))
203
+ new_relative_path = replace_in_path(relative_path.to_s, dict)
204
+
205
+ new_file_name = if destination_path
206
+ File.join(destination_path, new_relative_path)
207
+ else
208
+ File.join(origin_path, new_relative_path)
209
+ end
210
+
211
+ # Se o nome do arquivo mudou, move/renomeia o arquivo
212
+ if new_file_name != file_name
213
+ new_dir = File.dirname(new_file_name)
214
+ FileUtils.mkdir_p(new_dir) unless File.directory?(new_dir)
215
+
216
+ FileUtils.mv(file_name, new_file_name, force: true)
217
+
218
+ truncated_old = "...#{File.basename(file_name)}"
219
+ truncated_new = "...#{File.basename(new_file_name)}"
220
+ LOGGER.info("Binary file renamed from #{truncated_old} to #{truncated_new}")
221
+ end
222
+ rescue StandardError => e
223
+ LOGGER.error("Error renaming binary file #{file_name}: #{e.message}")
224
+ end
225
+
186
226
  def replace_in_path(path, dict)
187
227
  dict.reduce(path) do |s, (search, replace)|
188
228
  s.gsub(/#{Regexp.escape(search)}/, replace)
@@ -190,49 +230,52 @@ module CLAISS
190
230
  end
191
231
 
192
232
  def remove_empty_directories(origin_path)
193
- Dir.glob(File.join(origin_path, "**", "*"), File::FNM_DOTMATCH).reverse_each do |dir_name|
233
+ Dir.glob(File.join(origin_path, '**', '*'), File::FNM_DOTMATCH).reverse_each do |dir_name|
194
234
  next unless File.directory?(dir_name)
195
- next if dir_name.include?(".git/") || dir_name.include?("node_modules/") # Ignorar pastas .git e node_modules
196
- next if dir_name == "." || dir_name == ".." # Ignorar diretórios especiais . e ..
197
- if (Dir.entries(dir_name) - %w[. ..]).empty?
198
- begin
199
- Dir.rmdir(dir_name)
200
- puts "Diretório vazio removido: #{dir_name}"
201
- rescue Errno::ENOTEMPTY, Errno::EINVAL => e
202
- puts "Não foi possível remover o diretório: #{dir_name}. Erro: #{e.message}"
203
- end
235
+ next if dir_name.include?('.git/') || dir_name.include?('node_modules/') # Ignorar pastas .git e node_modules
236
+ next if ['.', '..'].include?(dir_name) # Ignorar diretórios especiais . e ..
237
+
238
+ next unless (Dir.entries(dir_name) - %w[. ..]).empty?
239
+
240
+ begin
241
+ Dir.rmdir(dir_name)
242
+ puts "Diretório vazio removido: #{dir_name}"
243
+ rescue Errno::ENOTEMPTY, Errno::EINVAL => e
244
+ puts "Não foi possível remover o diretório: #{dir_name}. Erro: #{e.message}"
204
245
  end
205
246
  end
206
247
  end
207
248
  end
208
249
 
209
250
  class FixRubyPermissions < Dry::CLI::Command
210
- desc "Fix permissions for a Ruby project"
251
+ desc 'Fix permissions for a Ruby project'
211
252
 
212
- argument :path, type: :string, required: false, default: ".", desc: "Path to the Ruby project (default: current directory)"
253
+ argument :path, type: :string, required: false, default: '.',
254
+ desc: 'Path to the Ruby project (default: current directory)'
213
255
 
214
256
  example [
215
- "",
216
- "path/to/ruby/project",
257
+ '',
258
+ 'path/to/ruby/project'
217
259
  ]
218
260
 
219
- def call(path: ".", **)
261
+ def call(path: '.', **)
220
262
  path = File.expand_path(path)
221
263
 
222
- Dir.glob(File.join(path, "**", "*"), File::FNM_DOTMATCH) do |item|
223
- next if item == "." || item == ".."
224
- next if item.include?("node_modules/") # Ignore node_modules folder
264
+ Dir.glob(File.join(path, '**', '*'), File::FNM_DOTMATCH) do |item|
265
+ next if ['.', '..'].include?(item)
266
+ next if item.include?('node_modules/') # Ignore node_modules folder
267
+
225
268
  if File.directory?(item)
226
- File.chmod(0755, item)
269
+ File.chmod(0o755, item)
227
270
  else
228
271
  fix_file_permissions(item)
229
272
  end
230
273
  end
231
274
 
232
- executable_files = ["bundle", "rails", "rake", "spring"]
275
+ executable_files = %w[bundle rails rake spring]
233
276
  executable_files.each do |file|
234
- file_path = File.join(path, "bin", file)
235
- File.chmod(0755, file_path) if File.exist?(file_path)
277
+ file_path = File.join(path, 'bin', file)
278
+ File.chmod(0o755, file_path) if File.exist?(file_path)
236
279
  end
237
280
 
238
281
  puts "Permissions fixed for Ruby project at #{path}"
@@ -243,28 +286,28 @@ module CLAISS
243
286
  def fix_file_permissions(file)
244
287
  # Não altera permissões de arquivos em diretórios restritos
245
288
  return if file.include?('/restricted/')
246
-
289
+
247
290
  # Obtém o modo atual do arquivo
248
- current_mode = File.stat(file).mode & 0777
249
-
291
+ current_mode = File.stat(file).mode & 0o777
292
+
250
293
  # Se o arquivo já tem permissões restritivas (menos de 0600), não altera
251
294
  return if current_mode < 0o600
252
-
295
+
253
296
  # Define as permissões apropriadas
254
- new_mode = if File.extname(file) == ".rb" || file.include?("/bin/")
297
+ new_mode = if File.extname(file) == '.rb' || file.include?('/bin/')
255
298
  0o755 # Executável
256
299
  else
257
300
  0o644 # Apenas leitura/escrita para o dono
258
301
  end
259
-
302
+
260
303
  # Aplica as permissões apenas se forem diferentes
261
304
  File.chmod(new_mode, file) if new_mode != current_mode
262
- rescue => e
305
+ rescue StandardError => e
263
306
  LOGGER.warn("Could not change permissions for #{file}: #{e.message}")
264
307
  end
265
308
  end
266
309
  end
267
310
 
268
- require_relative "claiss/version"
269
- require_relative "claiss/commands"
270
- require_relative "claiss/cli"
311
+ require_relative 'claiss/version'
312
+ require_relative 'claiss/commands'
313
+ require_relative 'claiss/cli'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claiss
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.5
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Júlio Papel
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-05-31 00:00:00.000000000 Z
10
+ date: 2025-06-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: dry-cli