bddgenx 0.1.43 → 0.1.44

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.
@@ -1,18 +1,34 @@
1
1
  # lib/bddgenx/pdf_exporter.rb
2
+ # encoding: utf-8
3
+ #
4
+ # Este arquivo define a classe PDFExporter, responsável por gerar documentos
5
+ # PDF a partir de arquivos .feature, formatados no estilo pretty Cucumber em
6
+ # preto e branco.
7
+ # Utiliza a gem Prawn para renderização de texto e tabelas.
8
+
2
9
  require 'prawn'
3
10
  require 'prawn/table'
4
11
  require 'fileutils'
5
12
  require_relative 'fontLoader'
6
13
 
7
- # Suprime aviso de internacionalização para fontes AFM built-in
14
+ # Suprime aviso de internacionalização para fontes AFM internas
8
15
  Prawn::Fonts::AFM.hide_m17n_warning = true
9
16
 
10
17
  module Bddgenx
18
+ # Gera documentos PDF baseados em arquivos .feature.
11
19
  class PDFExporter
12
- # Gera PDFs a partir de arquivos .feature no estilo pretty Cucumber em P/B
13
- # Params:
14
- # +caminho_feature+:: (String) caminho para um arquivo .feature específico. Se nil, gera para todos em features/*.feature
15
- # +only_new+:: (Boolean) se true, não sobrescreve PDFs já existentes
20
+ # Gera PDFs de features, criando um para cada arquivo .feature ou apenas para
21
+ # o especificado em caminho_feature.
22
+ #
23
+ # @param caminho_feature [String, nil]
24
+ # Caminho para um arquivo .feature específico. Se nil ou vazio, gera para todos
25
+ # os arquivos em features/*.feature.
26
+ # @param only_new [Boolean]
27
+ # Se true, não sobrescreve arquivos PDF já existentes.
28
+ # @return [Hash<Symbol, Array<String>>]
29
+ # Retorna um hash com duas chaves:
30
+ # - :generated => array de caminhos dos PDFs gerados
31
+ # - :skipped => array de caminhos dos PDFs que foram pulados
16
32
  def self.exportar_todos(caminho_feature: nil, only_new: false)
17
33
  FileUtils.mkdir_p('reports/pdf')
18
34
  features_list = if caminho_feature && !caminho_feature.empty?
@@ -21,14 +37,17 @@ module Bddgenx
21
37
  Dir.glob('features/*.feature')
22
38
  end
23
39
 
24
- generated, skipped = [], []
40
+ generated = []
41
+ skipped = []
42
+
25
43
  features_list.each do |feature|
26
44
  unless File.file?(feature)
27
45
  warn "⚠️ Feature não encontrada: #{feature}"
28
46
  next
29
47
  end
30
- nome = File.basename(feature, '.feature')
31
- destino = "reports/pdf/#{camel_case(nome)}.pdf"
48
+
49
+ nome = File.basename(feature, '.feature')
50
+ destino = "reports/pdf/#{camel_case(nome)}.pdf"
32
51
 
33
52
  if only_new && File.exist?(destino)
34
53
  skipped << destino
@@ -42,14 +61,22 @@ module Bddgenx
42
61
  { generated: generated, skipped: skipped }
43
62
  end
44
63
 
45
- # Converte string para camelCase, removendo caracteres especiais
64
+ # Converte uma string para formato camelCase, removendo caracteres especiais.
65
+ #
66
+ # @param str [String] A string de entrada a ser transformada.
67
+ # @return [String] String no formato camelCase.
46
68
  def self.camel_case(str)
47
69
  clean = str.gsub(/[^0-9A-Za-z ]/, '')
48
70
  parts = clean.split(/ |_/)
49
71
  ([parts.first&.downcase] + (parts[1..] || []).map(&:capitalize)).join
50
72
  end
51
73
 
52
- # Gera o PDF formatado a partir de um único arquivo .feature, sem executar testes
74
+ # Gera um documento PDF a partir de um arquivo .feature, aplicando estilos
75
+ # de cabeçalhos, cenários, passos e tabelas conforme padrões Cucumber.
76
+ #
77
+ # @param origem [String] Caminho para o arquivo .feature de origem.
78
+ # @param destino [String] Caminho onde o PDF será salvo.
79
+ # @return [void]
53
80
  def self.exportar_arquivo(origem, destino)
54
81
  FileUtils.mkdir_p(File.dirname(destino))
55
82
  conteudo = File.read(origem, encoding: 'utf-8')
@@ -59,17 +86,21 @@ module Bddgenx
59
86
  pdf.font_size 9
60
87
 
61
88
  table_buffer = []
89
+
62
90
  conteudo.each_line do |linha|
63
91
  text = linha.chomp
64
92
 
65
- # Agrupa linhas de tabela e renderiza quando termina
93
+ # Agrega linhas de tabela até o bloco terminar
66
94
  if text =~ /^\s*\|.*\|/i
67
- table_buffer << text.gsub(/^\s*\||\|\s*$/, '').split('|').map(&:strip)
95
+ # Remove bordas laterais e separa colunas
96
+ row = text.gsub(/^\s*\||\|\s*$/, '').split('|').map(&:strip)
97
+ table_buffer << row
68
98
  next
69
99
  elsif table_buffer.any?
100
+ # Renderiza tabela acumulada
70
101
  pdf.table(table_buffer, header: true, width: pdf.bounds.width) do
71
- self.header = true
72
- self.row_colors = ['EEEEEE', 'FFFFFF']
102
+ self.header = true
103
+ self.row_colors = ['EEEEEE', 'FFFFFF']
73
104
  self.cell_style = { size: 8, font: 'Courier' }
74
105
  end
75
106
  pdf.move_down 4
@@ -95,6 +126,7 @@ module Bddgenx
95
126
  pdf.text text, size: 8, style: :italic
96
127
  pdf.move_down 4
97
128
  when /^(?:\s*)(Given|When|Then|And|But|Dado|Quando|Então|E|Mas)\b/i
129
+ # Passo Gherkin: destaca palavra-chave e texto
98
130
  keyword, rest = text.strip.split(' ', 2)
99
131
  pdf.indent(20) do
100
132
  pdf.formatted_text [
@@ -110,20 +142,21 @@ module Bddgenx
110
142
  end
111
143
  end
112
144
 
113
- # Renderiza qualquer tabela remanescente
145
+ # Renderiza tabela remanescente, se houver
114
146
  if table_buffer.any?
115
147
  pdf.table(table_buffer, header: true, width: pdf.bounds.width) do
116
- self.header = true
117
- self.row_colors = ['EEEEEE', 'FFFFFF']
148
+ self.header = true
149
+ self.row_colors = ['EEEEEE', 'FFFFFF']
118
150
  self.cell_style = { size: 8, font: 'Courier' }
119
151
  end
120
152
  pdf.move_down 4
121
153
  end
122
154
 
155
+ # Numeração de páginas
123
156
  pdf.number_pages 'Página <page> de <total>', align: :right, size: 8
124
157
  end
125
158
  rescue => e
126
159
  warn "❌ Erro ao gerar PDF de #{origem}: #{e.message}"
127
160
  end
128
161
  end
129
- end
162
+ end
@@ -1,20 +1,40 @@
1
+ # lib/bddgenx/tracer.rb
2
+ # encoding: utf-8
3
+ #
4
+ # Este arquivo define a classe Tracer, responsável por gerar e manter
5
+ # informações de rastreabilidade de cenários e passos em um arquivo CSV.
6
+ # Útil para auditoria e análise de cobertura de cenários gerados.
7
+
1
8
  require 'csv'
2
9
  require 'fileutils'
3
10
 
4
11
  module Bddgenx
12
+ # Classe para adicionar registros de rastreabilidade a um relatório CSV.
5
13
  class Tracer
14
+ # Adiciona entradas de rastreabilidade para cada passo de cada grupo
15
+ # da história em um arquivo CSV localizado em 'reports/output/rastreabilidade.csv'.
16
+ #
17
+ # @param historia [Hash]
18
+ # Objeto de história contendo :quero (título da funcionalidade) e :grupos,
19
+ # onde cada grupo possui :tipo, :tag, e :passos (Array<String>)
20
+ # @param nome_arquivo_feature [String]
21
+ # Nome do arquivo .feature de onde os passos foram gerados
22
+ # @return [void]
6
23
  def self.adicionar_entrada(historia, nome_arquivo_feature)
24
+ # Garante existência do diretório de saída
7
25
  FileUtils.mkdir_p('reports/output')
8
26
  arquivo_csv = 'reports/output/rastreabilidade.csv'
9
27
 
28
+ # Cabeçalho padrão do CSV: identifica colunas
10
29
  cabecalho = ['Funcionalidade', 'Tipo', 'Tag', 'Cenário', 'Passo', 'Origem']
11
30
 
12
31
  linhas = []
13
32
 
33
+ # Itera sobre grupos de passos para compor linhas de rastreabilidade
14
34
  historia[:grupos].each_with_index do |grupo, idx|
15
- tipo = grupo[:tipo]
16
- tag = grupo[:tag]
17
- passos = grupo[:passos]
35
+ tipo = grupo[:tipo]
36
+ tag = grupo[:tag]
37
+ passos = grupo[:passos] || []
18
38
 
19
39
  nome_funcionalidade = historia[:quero].gsub(/^Quero\s*/, '').strip
20
40
  nome_cenario = "Cenário #{idx + 1}"
@@ -31,10 +51,18 @@ module Bddgenx
31
51
  end
32
52
  end
33
53
 
54
+ # Escreve ou anexa as linhas geradas ao CSV
34
55
  escrever_csv(arquivo_csv, cabecalho, linhas)
35
56
  end
36
57
 
58
+ # Escreve ou anexa registros em um arquivo CSV, criando cabeçalho se necessário.
59
+ #
60
+ # @param caminho [String] Caminho completo para o arquivo CSV de rastreabilidade
61
+ # @param cabecalho [Array<String>] Array de títulos das colunas a serem escritos
62
+ # @param linhas [Array<Array<String>>] Dados a serem gravados no CSV (cada sub-array é uma linha)
63
+ # @return [void]
37
64
  def self.escrever_csv(caminho, cabecalho, linhas)
65
+ # Verifica se é um novo arquivo para incluir o cabeçalho
38
66
  novo_arquivo = !File.exist?(caminho)
39
67
 
40
68
  CSV.open(caminho, 'a+', col_sep: ';', force_quotes: true) do |csv|
@@ -1,32 +1,58 @@
1
+ # lib/bddgenx/validator.rb
2
+ # encoding: utf-8
3
+ #
4
+ # Este arquivo define a classe Validator, responsável por validar a estrutura
5
+ # de uma história antes de gerar cenários ou arquivos .feature.
6
+ # Verifica presença de cabeçalho obrigatório e integridade dos grupos de passos.
7
+
1
8
  module Bddgenx
9
+ # Valida objetos de história garantindo que possuam campos e blocos corretos.
2
10
  class Validator
11
+ # Valida o hash de história fornecido.
12
+ #
13
+ # Verifica:
14
+ # - Presença das chaves :como, :quero, :para no cabeçalho
15
+ # - Presença de pelo menos um grupo em :grupos
16
+ # - Cada grupo deve ter ao menos passos ou exemplos
17
+ # - Grupos do tipo "EXAMPLES" devem conter uma tabela de exemplos válida
18
+ #
19
+ # @param historia [Hash] Objeto de história com chaves :como, :quero, :para e :grupos
20
+ # @return [Boolean] Retorna true se a história for válida; caso contrário, false
3
21
  def self.validar(historia)
4
22
  erros = []
5
23
 
24
+ # Verificação do cabeçalho obrigatório
6
25
  unless historia[:como] && historia[:quero] && historia[:para]
7
26
  erros << "❌ Cabeçalho incompleto (Como, Quero, Para obrigatórios)"
8
27
  end
9
28
 
10
- if historia[:grupos].empty?
29
+ # Verificação de grupos de passos
30
+ if historia[:grupos].nil? || historia[:grupos].empty?
11
31
  erros << "❌ Nenhum grupo de blocos detectado"
12
32
  else
13
33
  historia[:grupos].each_with_index do |grupo, idx|
14
- if grupo[:passos].empty? && grupo[:exemplos].empty?
34
+ # Cada grupo deve conter passos ou exemplos
35
+ if (grupo[:passos].nil? || grupo[:passos].empty?) &&
36
+ (grupo[:exemplos].nil? || grupo[:exemplos].empty?)
15
37
  erros << "❌ Grupo #{idx + 1} do tipo [#{grupo[:tipo]}] está vazio"
16
38
  end
17
39
 
18
- if grupo[:tipo] == "EXAMPLES" && grupo[:exemplos].none? { |l| l.strip.start_with?('|') }
40
+ # Validação específica para blocos de exemplos
41
+ if grupo[:tipo].casecmp('EXAMPLES').zero? &&
42
+ grupo[:exemplos].none? { |l| l.strip.start_with?('|') }
19
43
  erros << "❌ Grupo de EXAMPLES no bloco #{idx + 1} não contém tabela válida"
20
44
  end
21
45
  end
22
46
  end
23
47
 
48
+ # Exibe erros e retorna false se houver falhas
24
49
  if erros.any?
25
50
  puts "⚠️ Erros encontrados no arquivo:"
26
51
  erros.each { |e| puts " - #{e}" }
27
52
  return false
28
53
  end
29
54
 
55
+ # História válida
30
56
  true
31
57
  end
32
58
  end
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: 0.1.43
4
+ version: 0.1.44
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Nascimento
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: prawn-table
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: prawn-svg
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
27
55
  description: Transforma arquivos .txt com histórias em arquivos .feature, com steps,
28
56
  rastreabilidade e integração com CI/CD.
29
57
  email:
@@ -49,7 +77,6 @@ files:
49
77
  - lib/bddgenx/utils/fontLoader.rb
50
78
  - lib/bddgenx/utils/parser.rb
51
79
  - lib/bddgenx/utils/pdf_exporter.rb
52
- - lib/bddgenx/utils/tipo_param.rb
53
80
  - lib/bddgenx/utils/tracer.rb
54
81
  - lib/bddgenx/utils/validator.rb
55
82
  - lib/bddgenx/version.rb
@@ -1,16 +0,0 @@
1
-
2
- module Bddgenx
3
- # Módulo para inferir o tipo de parâmetro a partir de exemplos
4
- class TipoParam
5
- # Retorna 'string', 'int', 'float' ou 'boolean'
6
- def self.determine_type(nome, estrutura)
7
- return 'string' unless estrutura[:cabecalho].include?(nome)
8
- idx = estrutura[:cabecalho].index(nome)
9
- vals = estrutura[:linhas].map { |l| l[idx] }
10
- return 'boolean' if vals.all? { |v| %w[true false].include?(v.downcase) }
11
- return 'int' if vals.all? { |v| v.match?(/^\d+$/) }
12
- return 'float' if vals.all? { |v| v.match?(/^\d+\.\d+$/) }
13
- 'string'
14
- end
15
- end
16
- end