bddgenx 2.3.3 → 2.4.3
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/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/bddgenx/generators/generator.rb +31 -27
- data/lib/bddgenx/generators/runner.rb +55 -49
- data/lib/bddgenx/generators/steps_generator.rb +32 -30
- data/lib/bddgenx/locales/en.yml +28 -0
- data/lib/bddgenx/locales/pt.yml +27 -0
- data/lib/bddgenx.rb +0 -3
- data/lib/env.rb +95 -38
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27017e2957f3a9710eb63407c7f6d15e35e756a45890d3dc43b281b357d7d509
|
4
|
+
data.tar.gz: e50c8a8b925a0f941229ea8c79215e7671584b288cc29aab3dda78ad05db9e13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73d8b6d056d42b958814229d6d03384338199e6fbbb36da8110923ea955410b0b4de9a36d8f8df71343974178bebfc948a488303fe1e60d9a94bb410968f9e84
|
7
|
+
data.tar.gz: a8da8ca236ae14891de29ba9f22807581348258fb711922cc614dec74453ccb6fa6073b04cf6f74cdff24d304ff958e425d71762daaee59dc15df8bb93b3e163
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.3
|
@@ -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,25 +98,28 @@ 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 %w[gemini chatgpt].include?(modo)
|
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
114
|
|
108
|
-
feature_text =
|
109
|
-
|
115
|
+
feature_text = Support::Loader.run(I18n.t('messages.ia_waiting'), :default) do
|
116
|
+
case modo
|
117
|
+
when 'gemini'
|
110
118
|
IA::GeminiCliente.gerar_cenarios(historia, idioma)
|
111
|
-
|
119
|
+
when 'chatgpt'
|
112
120
|
IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
121
|
+
when 'deepseek'
|
122
|
+
IA::DeepseekCliente.gerar_cenarios(historia, idioma)
|
113
123
|
end
|
114
124
|
end
|
115
125
|
|
@@ -118,11 +128,13 @@ module Bddgenx
|
|
118
128
|
feature_content = Bddgenx::GherkinCleaner.limpar(feature_text)
|
119
129
|
else
|
120
130
|
ignored += 1
|
121
|
-
puts
|
131
|
+
puts I18n.t('messages.feature_fail', arquivo: arquivo)
|
122
132
|
next
|
123
133
|
end
|
124
134
|
else
|
125
|
-
|
135
|
+
# Geração local (modo static)
|
136
|
+
feature_path, feature_content = Support::Loader.run(I18n.t('messages.start_static'), :dots) do
|
137
|
+
sleep(2)
|
126
138
|
Generator.gerar_feature(historia)
|
127
139
|
end
|
128
140
|
end
|
@@ -130,29 +142,23 @@ module Bddgenx
|
|
130
142
|
Backup.salvar_versao_antiga(feature_path)
|
131
143
|
features += 1 if Generator.salvar_feature(feature_path, feature_content)
|
132
144
|
|
133
|
-
# Geração de steps
|
134
145
|
if StepsGenerator.gerar_passos(feature_path)
|
135
146
|
steps += 1
|
136
147
|
else
|
137
148
|
skipped_steps << feature_path
|
138
149
|
end
|
139
150
|
|
140
|
-
# Exportação de PDF (apenas novos)
|
141
151
|
FileUtils.mkdir_p('reports')
|
142
152
|
result = PDFExporter.exportar_todos(only_new: true)
|
143
153
|
generated_pdfs.concat(result[:generated])
|
144
154
|
skipped_pdfs.concat(result[:skipped])
|
145
155
|
end
|
146
156
|
|
147
|
-
#
|
148
|
-
puts "\n
|
149
|
-
puts "-
|
150
|
-
puts "-
|
151
|
-
puts "-
|
152
|
-
puts "- Steps ignorados: #{skipped_steps.size}"
|
153
|
-
puts "- PDFs gerados: #{generated_pdfs.size}"
|
154
|
-
puts "- PDFs já existentes: #{skipped_pdfs.size}"
|
155
|
-
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}"
|
156
162
|
end
|
157
163
|
end
|
158
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
|
@@ -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
|
+
|
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,52 +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
|
-
|
49
|
-
|
105
|
+
# --------------------------------------
|
106
|
+
# 🔁 Define modo de execução (ambiente de dev por padrão)
|
107
|
+
# --------------------------------------
|
50
108
|
|
51
|
-
# Define variável de ambiente global para indicar que o ambiente BDDGENX está em modo desenvolvimento
|
52
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Nascimento
|
@@ -132,6 +132,8 @@ 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
|