Class: Bddgenx::StepsGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/bddgenx/generators/steps_generator.rb

Constant Summary collapse

GHERKIN_KEYS_PT =

Palavras-chave Gherkin em Português

%w[Dado Quando Então E Mas].freeze
GHERKIN_KEYS_EN =

Palavras-chave Gherkin em Inglês

%w[Given When Then And But].freeze
ALL_KEYS =

Conjunto de todas as palavras-chave suportadas

GHERKIN_KEYS_PT + GHERKIN_KEYS_EN

Class Method Summary collapse

Class Method Details

.camelize(str) ⇒ String

Transforma uma string em estilo camelCase.

Parameters:

  • str (String)

    A string a ser transformada.

Returns:

  • (String)

    A string convertida para camelCase.



26
27
28
29
# File 'lib/bddgenx/generators/steps_generator.rb', line 26

def self.camelize(str)
  partes = str.strip.split(/[^a-zA-Z0-9]+/)
  partes.map.with_index { |palavra, i| i.zero? ? palavra.downcase : palavra.capitalize }.join
end

.gerar_passos(feature_path) ⇒ Boolean

Gera arquivos de passos do Cucumber a partir de um arquivo .feature.

O método lê o arquivo, detecta o idioma, extrai os passos, parametriza as variáveis (números e strings), e escreve os métodos em um novo arquivo no diretório ‘steps/`.

Parameters:

  • feature_path (String)

    Caminho para o arquivo .feature.

Returns:

  • (Boolean)

    Retorna true se os passos forem gerados com sucesso, false se não houver passos.

Raises:

  • (ArgumentError)

    Se o caminho fornecido não for uma String.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/bddgenx/generators/steps_generator.rb', line 42

def self.gerar_passos(feature_path)
  raise ArgumentError, "Caminho esperado como String, recebeu #{feature_path.class}" unless feature_path.is_a?(String)

  linhas = File.readlines(feature_path)

  # Detecta o idioma com base na diretiva "# language:"
  lang = if (m = linhas.find { |l| l =~ /^#\s*language:\s*(\w+)/i })
           m[/^#\s*language:\s*(\w+)/i, 1].downcase
         else
           'pt'
         end

  pt_para_en = GHERKIN_KEYS_PT.zip(GHERKIN_KEYS_EN).to_h
  en_para_pt = GHERKIN_KEYS_EN.zip(GHERKIN_KEYS_PT).to_h

  # Seleciona apenas linhas que começam com palavras-chave Gherkin
  linhas_passos = linhas.map(&:strip).select do |linha|
    ALL_KEYS.any? { |chave| linha.start_with?(chave + ' ') }
  end

  return false if linhas_passos.empty?

  dir_saida = File.join(File.dirname(feature_path), 'steps')
  FileUtils.mkdir_p(dir_saida)
  arquivo_saida = File.join(dir_saida, "#{File.basename(feature_path, '.feature')}_steps.rb")

  conteudo = +"# encoding: utf-8\n"
  conteudo << "# Definições de passos geradas automaticamente para #{File.basename(feature_path)}\n\n"

  passos_unicos = Set.new

  linhas_passos.each do |linha|
    palavra_original, restante = linha.split(' ', 2)

    # Tradução de palavras-chave se necessário
    chave = case lang
            when 'en' then pt_para_en[palavra_original] || palavra_original
            else           en_para_pt[palavra_original] || palavra_original
            end

    texto_bruto = restante.dup
    scanner = ::StringScanner.new(restante)
    padrao = ''
    tokens = []

    # Analisa e parametriza o conteúdo dos passos
    until scanner.eos?
      if scanner.check(/"<([^>]+)>"/)
        scanner.scan(/"<([^>]+)>"/)
        tokens << scanner[1]
        padrao << '{string}'
      elsif scanner.check(/<([^>]+)>/)
        scanner.scan(/<([^>]+)>/)
        tokens << scanner[1]
        padrao << '{int}'
      elsif scanner.check(/"([^"<>]+)"/)
        scanner.scan(/"([^"<>]+)"/)
        tokens << scanner[1]
        padrao << '{string}'
      elsif scanner.check(/\d+(?:\.\d+)?/)
        numero = scanner.scan(/\d+(?:\.\d+)?/)
        tokens << numero
        padrao << '{int}'
      else
        padrao << scanner.getch
      end
    end

    padrao_seguro = padrao.gsub('"', '\\"')

    # Impede criação de métodos duplicados
    next if passos_unicos.include?(padrao_seguro)

    passos_unicos << padrao_seguro

    assinatura = "#{chave}(\"#{padrao_seguro}\")"
    if tokens.any?
      argumentos = tokens.each_index.map { |i| "arg#{i+1}" }.join(', ')
      assinatura << " do |#{argumentos}|"
    else
      assinatura << ' do'
    end

    conteudo << "#{assinatura}\n"
    conteudo << "  pending 'Implementar passo: #{texto_bruto}'\n"
    conteudo << "end\n\n"
  end

  File.write(arquivo_saida, conteudo)
  puts "✅ Steps gerados: #{arquivo_saida}"
  true
end