bddgenx 2.3.2 → 2.4.2
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.
- checksums.yaml +4 -4
- data/README.md +48 -20
- data/Rakefile +23 -36
- data/VERSION +1 -1
- data/lib/bddgenx/generators/generator.rb +31 -27
- data/lib/bddgenx/generators/runner.rb +60 -49
- data/lib/bddgenx/generators/steps_generator.rb +32 -30
- data/lib/bddgenx/ia/chatgtp_cliente.rb +29 -16
- data/lib/bddgenx/ia/gemini_cliente.rb +32 -15
- data/lib/bddgenx/locales/en.yml +28 -0
- data/lib/bddgenx/locales/pt.yml +27 -0
- data/lib/bddgenx/support/loader.rb +31 -0
- data/lib/bddgenx.rb +0 -3
- data/lib/env.rb +95 -37
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cfed14eace60df849622da45beb5a391ef24a8f2cec73191e86d993183f47e1
|
4
|
+
data.tar.gz: ee6cae8cc16805c90028f461edc51e0327471d7bcbb9869aec4119cf8adc945e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e0c7e03df28a0bec6a70a0324843ca774b2f1f9b2523b21ded4106ae85436478215462c9037c5efcee12802d26afc1f400eea693a9bdc8c1bf7ded9d3b2a66d
|
7
|
+
data.tar.gz: 8fcbaebb88edd22bd3755650988797f4ffef3aac64e0d117cee6528ebf35d0db1e0b027a1242c4999b77421143eef993be0c1dcd16a4d52a39a7ecc1b4d978a2
|
data/README.md
CHANGED
@@ -149,34 +149,42 @@ Bddgenx::Runner.execute
|
|
149
149
|
|
150
150
|
## 📦 Geração manual via Rake
|
151
151
|
```Ruby
|
152
|
-
require_relative 'lib/env' # ajuste conforme seu projeto
|
153
152
|
require 'rake'
|
153
|
+
require 'bddgenx'
|
154
154
|
|
155
155
|
namespace :bddgenx do
|
156
|
-
desc '
|
157
|
-
task :generate
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
156
|
+
desc 'Executa geração interativa: escolha entre static, chatgpt, gemini ou deepseek'
|
157
|
+
task :generate do
|
158
|
+
puts "=== Qual modo deseja usar para gerar os cenários? ==="
|
159
|
+
puts "1. static (sem IA)"
|
160
|
+
puts "2. chatgpt (via OpenAI)"
|
161
|
+
puts "3. gemini (via Google)"
|
162
|
+
print "Digite o número (1-3): "
|
163
|
+
|
164
|
+
escolha = STDIN.gets.chomp.to_i
|
165
|
+
|
166
|
+
modo = case escolha
|
167
|
+
when 1 then :static
|
168
|
+
when 2 then :chatgpt
|
169
|
+
when 3 then :gemini
|
170
|
+
else
|
171
|
+
puts "❌ Opção inválida. Saindo."; exit 1
|
172
|
+
end
|
165
173
|
|
166
174
|
Bddgenx.configure do |config|
|
167
175
|
config.mode = modo
|
168
176
|
config.openai_api_key_env = 'OPENAI_API_KEY'
|
169
177
|
config.gemini_api_key_env = 'GEMINI_API_KEY'
|
170
|
-
config.deepseek_api_key_env = 'DEEPSEEK_API_KEY'
|
171
178
|
end
|
172
179
|
|
173
|
-
|
180
|
+
# ⚠️ Limpa o ARGV antes de executar para evitar que [static] seja interpretado como nome de arquivo
|
181
|
+
ARGV.clear
|
174
182
|
|
175
|
-
|
183
|
+
ENV['BDDGENX_MODE'] = modo.to_s
|
184
|
+
puts "\n⚙️ Modo selecionado: #{modo}\n\n"
|
176
185
|
Bddgenx::Runner.execute
|
177
186
|
end
|
178
187
|
end
|
179
|
-
|
180
188
|
```
|
181
189
|
|
182
190
|
## 📝 Formato do Arquivo de Entrada (`.txt`)
|
@@ -184,17 +192,37 @@ end
|
|
184
192
|
```txt
|
185
193
|
# language: pt
|
186
194
|
Como um usuário do sistema
|
187
|
-
Quero fazer login
|
188
|
-
Para acessar minha conta
|
195
|
+
Quero fazer login corretamente
|
196
|
+
Para acessar minha conta com segurança
|
197
|
+
|
198
|
+
[CONTEXT]
|
199
|
+
Dado que estou na tela de login
|
189
200
|
|
190
201
|
[SUCCESS]
|
191
|
-
Quando preencho
|
202
|
+
Quando preencho email e senha válidos
|
192
203
|
Então vejo a tela inicial
|
193
204
|
|
205
|
+
[SUCCESS]
|
206
|
+
Quando tento logar com "<email>" e "<senha>"
|
207
|
+
Então recebo "<mensagem>"
|
208
|
+
|
209
|
+
[EXAMPLES]
|
210
|
+
| email | senha | mensagem |
|
211
|
+
| user@site.com | 123456 | login realizado |
|
212
|
+
| errado@site.com | senha | credenciais inválidas |
|
213
|
+
| | senha | email é obrigatório |
|
214
|
+
| user@site.com | | senha é obrigatória |
|
215
|
+
|
216
|
+
[SUCCESS]
|
217
|
+
Quando deixo o campo "<campo>" vazio
|
218
|
+
Então recebo a mensagem "<mensagem>"
|
219
|
+
|
194
220
|
[EXAMPLES]
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
221
|
+
| campo | mensagem |
|
222
|
+
| | login realizado |
|
223
|
+
| | credenciais inválidas |
|
224
|
+
| email | email é obrigatório |
|
225
|
+
| senha | senha é obrigatória |
|
198
226
|
```
|
199
227
|
|
200
228
|
---
|
data/Rakefile
CHANGED
@@ -1,49 +1,36 @@
|
|
1
|
-
|
2
|
-
require_relative 'lib/env'
|
1
|
+
require 'bddgenx'
|
3
2
|
require 'rake'
|
4
3
|
|
5
4
|
namespace :bddgenx do
|
6
|
-
desc '
|
7
|
-
task :setup do
|
8
|
-
Bddgenx::Setup.inicializar_projeto
|
9
|
-
end
|
10
|
-
|
11
|
-
desc 'Executa a geração BDD usando o modo atual (static, chatgpt, gemini)'
|
5
|
+
desc 'Executa geração interativa: escolha entre static, chatgpt, gemini ou deepseek'
|
12
6
|
task :generate do
|
13
|
-
puts "
|
7
|
+
puts "=== Qual modo deseja usar para gerar os cenários? ==="
|
8
|
+
puts "1. static (sem IA)"
|
9
|
+
puts "2. chatgpt (via OpenAI)"
|
10
|
+
puts "3. gemini (via Google)"
|
11
|
+
print "Digite o número (1-3): "
|
14
12
|
|
15
|
-
|
16
|
-
ARGV.clear
|
13
|
+
escolha = STDIN.gets.chomp.to_i
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
ENV['BDDGENX_MODE'] = 'static'
|
27
|
-
Rake::Task['bddgenx:generate'].invoke
|
28
|
-
end
|
15
|
+
modo = case escolha
|
16
|
+
when 1 then :static
|
17
|
+
when 2 then :chatgpt
|
18
|
+
when 3 then :gemini
|
19
|
+
else
|
20
|
+
puts "❌ Opção inválida. Saindo."; exit 1
|
21
|
+
end
|
29
22
|
|
30
|
-
desc 'Gera features usando ChatGPT'
|
31
|
-
task :chatgpt do
|
32
23
|
Bddgenx.configure do |config|
|
33
|
-
config.mode =
|
24
|
+
config.mode = modo
|
34
25
|
config.openai_api_key_env = 'OPENAI_API_KEY'
|
35
|
-
end
|
36
|
-
ENV['BDDGENX_MODE'] = 'chatgpt'
|
37
|
-
Rake::Task['bddgenx:generate'].invoke
|
38
|
-
end
|
39
|
-
|
40
|
-
desc 'Gera features usando Gemini'
|
41
|
-
task :gemini do
|
42
|
-
Bddgenx.configure do |config|
|
43
|
-
config.mode = :gemini
|
44
26
|
config.gemini_api_key_env = 'GEMINI_API_KEY'
|
45
27
|
end
|
46
|
-
|
47
|
-
|
28
|
+
|
29
|
+
# ⚠️ Limpa o ARGV antes de executar para evitar que [static] seja interpretado como nome de arquivo
|
30
|
+
ARGV.clear
|
31
|
+
|
32
|
+
ENV['BDDGENX_MODE'] = modo.to_s
|
33
|
+
puts "\n⚙️ Modo selecionado: #{modo}\n\n"
|
34
|
+
Bddgenx::Runner.execute
|
48
35
|
end
|
49
36
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.2
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# lib/bddgenx/generator.rb
|
2
2
|
# encoding: utf-8
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# Suporta Gherkin em Português e Inglês,
|
7
|
-
#
|
4
|
+
# Classe responsável pela geração de arquivos `.feature` no formato Gherkin
|
5
|
+
# a partir de arquivos de entrada de histórias ou estruturas hash.
|
6
|
+
# Suporta palavras-chave Gherkin em Português e Inglês, além de integração com IA
|
7
|
+
# (ChatGPT ou Gemini) para geração automática de cenários.
|
8
8
|
|
9
9
|
module Bddgenx
|
10
10
|
class Generator
|
@@ -14,37 +14,39 @@ module Bddgenx
|
|
14
14
|
# Palavras-chave do Gherkin em Inglês
|
15
15
|
GHERKIN_KEYS_EN = %w[Given When Then And But].freeze
|
16
16
|
|
17
|
-
# Mapeamento
|
17
|
+
# Mapeamento PT → EN
|
18
18
|
GHERKIN_MAP_PT_EN = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
|
19
19
|
|
20
|
-
# Mapeamento
|
20
|
+
# Mapeamento EN → PT
|
21
21
|
GHERKIN_MAP_EN_PT = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h
|
22
22
|
|
23
|
-
# Todas as palavras-chave reconhecidas
|
23
|
+
# Todas as palavras-chave reconhecidas pelos parsers
|
24
24
|
ALL_KEYS = GHERKIN_KEYS_PT + GHERKIN_KEYS_EN
|
25
25
|
|
26
26
|
##
|
27
27
|
# Extrai todas as linhas de exemplo de um array de strings.
|
28
28
|
#
|
29
|
-
# @param raw [Array<String>]
|
30
|
-
# @return [Array<String>]
|
29
|
+
# @param raw [Array<String>] Array com linhas do grupo de passos
|
30
|
+
# @return [Array<String>] Somente as linhas que contêm exemplos (começam com '|')
|
31
31
|
def self.dividir_examples(raw)
|
32
32
|
raw.select { |l| l.strip.start_with?('|') }
|
33
33
|
end
|
34
34
|
|
35
35
|
##
|
36
|
-
# Gera o conteúdo de um arquivo `.feature`
|
37
|
-
# Pode operar em três modos:
|
38
|
-
#
|
36
|
+
# Gera o conteúdo de um arquivo `.feature` baseado na história fornecida.
|
37
|
+
# Pode operar em três modos:
|
38
|
+
# - :static (sem IA)
|
39
|
+
# - :chatgpt (usando OpenAI)
|
40
|
+
# - :gemini (usando Google Gemini)
|
39
41
|
#
|
40
|
-
# @param input [String, Hash]
|
41
|
-
# @param override_path [String, nil]
|
42
|
-
# @return [Array
|
42
|
+
# @param input [String, Hash] Caminho para um `.txt` ou estrutura de história já processada
|
43
|
+
# @param override_path [String, nil] Caminho alternativo de saída
|
44
|
+
# @return [Array<String, String>] Caminho e conteúdo do `.feature`
|
43
45
|
def self.gerar_feature(input, override_path = nil)
|
44
46
|
modo = ENV['BDD_MODE']&.to_sym || :static
|
45
47
|
|
46
48
|
if input.is_a?(String) && input.end_with?('.txt') && [:gemini, :chatgpt].include?(modo)
|
47
|
-
#
|
49
|
+
# Geração com IA
|
48
50
|
raw_txt = File.read(input)
|
49
51
|
historia = {
|
50
52
|
idioma: 'pt',
|
@@ -66,14 +68,14 @@ module Bddgenx
|
|
66
68
|
passos: GherkinCleaner.limpar(texto_gerado).lines.map(&:strip).reject(&:empty?)
|
67
69
|
}
|
68
70
|
else
|
69
|
-
#
|
71
|
+
# Geração estática
|
70
72
|
historia = input.is_a?(String) ? Parser.ler_historia(input) : input
|
71
73
|
end
|
72
74
|
|
73
75
|
idioma = historia[:idioma] || 'pt'
|
74
76
|
cont = 1
|
75
77
|
|
76
|
-
#
|
78
|
+
# Cria nome-base do arquivo .feature
|
77
79
|
nome_base = historia[:quero]
|
78
80
|
.gsub(/[^a-z0-9]/i, '_')
|
79
81
|
.downcase
|
@@ -84,7 +86,7 @@ module Bddgenx
|
|
84
86
|
|
85
87
|
caminho = override_path || "features/#{nome_base}.feature"
|
86
88
|
|
87
|
-
#
|
89
|
+
# Palavras-chave localizadas
|
88
90
|
palavras = {
|
89
91
|
feature: idioma == 'en' ? 'Feature' : 'Funcionalidade',
|
90
92
|
contexto: idioma == 'en' ? 'Background' : 'Contexto',
|
@@ -94,6 +96,7 @@ module Bddgenx
|
|
94
96
|
regra: idioma == 'en' ? 'Rule' : 'Regra'
|
95
97
|
}
|
96
98
|
|
99
|
+
# Cabeçalho do arquivo .feature
|
97
100
|
conteudo = <<~GHK
|
98
101
|
# language: #{idioma}
|
99
102
|
#{palavras[:feature]}: #{historia[:quero].sub(/^Quero\s*/i,'')}
|
@@ -102,14 +105,14 @@ module Bddgenx
|
|
102
105
|
# #{historia[:para]}
|
103
106
|
GHK
|
104
107
|
|
108
|
+
# Controle para não repetir passos
|
105
109
|
passos_unicos = Set.new
|
106
110
|
pt_map = GHERKIN_MAP_PT_EN
|
107
111
|
en_map = GHERKIN_MAP_EN_PT
|
108
112
|
detect = ALL_KEYS
|
109
|
-
cont = 1
|
110
113
|
|
111
114
|
historia[:grupos].each do |grupo|
|
112
|
-
passos = grupo[:passos]
|
115
|
+
passos = grupo[:passos] || []
|
113
116
|
exemplos = grupo[:exemplos] || []
|
114
117
|
next if passos.empty?
|
115
118
|
|
@@ -151,20 +154,21 @@ module Bddgenx
|
|
151
154
|
end
|
152
155
|
|
153
156
|
##
|
154
|
-
#
|
157
|
+
# Retorna o caminho padrão do arquivo `.feature` baseado no nome do `.txt`.
|
155
158
|
#
|
156
|
-
# @param arquivo_txt [String]
|
157
|
-
# @return [String]
|
159
|
+
# @param arquivo_txt [String] Caminho do arquivo .txt
|
160
|
+
# @return [String] Caminho final da feature gerada
|
158
161
|
def self.path_para_feature(arquivo_txt)
|
159
162
|
nome = File.basename(arquivo_txt, '.txt')
|
160
163
|
File.join('features', "#{nome}.feature")
|
161
164
|
end
|
162
165
|
|
163
166
|
##
|
164
|
-
# Salva o conteúdo
|
167
|
+
# Salva o conteúdo do arquivo `.feature` no disco.
|
168
|
+
# Cria diretórios intermediários, se necessário.
|
165
169
|
#
|
166
|
-
# @param caminho [String]
|
167
|
-
# @param conteudo [String]
|
170
|
+
# @param caminho [String] Caminho completo do arquivo
|
171
|
+
# @param conteudo [String] Conteúdo da feature a ser salva
|
168
172
|
# @return [void]
|
169
173
|
def self.salvar_feature(caminho, conteudo)
|
170
174
|
FileUtils.mkdir_p(File.dirname(caminho))
|
@@ -2,28 +2,35 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
#
|
4
4
|
# Este arquivo define a classe Runner (CLI) da gem bddgenx,
|
5
|
-
# responsável por orquestrar o fluxo de
|
6
|
-
# validação, geração de features, steps,
|
5
|
+
# responsável por orquestrar todo o fluxo de geração BDD:
|
6
|
+
# leitura e validação de histórias, geração de features, steps,
|
7
|
+
# exportação de PDFs e controle de modo (static / IA).
|
8
|
+
|
7
9
|
require_relative '../../bddgenx'
|
8
10
|
|
9
11
|
module Bddgenx
|
10
|
-
#
|
12
|
+
# Classe principal de execução da gem.
|
13
|
+
# Atua como ponto de entrada (CLI) para processar arquivos de entrada
|
14
|
+
# e gerar todos os artefatos BDD relacionados.
|
11
15
|
class Runner
|
12
|
-
|
13
|
-
|
14
|
-
#
|
16
|
+
|
17
|
+
##
|
18
|
+
# Retorna a lista de arquivos de entrada.
|
19
|
+
# Se houver argumentos em ARGV, utiliza-os como nomes de arquivos `.txt`.
|
20
|
+
# Caso contrário, chama prompt interativo.
|
15
21
|
#
|
16
|
-
# @param input_dir [String]
|
17
|
-
# @return [Array<String>] Lista de
|
22
|
+
# @param input_dir [String] Caminho do diretório de entrada
|
23
|
+
# @return [Array<String>] Lista de arquivos `.txt` a processar
|
18
24
|
def self.choose_files(input_dir)
|
19
25
|
ARGV.any? ? selecionar_arquivos_txt(input_dir) : choose_input(input_dir)
|
20
26
|
end
|
21
27
|
|
22
|
-
|
23
|
-
#
|
28
|
+
##
|
29
|
+
# Processa argumentos ARGV e converte em caminhos válidos de arquivos `.txt`.
|
30
|
+
# Adiciona extensão `.txt` se ausente e remove arquivos inexistentes.
|
24
31
|
#
|
25
|
-
# @param input_dir [String] Diretório
|
26
|
-
# @return [Array<String>] Caminhos válidos para
|
32
|
+
# @param input_dir [String] Diretório onde estão os arquivos
|
33
|
+
# @return [Array<String>] Caminhos válidos para arquivos de entrada
|
27
34
|
def self.selecionar_arquivos_txt(input_dir)
|
28
35
|
ARGV.map do |arg|
|
29
36
|
nome = arg.end_with?('.txt') ? arg : "#{arg}.txt"
|
@@ -36,12 +43,12 @@ module Bddgenx
|
|
36
43
|
end.compact
|
37
44
|
end
|
38
45
|
|
39
|
-
|
40
|
-
#
|
46
|
+
##
|
47
|
+
# Interface interativa para o usuário selecionar arquivos `.txt` a processar.
|
48
|
+
# Exibe uma lista dos arquivos disponíveis e solicita um número ao usuário.
|
41
49
|
#
|
42
50
|
# @param input_dir [String] Diretório de entrada
|
43
|
-
# @
|
44
|
-
# @return [Array<String>] Um único arquivo escolhido ou todos se ENTER
|
51
|
+
# @return [Array<String>] Lista com o arquivo escolhido ou todos
|
45
52
|
def self.choose_input(input_dir)
|
46
53
|
files = Dir.glob(File.join(input_dir, '*.txt'))
|
47
54
|
if files.empty?
|
@@ -61,29 +68,29 @@ module Bddgenx
|
|
61
68
|
[files[idx]]
|
62
69
|
end
|
63
70
|
|
64
|
-
|
65
|
-
#
|
66
|
-
# -
|
67
|
-
# -
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
71
|
+
##
|
72
|
+
# Executa o fluxo completo de geração BDD:
|
73
|
+
# - Define o modo (static / IA)
|
74
|
+
# - Coleta arquivos de entrada
|
75
|
+
# - Valida as histórias
|
76
|
+
# - Gera arquivos `.feature` e `steps`
|
77
|
+
# - Exporta PDFs e faz backup de versões antigas
|
78
|
+
#
|
79
|
+
# O modo de execução é lido da variável de ambiente `BDDGENX_MODE`.
|
73
80
|
#
|
74
81
|
# @return [void]
|
75
82
|
def self.execute
|
76
83
|
modo = ENV['BDDGENX_MODE'] || 'static'
|
77
|
-
|
78
84
|
input_dir = 'input'
|
79
85
|
Dir.mkdir(input_dir) unless Dir.exist?(input_dir)
|
80
86
|
|
81
87
|
arquivos = choose_files(input_dir)
|
82
88
|
if arquivos.empty?
|
83
|
-
warn
|
89
|
+
warn I18n.t('messages.no_files')
|
90
|
+
exit 1
|
84
91
|
end
|
85
92
|
|
86
|
-
#
|
93
|
+
# Contadores de geração
|
87
94
|
total = features = steps = ignored = 0
|
88
95
|
skipped_steps = []
|
89
96
|
generated_pdfs = []
|
@@ -91,63 +98,67 @@ module Bddgenx
|
|
91
98
|
|
92
99
|
arquivos.each do |arquivo|
|
93
100
|
total += 1
|
94
|
-
puts "\n🔍
|
101
|
+
puts "\n🔍 #{I18n.t('messages.processing')}: #{arquivo}"
|
95
102
|
|
96
103
|
historia = Parser.ler_historia(arquivo)
|
97
104
|
unless Validator.validar(historia)
|
98
105
|
ignored += 1
|
99
|
-
puts "❌
|
106
|
+
puts "❌ #{I18n.t('messages.invalid_story')}: #{arquivo}"
|
100
107
|
next
|
101
108
|
end
|
102
109
|
|
103
|
-
# Geração
|
104
|
-
if
|
105
|
-
puts
|
110
|
+
# Geração via IA (ChatGPT, Gemini, Deepseek)
|
111
|
+
if %w[gemini chatgpt deepseek].include?(modo)
|
112
|
+
puts I18n.t('messages.start_ia', modo: modo.capitalize)
|
106
113
|
idioma = IA::GeminiCliente.detecta_idioma_arquivo(arquivo)
|
107
|
-
|
108
|
-
|
114
|
+
|
115
|
+
feature_text = Support::Loader.run(I18n.t('messages.ia_waiting'), :default) do
|
116
|
+
case modo
|
117
|
+
when 'gemini'
|
109
118
|
IA::GeminiCliente.gerar_cenarios(historia, idioma)
|
110
|
-
|
119
|
+
when 'chatgpt'
|
111
120
|
IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
121
|
+
when 'deepseek'
|
122
|
+
IA::DeepseekCliente.gerar_cenarios(historia, idioma)
|
112
123
|
end
|
124
|
+
end
|
125
|
+
|
113
126
|
if feature_text
|
114
127
|
feature_path = Generator.path_para_feature(arquivo)
|
115
128
|
feature_content = Bddgenx::GherkinCleaner.limpar(feature_text)
|
116
129
|
else
|
117
130
|
ignored += 1
|
118
|
-
puts
|
131
|
+
puts I18n.t('messages.feature_fail', arquivo: arquivo)
|
119
132
|
next
|
120
133
|
end
|
121
134
|
else
|
122
|
-
|
135
|
+
# Geração local (modo static)
|
136
|
+
feature_path, feature_content = Support::Loader.run(I18n.t('messages.start_static'), :dots) do
|
137
|
+
sleep(2)
|
138
|
+
Generator.gerar_feature(historia)
|
139
|
+
end
|
123
140
|
end
|
124
141
|
|
125
142
|
Backup.salvar_versao_antiga(feature_path)
|
126
143
|
features += 1 if Generator.salvar_feature(feature_path, feature_content)
|
127
144
|
|
128
|
-
# Geração de steps
|
129
145
|
if StepsGenerator.gerar_passos(feature_path)
|
130
146
|
steps += 1
|
131
147
|
else
|
132
148
|
skipped_steps << feature_path
|
133
149
|
end
|
134
150
|
|
135
|
-
# Exportação de PDF (apenas novos)
|
136
151
|
FileUtils.mkdir_p('reports')
|
137
152
|
result = PDFExporter.exportar_todos(only_new: true)
|
138
153
|
generated_pdfs.concat(result[:generated])
|
139
154
|
skipped_pdfs.concat(result[:skipped])
|
140
155
|
end
|
141
156
|
|
142
|
-
#
|
143
|
-
puts "\n
|
144
|
-
puts "-
|
145
|
-
puts "-
|
146
|
-
puts "-
|
147
|
-
puts "- Steps ignorados: #{skipped_steps.size}"
|
148
|
-
puts "- PDFs gerados: #{generated_pdfs.size}"
|
149
|
-
puts "- PDFs já existentes: #{skipped_pdfs.size}"
|
150
|
-
puts "- Histórias ignoradas: #{ignored}"
|
157
|
+
# Resumo final
|
158
|
+
puts "\n#{I18n.t('messages.processing_done')}"
|
159
|
+
puts "- #{I18n.t('messages.total_histories')}: #{total}"
|
160
|
+
puts "- #{I18n.t('messages.features_generated')}: #{features}"
|
161
|
+
puts "- #{I18n.t('messages.steps_generated')}: #{steps}"
|
151
162
|
end
|
152
163
|
end
|
153
164
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# lib/bddgenx/steps_generator.rb
|
2
2
|
# encoding: utf-8
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# Suporta palavras-chave Gherkin em Português
|
7
|
-
# strings e números
|
4
|
+
# Classe responsável por gerar automaticamente os arquivos de definição
|
5
|
+
# de passos do Cucumber a partir de arquivos `.feature`.
|
6
|
+
# Suporta palavras-chave do Gherkin tanto em Português quanto em Inglês,
|
7
|
+
# além de identificar parâmetros dinamicamente (strings e números).
|
8
8
|
|
9
9
|
module Bddgenx
|
10
10
|
class StepsGenerator
|
@@ -14,66 +14,67 @@ module Bddgenx
|
|
14
14
|
# Palavras-chave Gherkin em Inglês
|
15
15
|
GHERKIN_KEYS_EN = %w[Given When Then And But].freeze
|
16
16
|
|
17
|
-
# Conjunto de todas as palavras-chave
|
17
|
+
# Conjunto de todas as palavras-chave reconhecidas
|
18
18
|
ALL_KEYS = GHERKIN_KEYS_PT + GHERKIN_KEYS_EN
|
19
19
|
|
20
20
|
##
|
21
|
-
# Transforma uma string em
|
22
|
-
#
|
23
|
-
# @param str [String] A string a ser transformada.
|
24
|
-
# @return [String] A string convertida para camelCase.
|
21
|
+
# Transforma uma string em camelCase (sem alterar acentuação).
|
25
22
|
#
|
23
|
+
# @param str [String] A string de entrada
|
24
|
+
# @return [String] A string convertida para estilo camelCase
|
26
25
|
def self.camelize(str)
|
27
26
|
partes = str.strip.split(/[^a-zA-Z0-9]+/)
|
28
27
|
partes.map.with_index { |palavra, i| i.zero? ? palavra.downcase : palavra.capitalize }.join
|
29
28
|
end
|
30
29
|
|
31
30
|
##
|
32
|
-
# Gera
|
33
|
-
#
|
34
|
-
# O método lê o arquivo, detecta o idioma, extrai os passos,
|
35
|
-
# parametriza as variáveis (números e strings), e escreve os métodos
|
36
|
-
# em um novo arquivo no diretório `steps/`.
|
37
|
-
#
|
38
|
-
# @param feature_path [String] Caminho para o arquivo .feature.
|
39
|
-
# @return [Boolean] Retorna true se os passos forem gerados com sucesso, false se não houver passos.
|
40
|
-
# @raise [ArgumentError] Se o caminho fornecido não for uma String.
|
31
|
+
# Gera um arquivo de definição de passos do Cucumber com base em um `.feature`.
|
32
|
+
# Detecta automaticamente o idioma e converte os passos em métodos com placeholders.
|
41
33
|
#
|
34
|
+
# @param feature_path [String] Caminho para o arquivo `.feature`
|
35
|
+
# @return [Boolean] Retorna true se os steps foram gerados, false se nenhum foi encontrado
|
36
|
+
# @raise [ArgumentError] Se o parâmetro não for uma String
|
42
37
|
def self.gerar_passos(feature_path)
|
43
|
-
raise ArgumentError,
|
38
|
+
raise ArgumentError, I18n.t('errors.invalid_path', path: feature_path.class) unless feature_path.is_a?(String)
|
44
39
|
|
45
40
|
linhas = File.readlines(feature_path)
|
46
41
|
|
47
|
-
# Detecta o idioma
|
42
|
+
# Detecta o idioma a partir da linha `# language:`
|
48
43
|
lang = if (m = linhas.find { |l| l =~ /^#\s*language:\s*(\w+)/i })
|
49
44
|
m[/^#\s*language:\s*(\w+)/i, 1].downcase
|
50
45
|
else
|
51
46
|
'pt'
|
52
47
|
end
|
53
48
|
|
49
|
+
# Define o locale do I18n conforme idioma detectado
|
50
|
+
I18n.locale = lang.to_sym rescue :pt
|
51
|
+
|
54
52
|
pt_para_en = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
|
55
53
|
en_para_pt = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h
|
56
54
|
|
57
|
-
# Seleciona apenas linhas que
|
55
|
+
# Seleciona apenas as linhas que representam passos
|
58
56
|
linhas_passos = linhas.map(&:strip).select do |linha|
|
59
57
|
ALL_KEYS.any? { |chave| linha.start_with?(chave + ' ') }
|
60
58
|
end
|
61
59
|
|
62
60
|
return false if linhas_passos.empty?
|
63
61
|
|
62
|
+
# Cria diretório `steps` no mesmo nível do `.feature`
|
64
63
|
dir_saida = File.join(File.dirname(feature_path), 'steps')
|
65
64
|
FileUtils.mkdir_p(dir_saida)
|
65
|
+
|
66
66
|
arquivo_saida = File.join(dir_saida, "#{File.basename(feature_path, '.feature')}_steps.rb")
|
67
67
|
|
68
|
+
# Cabeçalho do arquivo gerado
|
68
69
|
conteudo = +"# encoding: utf-8\n"
|
69
|
-
conteudo << "#
|
70
|
+
conteudo << "# #{I18n.t('steps.header', file: File.basename(feature_path))}\n\n"
|
70
71
|
|
71
72
|
passos_unicos = Set.new
|
72
73
|
|
73
74
|
linhas_passos.each do |linha|
|
74
75
|
palavra_original, restante = linha.split(' ', 2)
|
75
76
|
|
76
|
-
# Tradução
|
77
|
+
# Tradução da palavra-chave inicial
|
77
78
|
chave = case lang
|
78
79
|
when 'en' then pt_para_en[palavra_original] || palavra_original
|
79
80
|
else en_para_pt[palavra_original] || palavra_original
|
@@ -84,7 +85,7 @@ module Bddgenx
|
|
84
85
|
padrao = ''
|
85
86
|
tokens = []
|
86
87
|
|
87
|
-
# Analisa e parametriza
|
88
|
+
# Analisa e parametriza variáveis
|
88
89
|
until scanner.eos?
|
89
90
|
if scanner.check(/"<([^>]+)>"/)
|
90
91
|
scanner.scan(/"<([^>]+)>"/)
|
@@ -94,8 +95,8 @@ module Bddgenx
|
|
94
95
|
scanner.scan(/<([^>]+)>/)
|
95
96
|
tokens << scanner[1]
|
96
97
|
padrao << '{int}'
|
97
|
-
elsif scanner.check(/"([^"
|
98
|
-
scanner.scan(/"([^"
|
98
|
+
elsif scanner.check(/"([^"]+)"/)
|
99
|
+
scanner.scan(/"([^"]+)"/)
|
99
100
|
tokens << scanner[1]
|
100
101
|
padrao << '{string}'
|
101
102
|
elsif scanner.check(/\d+(?:\.\d+)?/)
|
@@ -109,11 +110,11 @@ module Bddgenx
|
|
109
110
|
|
110
111
|
padrao_seguro = padrao.gsub('"', '\\"')
|
111
112
|
|
112
|
-
#
|
113
|
+
# Evita duplicatas de métodos
|
113
114
|
next if passos_unicos.include?(padrao_seguro)
|
114
|
-
|
115
115
|
passos_unicos << padrao_seguro
|
116
116
|
|
117
|
+
# Monta assinatura do step
|
117
118
|
assinatura = "#{chave}(\"#{padrao_seguro}\")"
|
118
119
|
if tokens.any?
|
119
120
|
argumentos = tokens.each_index.map { |i| "arg#{i+1}" }.join(', ')
|
@@ -123,12 +124,13 @@ module Bddgenx
|
|
123
124
|
end
|
124
125
|
|
125
126
|
conteudo << "#{assinatura}\n"
|
126
|
-
conteudo << " pending '
|
127
|
+
conteudo << " pending '#{I18n.t('steps.pending', text: texto_bruto)}'\n"
|
127
128
|
conteudo << "end\n\n"
|
128
129
|
end
|
129
130
|
|
131
|
+
# Escreve o arquivo final
|
130
132
|
File.write(arquivo_saida, conteudo)
|
131
|
-
puts
|
133
|
+
puts I18n.t('steps.generated', path: arquivo_saida)
|
132
134
|
true
|
133
135
|
end
|
134
136
|
end
|
@@ -55,21 +55,31 @@ module Bddgenx
|
|
55
55
|
|
56
56
|
# Prompt base enviado ao ChatGPT, instruindo a saída no formato correto
|
57
57
|
prompt_base = <<~PROMPT
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
58
|
+
Gere cenários BDD no formato Gherkin, utilizando as palavras-chave estruturais no idioma "#{idioma}":
|
59
|
+
Feature: #{keywords[:feature]}
|
60
|
+
Scenario: #{keywords[:scenario]}
|
61
|
+
Scenario Outline: #{keywords[:scenario_outline]}
|
62
|
+
Examples: #{keywords[:examples]}
|
63
|
+
Given: #{keywords[:given]}
|
64
|
+
When: #{keywords[:when]}
|
65
|
+
Then: #{keywords[:then]}
|
66
|
+
And: #{keywords[:and]}
|
67
|
+
|
68
|
+
Instruções:
|
69
|
+
- Todos os textos dos passos devem ser escritos em **português**.
|
70
|
+
- Use as palavras-chave Gherkin no idioma especificado ("#{idioma}").
|
71
|
+
- Gere **vários cenários**, incluindo positivos e negativos.
|
72
|
+
- Use `Scenario Outline` e `Examples` sempre que houver valores variáveis.
|
73
|
+
- Mantenha os parâmetros como `<email>`, `<senha>` e outros entre colchetes angulares, exatamente como aparecem.
|
74
|
+
- Se a história fornecer contexto (ex: `[CONTEXT]` ou "Dado que..."), utilize-o como base para os cenários.
|
75
|
+
- Se não houver contexto explícito, **crie um coerente** baseado na história.
|
76
|
+
- A primeira linha do resultado deve conter obrigatoriamente `# language: #{idioma}`.
|
77
|
+
- Evite passos vagos ou genéricos. Use ações claras e específicas.
|
78
|
+
- Gere apenas o conteúdo da feature, sem explicações adicionais.
|
79
|
+
|
80
|
+
História fornecida:
|
81
|
+
#{historia}
|
82
|
+
PROMPT
|
73
83
|
|
74
84
|
uri = URI(CHATGPT_API_URL)
|
75
85
|
request_body = {
|
@@ -107,7 +117,10 @@ module Bddgenx
|
|
107
117
|
return fallback_com_gemini(historia, idioma)
|
108
118
|
end
|
109
119
|
else
|
110
|
-
|
120
|
+
if response.code.to_i == 429
|
121
|
+
warn "❌ Limite de uso da API OpenAI excedido."
|
122
|
+
warn "🔗 Verifique sua conta: https://platform.openai.com/account/usage"
|
123
|
+
end
|
111
124
|
return fallback_com_gemini(historia, idioma)
|
112
125
|
end
|
113
126
|
end
|
@@ -46,21 +46,33 @@ module Bddgenx
|
|
46
46
|
|
47
47
|
# Prompt base que instrui a IA a gerar cenários Gherkin no idioma indicado
|
48
48
|
prompt_base = <<~PROMPT
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
49
|
+
Gere cenários BDD no formato Gherkin, utilizando as palavras-chave estruturais no idioma "#{idioma}":
|
50
|
+
Feature: #{keywords[:feature]}
|
51
|
+
Scenario: #{keywords[:scenario]}
|
52
|
+
Scenario Outline: #{keywords[:scenario_outline]}
|
53
|
+
Examples: #{keywords[:examples]}
|
54
|
+
Given: #{keywords[:given]}
|
55
|
+
When: #{keywords[:when]}
|
56
|
+
Then: #{keywords[:then]}
|
57
|
+
And: #{keywords[:and]}
|
58
|
+
|
59
|
+
Instruções:
|
60
|
+
- Todos os textos dos passos devem ser escritos em **português**.
|
61
|
+
- Use as palavras-chave Gherkin no idioma especificado ("#{idioma}").
|
62
|
+
- Gere **vários cenários**, incluindo positivos e negativos.
|
63
|
+
- Use `Scenario Outline` e `Examples` sempre que houver valores variáveis.
|
64
|
+
- Mantenha os parâmetros como `<email>`, `<senha>` e outros entre colchetes angulares, exatamente como aparecem.
|
65
|
+
- Se a história fornecer contexto (ex: `[CONTEXT]` ou "Dado que..."), utilize-o como base para os cenários.
|
66
|
+
- Se não houver contexto explícito, **crie um coerente** baseado na história.
|
67
|
+
- A primeira linha do resultado deve conter obrigatoriamente `# language: #{idioma}`.
|
68
|
+
- Evite passos vagos ou genéricos. Use ações claras e específicas.
|
69
|
+
- Gere apenas o conteúdo da feature, sem explicações adicionais.
|
70
|
+
|
71
|
+
História fornecida:
|
72
|
+
#{historia}
|
73
|
+
PROMPT
|
74
|
+
|
75
|
+
|
64
76
|
|
65
77
|
unless api_key
|
66
78
|
warn "❌ API Key do Gemini não encontrada no .env (GEMINI_API_KEY)"
|
@@ -101,6 +113,11 @@ module Bddgenx
|
|
101
113
|
texto_limpo.sub!(/^# language: .*/, "# language: #{idioma}")
|
102
114
|
texto_limpo.prepend("# language: #{idioma}\n") unless texto_limpo.start_with?("# language:")
|
103
115
|
|
116
|
+
# Garante diretiva de idioma
|
117
|
+
feature_text = Bddgenx::GherkinCleaner.limpar(texto_ia)
|
118
|
+
feature_text.sub!(/^# language: .*/, "") # remove qualquer # language: existente
|
119
|
+
feature_text.prepend("# language: #{idioma}\n") # insere a correta
|
120
|
+
|
104
121
|
return texto_limpo
|
105
122
|
else
|
106
123
|
warn "❌ Resposta da IA sem conteúdo de texto"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
en:
|
2
|
+
messages:
|
3
|
+
start_ia: "🤖 Generating scenarios with AI (%{modo})..."
|
4
|
+
start_static: "⛏️ Generating static feature..."
|
5
|
+
ia_waiting: "⏳ Waiting for AI response..."
|
6
|
+
feature_fail: "❌ Failed to generate via AI: %{arquivo}"
|
7
|
+
no_files: "❌ No story file found to process."
|
8
|
+
not_found: "⚠️ File not found: %{arquivo}"
|
9
|
+
processing_done: "✅ Processing complete"
|
10
|
+
total_histories: "Total stories"
|
11
|
+
features_generated: "Generated features"
|
12
|
+
steps_generated: "Generated steps"
|
13
|
+
feature_created: "✅ .feature file generated: %{caminho}"
|
14
|
+
gherkin:
|
15
|
+
feature: "Feature"
|
16
|
+
context: "Background"
|
17
|
+
scenario: "Scenario"
|
18
|
+
scenario_outline: "Scenario Outline"
|
19
|
+
examples: "Examples"
|
20
|
+
rule: "Rule"
|
21
|
+
steps:
|
22
|
+
header: "Step definitions automatically generated for %{file}"
|
23
|
+
pending: "Implement step: %{text}"
|
24
|
+
generated: "✅ Steps generated: %{path}"
|
25
|
+
errors:
|
26
|
+
invalid_path: "Expected path as String, got %{path}"
|
27
|
+
messages2:
|
28
|
+
processing_done: "✅ Processing complete"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
pt:
|
2
|
+
messages:
|
3
|
+
start_ia: "🤖 Gerando cenários com IA (%{modo})..."
|
4
|
+
start_static: "⛏️ Gerando feature estática..."
|
5
|
+
ia_waiting: "⏳ Aguardando resposta da IA..."
|
6
|
+
feature_fail: "❌ Falha ao gerar com IA: %{arquivo}"
|
7
|
+
no_files: "❌ Nenhum arquivo de história para processar."
|
8
|
+
not_found: "⚠️ Arquivo não encontrado: %{arquivo}"
|
9
|
+
processing_done: "✅ Processamento concluído"
|
10
|
+
total_histories: "Total de histórias"
|
11
|
+
features_generated: "Features geradas"
|
12
|
+
steps_generated: "Steps gerados"
|
13
|
+
feature_created: "✅ Arquivo .feature gerado: %{caminho}"
|
14
|
+
gherkin:
|
15
|
+
feature: "Funcionalidade"
|
16
|
+
context: "Contexto"
|
17
|
+
scenario: "Cenário"
|
18
|
+
scenario_outline: "Esquema do Cenário"
|
19
|
+
examples: "Exemplos"
|
20
|
+
rule: "Regra"
|
21
|
+
steps:
|
22
|
+
header: "Definições de passos geradas automaticamente para %{file}"
|
23
|
+
pending: "Implementar passo: %{text}"
|
24
|
+
generated: "✅ Steps gerados: %{path}"
|
25
|
+
errors:
|
26
|
+
invalid_path: "Caminho esperado como String, recebeu %{path}"
|
27
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bddgenx
|
2
|
+
module Support
|
3
|
+
class Loader
|
4
|
+
SPINNERS = {
|
5
|
+
default: %w[| / - \\],
|
6
|
+
dots: %w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏]
|
7
|
+
}
|
8
|
+
|
9
|
+
def self.run(mensagem = "⏳ Processando...", tipo = :default)
|
10
|
+
spinner = SPINNERS[tipo] || SPINNERS[:default]
|
11
|
+
done = false
|
12
|
+
|
13
|
+
thread = Thread.new do
|
14
|
+
i = 0
|
15
|
+
print "\n"
|
16
|
+
until done
|
17
|
+
print "\r#{mensagem} #{spinner[i % spinner.length]}"
|
18
|
+
sleep(0.1)
|
19
|
+
i += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
result = yield
|
24
|
+
done = true
|
25
|
+
thread.join
|
26
|
+
print "\r#{mensagem} ✅\n"
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/bddgenx.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# Shebang para permitir execução direta do script no Linux/macOS, usando o interpretador Ruby do PATH
|
3
|
-
|
4
1
|
require_relative 'env'
|
5
2
|
# Carrega o arquivo 'env.rb' relativo a este script. Geralmente contém configurações e carregamento da gem Bddgenx.
|
6
3
|
|
data/lib/env.rb
CHANGED
@@ -1,51 +1,109 @@
|
|
1
1
|
# lib/bddgenx/env.rb
|
2
|
+
# encoding: utf-8
|
3
|
+
#
|
4
|
+
# Responsável por carregar todas as dependências da gem bddgenx.
|
5
|
+
# Inclui bibliotecas padrão, gems externas e arquivos internos
|
6
|
+
# essenciais para o funcionamento da geração BDD, com suporte a I18n,
|
7
|
+
# IA (ChatGPT, Gemini), geração de PDF, validações e estrutura de projeto.
|
2
8
|
|
3
|
-
#
|
9
|
+
# --------------------------------------
|
10
|
+
# 📦 Gems padrão da linguagem Ruby
|
11
|
+
# --------------------------------------
|
4
12
|
|
5
|
-
require 'json' #
|
6
|
-
require 'net/http' #
|
7
|
-
require 'uri' #
|
8
|
-
require 'fileutils' #
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require 'open3' # Para executar comandos externos com captura de saída
|
13
|
-
require 'faraday' # Cliente HTTP para Gemini API
|
14
|
-
require 'dotenv' # Para carregar variáveis de ambiente de arquivos .env
|
15
|
-
require 'unicode' # Para manipulação avançada de strings Unicode (ex: remoção de acentos)
|
16
|
-
require 'bigdecimal' # Para operações matemáticas precisas com decimais
|
13
|
+
require 'json' # Manipulação de dados JSON
|
14
|
+
require 'net/http' # Requisições HTTP nativas
|
15
|
+
require 'uri' # Manipulação de URLs
|
16
|
+
require 'fileutils' # Operações com arquivos e diretórios
|
17
|
+
require 'open3' # Execução de comandos externos com captura de saída
|
18
|
+
require 'bigdecimal' # Cálculos matemáticos de alta precisão
|
19
|
+
require 'i18n' # Internacionalização (traduções dinâmicas)
|
17
20
|
|
18
|
-
|
21
|
+
# --------------------------------------
|
22
|
+
# 📚 Gems externas
|
23
|
+
# --------------------------------------
|
19
24
|
|
20
|
-
#
|
25
|
+
require 'prawn' # Geração de documentos PDF
|
26
|
+
require 'prawn/table' # Suporte a tabelas no Prawn
|
27
|
+
require 'prawn-svg' # Suporte a SVG no PDF
|
28
|
+
require 'faraday' # Cliente HTTP para integração com APIs (ex: Gemini)
|
29
|
+
require 'dotenv' # Carrega variáveis de ambiente do arquivo `.env`
|
30
|
+
require 'unicode' # Manipulação e normalização de caracteres Unicode
|
31
|
+
|
32
|
+
# --------------------------------------
|
33
|
+
# 🌍 Configuração de idioma (I18n)
|
34
|
+
# --------------------------------------
|
35
|
+
|
36
|
+
Dotenv.load # Carrega variáveis como BDDGENX_LANG e APIs
|
37
|
+
|
38
|
+
# Define o caminho de arquivos de tradução YAML
|
39
|
+
locales_path = File.expand_path('bddgenx/locales/*.yml', __dir__)
|
40
|
+
I18n.load_path += Dir[locales_path]
|
41
|
+
|
42
|
+
# Define o idioma ativo somente se estiver presente e válido
|
43
|
+
idioma_env = ENV['BDDGENX_LANG']
|
44
|
+
if idioma_env && !idioma_env.strip.empty?
|
45
|
+
I18n.locale = idioma_env.strip.to_sym
|
46
|
+
else
|
47
|
+
I18n.locale = :pt
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# --------------------------------------
|
52
|
+
# 🔧 Bundler (para projetos com Gemfile)
|
53
|
+
# --------------------------------------
|
54
|
+
|
55
|
+
# Carrega as dependências listadas no Gemfile (se houver)
|
21
56
|
require 'bundler/setup' if File.exist?(File.expand_path('../../Gemfile', __FILE__))
|
22
57
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
require_relative
|
58
|
+
# --------------------------------------
|
59
|
+
# 🧩 Módulos utilitários da gem
|
60
|
+
# --------------------------------------
|
61
|
+
|
62
|
+
require_relative 'bddgenx/support/gherkin_cleaner' # Sanitização de Gherkin gerado
|
63
|
+
require_relative 'bddgenx/support/remover_steps_duplicados' # Remove passos duplicados
|
64
|
+
require_relative 'bddgenx/support/validator' # Valida estrutura de entrada
|
65
|
+
require_relative 'bddgenx/support/font_loader' # Carrega fontes do PDF
|
66
|
+
|
67
|
+
# --------------------------------------
|
68
|
+
# 🤖 Clientes de IA (ChatGPT, Gemini)
|
69
|
+
# --------------------------------------
|
70
|
+
|
71
|
+
require_relative 'bddgenx/ia/gemini_cliente' # Integração com Google Gemini
|
72
|
+
require_relative 'bddgenx/ia/chatgtp_cliente' # Integração com OpenAI (ChatGPT)
|
73
|
+
|
74
|
+
# --------------------------------------
|
75
|
+
# 🛠 Geradores (features, steps e execução)
|
76
|
+
# --------------------------------------
|
77
|
+
|
78
|
+
require_relative 'bddgenx/generators/generator' # Geração do conteúdo `.feature`
|
79
|
+
require_relative 'bddgenx/generators/steps_generator' # Geração de arquivos `*_steps.rb`
|
80
|
+
require_relative 'bddgenx/generators/runner' # Orquestrador da execução CLI
|
81
|
+
|
82
|
+
# --------------------------------------
|
83
|
+
# 📄 Parser e metadados
|
84
|
+
# --------------------------------------
|
85
|
+
|
86
|
+
require_relative 'parser' # Interpreta arquivos `.txt` de entrada
|
87
|
+
require_relative 'bddgenx/version' # Lê versão do arquivo `VERSION`
|
28
88
|
|
29
|
-
#
|
30
|
-
|
31
|
-
|
89
|
+
# --------------------------------------
|
90
|
+
# 📤 Relatórios e exportação
|
91
|
+
# --------------------------------------
|
32
92
|
|
33
|
-
#
|
34
|
-
require_relative
|
35
|
-
require_relative
|
36
|
-
require_relative 'bddgenx/generators/runner' # Classe responsável pela execução do processo de geração
|
93
|
+
require_relative 'bddgenx/reports/pdf_exporter' # Exporta features para PDF
|
94
|
+
require_relative 'bddgenx/reports/backup' # Gera backups de arquivos
|
95
|
+
require_relative 'bddgenx/reports/tracer' # Rastreabilidade de geração
|
37
96
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
97
|
+
# --------------------------------------
|
98
|
+
# ⚙️ Configuração da gem e loaders auxiliares
|
99
|
+
# --------------------------------------
|
41
100
|
|
42
|
-
#
|
43
|
-
require_relative
|
44
|
-
require_relative
|
45
|
-
require_relative 'bddgenx/reports/tracer' # Rastreabilidade dos processos
|
101
|
+
require_relative 'bddgenx/configuration' # Variáveis de configuração (modo, APIs, etc.)
|
102
|
+
require_relative 'bddgenx/setup' # Inicializa estrutura do projeto (input/, features/, etc.)
|
103
|
+
require_relative 'bddgenx/support/loader' # Exibe loaders/spinners no terminal
|
46
104
|
|
47
|
-
|
48
|
-
|
105
|
+
# --------------------------------------
|
106
|
+
# 🔁 Define modo de execução (ambiente de dev por padrão)
|
107
|
+
# --------------------------------------
|
49
108
|
|
50
|
-
# Define variável de ambiente global para indicar que o ambiente BDDGENX está em modo desenvolvimento
|
51
109
|
ENV['BDDGENX_ENV'] = 'development'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bddgenx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Nascimento
|
@@ -132,12 +132,15 @@ files:
|
|
132
132
|
- lib/bddgenx/generators/steps_generator.rb
|
133
133
|
- lib/bddgenx/ia/chatgtp_cliente.rb
|
134
134
|
- lib/bddgenx/ia/gemini_cliente.rb
|
135
|
+
- lib/bddgenx/locales/en.yml
|
136
|
+
- lib/bddgenx/locales/pt.yml
|
135
137
|
- lib/bddgenx/reports/backup.rb
|
136
138
|
- lib/bddgenx/reports/pdf_exporter.rb
|
137
139
|
- lib/bddgenx/reports/tracer.rb
|
138
140
|
- lib/bddgenx/setup.rb
|
139
141
|
- lib/bddgenx/support/font_loader.rb
|
140
142
|
- lib/bddgenx/support/gherkin_cleaner.rb
|
143
|
+
- lib/bddgenx/support/loader.rb
|
141
144
|
- lib/bddgenx/support/remover_steps_duplicados.rb
|
142
145
|
- lib/bddgenx/support/validator.rb
|
143
146
|
- lib/bddgenx/version.rb
|