bddgenx 2.4.6 → 2.4.9
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/VERSION +1 -1
- data/lib/bddgenx/configuration.rb +65 -7
- data/lib/bddgenx/generators/generator.rb +18 -47
- data/lib/bddgenx/generators/runner.rb +63 -38
- data/lib/bddgenx/generators/steps_generator.rb +6 -18
- data/lib/bddgenx/ia/chatgtp_cliente.rb +3 -21
- data/lib/bddgenx/ia/gemini_cliente.rb +3 -21
- data/lib/bddgenx/ia/microsoft_copilot_cliente.rb +133 -0
- data/lib/bddgenx/locales/en.yml +1 -0
- data/lib/bddgenx/locales/pt.yml +1 -0
- data/lib/bddgenx/reports/tracer.rb +101 -30
- data/lib/bddgenx/support/properties_loader.rb +108 -0
- data/lib/bddgenx/{support/gherkin_cleaner.rb → utils/gherkin_cleaner_helper.rb} +1 -1
- data/lib/bddgenx/utils/language_helper.rb +45 -0
- data/lib/bddgenx/utils/remover_steps_duplicados_helper.rb +79 -0
- data/lib/env.rb +65 -50
- metadata +7 -5
- data/Rakefile +0 -36
- data/lib/bddgenx/support/remover_steps_duplicados.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adf58e7c99b89027c56542f9b2dbff2cc71c336ca164eb6a2bc65308546beef3
|
4
|
+
data.tar.gz: 2093d4ac9a62eea83e87eb7faff89a43196f0a4585f885e515c967e52e0688b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10e4ffafcb2230a6a88cd3556ab995dfe936c36925c86027fee92d0e8f74f7e7b75c4bf6ea0415ec5a083dd5c63f9043750b350dcfa04176b3740c1123e67fa8
|
7
|
+
data.tar.gz: 3791efeb6c7a684e666bd73cfa03d21d2f8cc0825e6791655aa639f51901395c0595170661ff06b331e801ee2a158ec5193182ce4e6030712133c0c10c0b1176
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.4.
|
1
|
+
2.4.9
|
@@ -1,34 +1,92 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Este arquivo define a classe de configuração global da gem BDDGenX.
|
4
|
+
#
|
5
|
+
# A classe `Bddgenx::Configuration` permite configurar o modo de operação da ferramenta
|
6
|
+
# (ex: estático ou com IA) e define as variáveis de ambiente que armazenam as chaves de API
|
7
|
+
# para serviços externos como OpenAI (ChatGPT), Google Gemini e Microsoft Copilot.
|
8
|
+
|
2
9
|
module Bddgenx
|
10
|
+
# Classe de configuração principal da gem BDDGenX.
|
11
|
+
# Permite definir o modo de geração BDD e os nomes das variáveis de ambiente
|
12
|
+
# que armazenam as chaves de API para integração com serviços de IA.
|
3
13
|
class Configuration
|
4
|
-
#
|
14
|
+
# Modo de execução da gem.
|
15
|
+
# Pode ser:
|
16
|
+
# - :static → geração local
|
17
|
+
# - :chatgpt → uso da IA do ChatGPT (OpenAI)
|
18
|
+
# - :gemini → uso da IA Gemini (Google)
|
19
|
+
# - :copilot → uso do Microsoft Copilot
|
20
|
+
#
|
21
|
+
# @return [Symbol]
|
5
22
|
attr_accessor :mode
|
6
23
|
|
7
|
-
#
|
8
|
-
|
24
|
+
# Nome da variável de ambiente que contém a chave da API da OpenAI
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :openai_api_key_env
|
27
|
+
|
28
|
+
# Nome da variável de ambiente que contém a chave da API do Google Gemini
|
29
|
+
# @return [String]
|
30
|
+
attr_accessor :gemini_api_key_env
|
31
|
+
|
32
|
+
# Nome da variável de ambiente que contém a chave da API do Microsoft Copilot
|
33
|
+
# @return [String]
|
34
|
+
attr_accessor :microsoft_copilot_api_env
|
9
35
|
|
36
|
+
##
|
37
|
+
# Inicializa a configuração com valores padrão:
|
38
|
+
# - modo: :static
|
39
|
+
# - ENV keys: 'OPENAI_API_KEY', 'GEMINI_API_KEY', 'MICROSOFT_COPILOT_API_KEY'
|
10
40
|
def initialize
|
11
41
|
@mode = :static
|
12
42
|
@openai_api_key_env = 'OPENAI_API_KEY'
|
13
43
|
@gemini_api_key_env = 'GEMINI_API_KEY'
|
44
|
+
@microsoft_copilot_api_env = 'MICROSOFT_COPILOT_API_KEY'
|
14
45
|
end
|
15
46
|
|
16
|
-
|
47
|
+
##
|
48
|
+
# Retorna a chave da API do OpenAI, lida diretamente da ENV.
|
49
|
+
#
|
50
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
17
51
|
def openai_api_key
|
18
52
|
ENV[@openai_api_key_env]
|
19
53
|
end
|
20
54
|
|
55
|
+
##
|
56
|
+
# Retorna a chave da API do Gemini, lida diretamente da ENV.
|
57
|
+
#
|
58
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
21
59
|
def gemini_api_key
|
22
60
|
ENV[@gemini_api_key_env]
|
23
61
|
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Retorna a chave da API do Microsoft Copilot, lida diretamente da ENV.
|
65
|
+
#
|
66
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
67
|
+
def microsoft_copilot_api_key
|
68
|
+
ENV[@microsoft_copilot_api_env]
|
69
|
+
end
|
24
70
|
end
|
25
71
|
|
26
|
-
|
72
|
+
##
|
73
|
+
# Retorna uma instância singleton da configuração da gem.
|
74
|
+
#
|
75
|
+
# @return [Configuration]
|
27
76
|
def self.configuration
|
28
77
|
@configuration ||= Configuration.new
|
29
78
|
end
|
30
79
|
|
31
|
-
|
80
|
+
##
|
81
|
+
# Permite configurar a gem usando um bloco DSL.
|
82
|
+
#
|
83
|
+
# Exemplo:
|
84
|
+
# Bddgenx.configure do |config|
|
85
|
+
# config.mode = :gemini
|
86
|
+
# config.gemini_api_key_env = 'MY_GEMINI_KEY'
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# @yieldparam config [Configuration] instância de configuração atual
|
32
90
|
def self.configure
|
33
91
|
yield(configuration)
|
34
92
|
end
|
@@ -8,36 +8,6 @@
|
|
8
8
|
|
9
9
|
module Bddgenx
|
10
10
|
class Generator
|
11
|
-
# Palavras-chave do Gherkin em Português
|
12
|
-
GHERKIN_KEYS_PT = %w[Dado Quando Então E Mas].freeze
|
13
|
-
|
14
|
-
# Palavras-chave do Gherkin em Inglês
|
15
|
-
GHERKIN_KEYS_EN = %w[Given When Then And But].freeze
|
16
|
-
|
17
|
-
# Mapeamento PT → EN
|
18
|
-
GHERKIN_MAP_PT_EN = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
|
19
|
-
|
20
|
-
# Mapeamento EN → PT
|
21
|
-
GHERKIN_MAP_EN_PT = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h
|
22
|
-
|
23
|
-
# Todas as palavras-chave reconhecidas pelos parsers
|
24
|
-
ALL_KEYS = GHERKIN_KEYS_PT + GHERKIN_KEYS_EN
|
25
|
-
|
26
|
-
##
|
27
|
-
# Função para extrair o idioma do arquivo .txt
|
28
|
-
# @param txt_file [String] Caminho do arquivo .txt
|
29
|
-
# @return [String] O idioma extraído ou 'pt' como padrão
|
30
|
-
def self.obter_idioma_do_arquivo(txt_file)
|
31
|
-
idioma = nil
|
32
|
-
File.foreach(txt_file) do |line|
|
33
|
-
if line.strip.start_with?('# language:')
|
34
|
-
idioma = line.strip.split(':').last.strip.downcase
|
35
|
-
break
|
36
|
-
end
|
37
|
-
end
|
38
|
-
idioma || 'pt' # Retorna 'pt' como padrão caso o idioma não seja encontrado
|
39
|
-
end
|
40
|
-
|
41
11
|
##
|
42
12
|
# Gera o conteúdo de um arquivo `.feature` baseado na história fornecida.
|
43
13
|
# Pode operar em três modos:
|
@@ -48,9 +18,11 @@ module Bddgenx
|
|
48
18
|
# @param input [String, Hash] Caminho para um `.txt` ou estrutura de história já processada
|
49
19
|
# @param override_path [String, nil] Caminho alternativo de saída
|
50
20
|
# @return [Array<String, String>] Caminho e conteúdo do `.feature`
|
21
|
+
|
51
22
|
def self.gerar_feature(input, override_path = nil)
|
52
23
|
modo = ENV['BDD_MODE']&.to_sym || :static
|
53
24
|
|
25
|
+
# Verifique o idioma antes de continuar
|
54
26
|
if input.is_a?(String) && input.end_with?('.txt') && [:gemini, :chatgpt].include?(modo)
|
55
27
|
# Geração com IA
|
56
28
|
raw_txt = File.read(input)
|
@@ -62,38 +34,38 @@ module Bddgenx
|
|
62
34
|
grupos: []
|
63
35
|
}
|
64
36
|
|
37
|
+
# Detecta idioma do arquivo
|
38
|
+
idioma = Utils::detecta_idioma_de_texto(raw_txt)
|
39
|
+
historia[:idioma] = idioma
|
40
|
+
|
65
41
|
texto_gerado = if modo == :gemini
|
66
42
|
GeminiCliente.gerar_cenarios(raw_txt)
|
67
43
|
else
|
68
|
-
|
44
|
+
ChatGptCliente.gerar_cenarios(raw_txt)
|
69
45
|
end
|
70
46
|
|
71
47
|
historia[:grupos] << {
|
72
48
|
tipo: 'gerado',
|
73
49
|
tag: 'ia',
|
74
|
-
passos:
|
50
|
+
passos: Utils.limpar(texto_gerado).lines.map(&:strip).reject(&:empty?)
|
75
51
|
}
|
76
52
|
else
|
77
53
|
# Geração estática
|
78
54
|
historia = input.is_a?(String) ? Parser.ler_historia(input) : input
|
79
55
|
end
|
80
56
|
|
81
|
-
#
|
82
|
-
idioma = historia[:idioma] || obter_idioma_do_arquivo(input)
|
57
|
+
# Verifique o idioma que está sendo usado
|
58
|
+
idioma = historia[:idioma] || Utils::obter_idioma_do_arquivo(input)
|
59
|
+
|
60
|
+
# Verifique se o idioma está correto
|
61
|
+
puts "Idioma detectado: #{idioma}"
|
62
|
+
|
83
63
|
cont = 1
|
84
64
|
|
85
65
|
# Cria nome-base do arquivo .feature
|
86
|
-
nome_base = historia[:quero]
|
87
|
-
.gsub(/[^a-z0-9]/i, '_')
|
88
|
-
.downcase
|
89
|
-
.split('_')
|
90
|
-
.reject(&:empty?)
|
91
|
-
.first(5)
|
92
|
-
.join('_')
|
93
|
-
|
66
|
+
nome_base = historia[:quero].gsub(/[^a-z0-9]/i, '_').downcase.split('_').reject(&:empty?).first(5).join('_')
|
94
67
|
caminho = override_path || "features/#{nome_base}.feature"
|
95
68
|
|
96
|
-
# Palavras-chave localizadas
|
97
69
|
palavras = {
|
98
70
|
feature: idioma == 'en' ? 'Feature' : 'Funcionalidade',
|
99
71
|
contexto: idioma == 'en' ? 'Background' : 'Contexto',
|
@@ -103,7 +75,6 @@ module Bddgenx
|
|
103
75
|
regra: idioma == 'en' ? 'Rule' : 'Regra'
|
104
76
|
}
|
105
77
|
|
106
|
-
# Cabeçalho do arquivo .feature
|
107
78
|
conteudo = <<~GHK
|
108
79
|
# language: #{idioma}
|
109
80
|
#{palavras[:feature]}: #{historia[:quero].sub(/^Quero\s*/i,'')}
|
@@ -114,9 +85,9 @@ module Bddgenx
|
|
114
85
|
|
115
86
|
# Controle para não repetir passos
|
116
87
|
passos_unicos = Set.new
|
117
|
-
pt_map = GHERKIN_MAP_PT_EN
|
118
|
-
en_map = GHERKIN_MAP_EN_PT
|
119
|
-
detect = ALL_KEYS
|
88
|
+
pt_map = Utils::GHERKIN_MAP_PT_EN
|
89
|
+
en_map = Utils::GHERKIN_MAP_EN_PT
|
90
|
+
detect = Utils::ALL_KEYS
|
120
91
|
|
121
92
|
historia[:grupos].each do |grupo|
|
122
93
|
passos = grupo[:passos] || []
|
@@ -1,36 +1,49 @@
|
|
1
1
|
# lib/bddgenx/cli.rb
|
2
2
|
# encoding: utf-8
|
3
3
|
#
|
4
|
-
# Este arquivo define a classe Runner (CLI) da gem
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
4
|
+
# Este arquivo define a classe Runner (CLI) da gem BDDGenX.
|
5
|
+
#
|
6
|
+
# A Runner é responsável por orquestrar todo o fluxo de geração BDD:
|
7
|
+
# - Leitura e validação de histórias (arquivos `.txt`)
|
8
|
+
# - Geração de arquivos `.feature` e steps
|
9
|
+
# - Integração com IA (ChatGPT, Gemini, Copilot)
|
10
|
+
# - Exportação para PDF
|
11
|
+
# - Rastreabilidade via CSV
|
12
|
+
#
|
13
|
+
# Esta classe é o ponto de entrada da gem em execução via terminal (CLI).
|
14
|
+
# O comportamento é configurado com variáveis de ambiente como:
|
15
|
+
# - BDDGENX_MODE (static, chatgpt, gemini, copilot)
|
16
|
+
# - BDDGENX_LANG (pt, en)
|
8
17
|
|
9
18
|
require_relative '../../bddgenx'
|
10
19
|
|
11
20
|
module Bddgenx
|
12
|
-
# Classe principal de execução da gem.
|
13
|
-
#
|
14
|
-
# e
|
21
|
+
# Classe principal de execução da gem BDDGenX.
|
22
|
+
# Controla o fluxo de leitura de histórias, geração de artefatos BDD
|
23
|
+
# e exportação de relatórios. Suporta execução via terminal.
|
15
24
|
class Runner
|
16
25
|
|
17
26
|
##
|
18
|
-
# Retorna a lista de arquivos
|
19
|
-
#
|
20
|
-
#
|
27
|
+
# Retorna a lista de arquivos `.txt` a processar.
|
28
|
+
#
|
29
|
+
# - Se ARGV contiver argumentos, usa esses nomes como arquivos `.txt`
|
30
|
+
# - Caso contrário, entra em modo interativo para seleção manual
|
21
31
|
#
|
22
|
-
# @param input_dir [String] Caminho do diretório
|
23
|
-
# @return [Array<String>] Lista de arquivos `.txt`
|
32
|
+
# @param input_dir [String] Caminho do diretório com arquivos `.txt`
|
33
|
+
# @return [Array<String>] Lista de caminhos de arquivos `.txt`
|
24
34
|
def self.choose_files(input_dir)
|
25
35
|
ARGV.any? ? selecionar_arquivos_txt(input_dir) : choose_input(input_dir)
|
26
36
|
end
|
27
37
|
|
28
38
|
##
|
29
|
-
# Processa argumentos
|
30
|
-
#
|
39
|
+
# Processa os argumentos da linha de comando (ARGV) e gera caminhos
|
40
|
+
# completos para arquivos `.txt` no diretório informado.
|
31
41
|
#
|
32
|
-
#
|
33
|
-
#
|
42
|
+
# - Se a extensão `.txt` estiver ausente, ela é adicionada.
|
43
|
+
# - Arquivos inexistentes são ignorados com aviso.
|
44
|
+
#
|
45
|
+
# @param input_dir [String] Diretório base onde estão os arquivos `.txt`
|
46
|
+
# @return [Array<String>] Lista de arquivos válidos encontrados
|
34
47
|
def self.selecionar_arquivos_txt(input_dir)
|
35
48
|
ARGV.map do |arg|
|
36
49
|
nome = arg.end_with?('.txt') ? arg : "#{arg}.txt"
|
@@ -44,15 +57,18 @@ module Bddgenx
|
|
44
57
|
end
|
45
58
|
|
46
59
|
##
|
47
|
-
#
|
48
|
-
#
|
60
|
+
# Modo interativo para o usuário escolher o arquivo `.txt` a ser processado.
|
61
|
+
#
|
62
|
+
# Exibe uma lista numerada com os arquivos disponíveis no diretório.
|
63
|
+
# O usuário pode selecionar um específico ou pressionar ENTER para todos.
|
49
64
|
#
|
50
|
-
# @param input_dir [String]
|
51
|
-
# @return [Array<String>]
|
65
|
+
# @param input_dir [String] Caminho do diretório com arquivos `.txt`
|
66
|
+
# @return [Array<String>] Arquivo selecionado ou todos disponíveis
|
52
67
|
def self.choose_input(input_dir)
|
53
68
|
files = Dir.glob(File.join(input_dir, '*.txt'))
|
54
69
|
if files.empty?
|
55
|
-
warn "❌ Não há arquivos .txt no diretório #{input_dir}"
|
70
|
+
warn "❌ Não há arquivos .txt no diretório #{input_dir}"
|
71
|
+
exit 1
|
56
72
|
end
|
57
73
|
|
58
74
|
puts "Selecione o arquivo de história para processar:"
|
@@ -63,20 +79,24 @@ module Bddgenx
|
|
63
79
|
return files if choice.empty?
|
64
80
|
idx = choice.to_i - 1
|
65
81
|
unless idx.between?(0, files.size - 1)
|
66
|
-
warn "❌ Escolha inválida."
|
82
|
+
warn "❌ Escolha inválida."
|
83
|
+
exit 1
|
67
84
|
end
|
68
85
|
[files[idx]]
|
69
86
|
end
|
70
87
|
|
71
88
|
##
|
72
|
-
# Executa o fluxo
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# -
|
76
|
-
# -
|
77
|
-
# -
|
89
|
+
# Executa o fluxo principal de geração dos artefatos BDD.
|
90
|
+
#
|
91
|
+
# Etapas executadas:
|
92
|
+
# - Detecta o modo de execução via ENV['BDDGENX_MODE'] (static/chatgpt/gemini/copilot)
|
93
|
+
# - Carrega e valida histórias de usuário
|
94
|
+
# - Gera arquivos `.feature` e seus respectivos steps
|
95
|
+
# - Executa geração via IA (quando aplicável)
|
96
|
+
# - Exporta arquivos em PDF
|
97
|
+
# - Gera rastreabilidade via CSV
|
78
98
|
#
|
79
|
-
#
|
99
|
+
# Exibe no final um resumo das operações executadas.
|
80
100
|
#
|
81
101
|
# @return [void]
|
82
102
|
def self.execute
|
@@ -90,7 +110,7 @@ module Bddgenx
|
|
90
110
|
exit 1
|
91
111
|
end
|
92
112
|
|
93
|
-
# Contadores
|
113
|
+
# Contadores
|
94
114
|
total = features = steps = ignored = 0
|
95
115
|
skipped_steps = []
|
96
116
|
generated_pdfs = []
|
@@ -101,29 +121,30 @@ module Bddgenx
|
|
101
121
|
puts "\n🔍 #{I18n.t('messages.processing')}: #{arquivo}"
|
102
122
|
|
103
123
|
historia = Parser.ler_historia(arquivo)
|
124
|
+
idioma = Utils.obter_idioma_do_arquivo(arquivo) || historia[:idioma]
|
125
|
+
historia[:idioma] = idioma
|
126
|
+
|
104
127
|
unless Validator.validar(historia)
|
105
128
|
ignored += 1
|
106
129
|
puts "❌ #{I18n.t('messages.invalid_story')}: #{arquivo}"
|
107
130
|
next
|
108
131
|
end
|
109
132
|
|
110
|
-
#
|
111
|
-
if %w[gemini chatgpt].include?(modo)
|
133
|
+
# IA: geração de cenários com Gemini, ChatGPT ou Copilot
|
134
|
+
if %w[gemini chatgpt copilot].include?(modo)
|
112
135
|
puts I18n.t('messages.start_ia', modo: modo.capitalize)
|
113
|
-
idioma = IA::GeminiCliente.detecta_idioma_arquivo(arquivo)
|
114
136
|
|
115
137
|
feature_text = Support::Loader.run(I18n.t('messages.ia_waiting'), :default) do
|
116
138
|
case modo
|
117
|
-
when 'gemini'
|
118
|
-
|
119
|
-
when '
|
120
|
-
IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
139
|
+
when 'gemini' then IA::GeminiCliente.gerar_cenarios(historia, idioma)
|
140
|
+
when 'chatgpt' then IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
141
|
+
when 'copilot' then IA::MicrosoftCopilotCliente.gerar_cenarios(historia, idioma)
|
121
142
|
end
|
122
143
|
end
|
123
144
|
|
124
145
|
if feature_text
|
125
146
|
feature_path = Generator.path_para_feature(arquivo)
|
126
|
-
feature_content =
|
147
|
+
feature_content = Utils.limpar(feature_text)
|
127
148
|
else
|
128
149
|
ignored += 1
|
129
150
|
puts I18n.t('messages.feature_fail', arquivo: arquivo)
|
@@ -137,7 +158,9 @@ module Bddgenx
|
|
137
158
|
end
|
138
159
|
end
|
139
160
|
|
161
|
+
# Salva versão antiga se existir
|
140
162
|
Backup.salvar_versao_antiga(feature_path)
|
163
|
+
|
141
164
|
features += 1 if Generator.salvar_feature(feature_path, feature_content)
|
142
165
|
|
143
166
|
if StepsGenerator.gerar_passos(feature_path)
|
@@ -148,6 +171,8 @@ module Bddgenx
|
|
148
171
|
|
149
172
|
FileUtils.mkdir_p('reports')
|
150
173
|
result = PDFExporter.exportar_todos(only_new: true)
|
174
|
+
Tracer.adicionar_entrada(historia, feature_path)
|
175
|
+
|
151
176
|
generated_pdfs.concat(result[:generated])
|
152
177
|
skipped_pdfs.concat(result[:skipped])
|
153
178
|
end
|
@@ -8,15 +8,6 @@
|
|
8
8
|
|
9
9
|
module Bddgenx
|
10
10
|
class StepsGenerator
|
11
|
-
# Palavras-chave Gherkin em Português
|
12
|
-
GHERKIN_KEYS_PT = %w[Dado Quando Então E Mas].freeze
|
13
|
-
|
14
|
-
# Palavras-chave Gherkin em Inglês
|
15
|
-
GHERKIN_KEYS_EN = %w[Given When Then And But].freeze
|
16
|
-
|
17
|
-
# Conjunto de todas as palavras-chave reconhecidas
|
18
|
-
ALL_KEYS = GHERKIN_KEYS_PT + GHERKIN_KEYS_EN
|
19
|
-
|
20
11
|
##
|
21
12
|
# Transforma uma string em camelCase (sem alterar acentuação).
|
22
13
|
#
|
@@ -38,23 +29,20 @@ module Bddgenx
|
|
38
29
|
raise ArgumentError, I18n.t('errors.invalid_path', path: feature_path.class) unless feature_path.is_a?(String)
|
39
30
|
|
40
31
|
linhas = File.readlines(feature_path)
|
32
|
+
lang = Utils::detecta_idioma_de_texto(linhas.join)
|
33
|
+
|
34
|
+
I18n.locale = lang.to_sym rescue :pt
|
41
35
|
|
42
|
-
# Detecta o idioma a partir da linha `# language:`
|
43
|
-
lang = if (m = linhas.find { |l| l =~ /^#\s*language:\s*(\w+)/i })
|
44
|
-
m[/^#\s*language:\s*(\w+)/i, 1].downcase
|
45
|
-
else
|
46
|
-
'pt'
|
47
|
-
end
|
48
36
|
|
49
37
|
# Define o locale do I18n conforme idioma detectado
|
50
38
|
I18n.locale = lang.to_sym rescue :pt
|
51
39
|
|
52
|
-
pt_para_en = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
|
53
|
-
en_para_pt = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h
|
40
|
+
pt_para_en = Utils::GHERKIN_KEYS_PT.zip(Utils::GHERKIN_KEYS_EN).to_h
|
41
|
+
en_para_pt = Utils::GHERKIN_KEYS_EN.zip(Utils::GHERKIN_KEYS_PT).to_h
|
54
42
|
|
55
43
|
# Seleciona apenas as linhas que representam passos
|
56
44
|
linhas_passos = linhas.map(&:strip).select do |linha|
|
57
|
-
ALL_KEYS.any? { |chave| linha.start_with?(chave + ' ') }
|
45
|
+
Utils::ALL_KEYS.any? { |chave| linha.start_with?(chave + ' ') }
|
58
46
|
end
|
59
47
|
|
60
48
|
return false if linhas_passos.empty?
|
@@ -28,7 +28,7 @@ module Bddgenx
|
|
28
28
|
return fallback_com_gemini(historia, idioma)
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
|
32
32
|
keywords_pt = {
|
33
33
|
feature: "Funcionalidade",
|
34
34
|
scenario: "Cenário",
|
@@ -104,8 +104,8 @@ module Bddgenx
|
|
104
104
|
texto_ia = json.dig("choices", 0, "message", "content")
|
105
105
|
|
106
106
|
if texto_ia
|
107
|
-
texto_limpo =
|
108
|
-
Utils::
|
107
|
+
texto_limpo = Utils.limpar(texto_ia)
|
108
|
+
Utils::remover_steps_duplicados(texto_ia, idioma)
|
109
109
|
|
110
110
|
# Ajusta a linha de idioma no arquivo gerado
|
111
111
|
texto_limpo.sub!(/^# language: .*/, "# language: #{idioma}")
|
@@ -137,24 +137,6 @@ module Bddgenx
|
|
137
137
|
warn I18n.t('messages.fallback_gemini')
|
138
138
|
GeminiCliente.gerar_cenarios(historia, idioma)
|
139
139
|
end
|
140
|
-
|
141
|
-
##
|
142
|
-
# Detecta o idioma de um arquivo de feature pela linha "# language:".
|
143
|
-
#
|
144
|
-
# @param caminho_arquivo [String] Caminho para o arquivo de feature.
|
145
|
-
# @return [String] Código do idioma detectado ('pt' por padrão).
|
146
|
-
#
|
147
|
-
def self.detecta_idioma_arquivo(caminho_arquivo)
|
148
|
-
return 'pt' unless File.exist?(caminho_arquivo)
|
149
|
-
|
150
|
-
File.foreach(caminho_arquivo) do |linha|
|
151
|
-
if linha =~ /^#\s*language:\s*(\w{2})/i
|
152
|
-
return $1.downcase
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
'pt'
|
157
|
-
end
|
158
140
|
end
|
159
141
|
end
|
160
142
|
end
|
@@ -106,15 +106,15 @@ module Bddgenx
|
|
106
106
|
texto_ia = json["candidates"].first.dig("content", "parts", 0, "text")
|
107
107
|
if texto_ia
|
108
108
|
# Limpeza e sanitização do texto para manter padrão Gherkin
|
109
|
-
texto_limpo =
|
110
|
-
Utils
|
109
|
+
texto_limpo = Utils.limpar(texto_ia)
|
110
|
+
Utils.remover_steps_duplicados(texto_ia, idioma)
|
111
111
|
|
112
112
|
# Ajuste da diretiva de idioma na saída gerada
|
113
113
|
texto_limpo.sub!(/^# language: .*/, "# language: #{idioma}")
|
114
114
|
texto_limpo.prepend("# language: #{idioma}\n") unless texto_limpo.start_with?("# language:")
|
115
115
|
|
116
116
|
# Garante diretiva de idioma
|
117
|
-
feature_text =
|
117
|
+
feature_text = Utils.limpar(texto_ia)
|
118
118
|
feature_text.sub!(/^# language: .*/, "") # remove qualquer # language: existente
|
119
119
|
feature_text.prepend("# language: #{idioma}\n") # insere a correta
|
120
120
|
|
@@ -129,24 +129,6 @@ module Bddgenx
|
|
129
129
|
return nil
|
130
130
|
end
|
131
131
|
end
|
132
|
-
|
133
|
-
##
|
134
|
-
# Detecta o idioma do arquivo de feature pela linha "# language:".
|
135
|
-
#
|
136
|
-
# @param caminho_arquivo [String] Caminho do arquivo para detecção do idioma.
|
137
|
-
# @return [String] Código do idioma detectado (ex: 'pt'), padrão 'pt'.
|
138
|
-
#
|
139
|
-
def self.detecta_idioma_arquivo(caminho_arquivo)
|
140
|
-
return 'pt' unless File.exist?(caminho_arquivo)
|
141
|
-
|
142
|
-
File.foreach(caminho_arquivo) do |linha|
|
143
|
-
if linha =~ /^#\s*language:\s*(\w{2})/i
|
144
|
-
return $1.downcase
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
'pt' # idioma padrão caso não encontre
|
149
|
-
end
|
150
132
|
end
|
151
133
|
end
|
152
134
|
end
|