require_relative "check_table" class CheckHamlData include CheckTable attr_reader :inputs, :outputs def initialize(filepath) @inputs = File.read(filepath).split("\n") @outputs = [] @inputs.each_with_index do |line, index| output = {id: index, level: 0, state: :none, type: :none, source: line, msg: ""} @outputs << output end @ok = false end def ok? @ok end def show @outputs.each do |i| puts "#{i[:id]}: #{i[:state]} [#{i[:type]}] #{i[:msg]}" end end def show_errors errors = 0 @outputs.each do |i| next if i[:state] == :ok errors += 1 if errors < 11 data = {id: i[:id], msg: i[:msg], source: i[:source][0, 40]} order = i[:id] + 1 data = {order: order, msg: i[:msg], source: i[:source][0, 40]} message1 = Rainbow(" %<order>03d : %<msg>32s. => ").white message2 = Rainbow("%<source>s").yellow.bright output = format(message1, data) + format(message2, data) warn output end warn "..." if errors == 11 end if errors.zero? puts Rainbow("Syntax OK!").green.bright else message = "\nRevise #{errors} syntax warning or error/s\n" warn Rainbow(message).yellow.bright exit 1 end end def check @ok = true @inputs.each_with_index do |line, index| check_empty_lines(line, index) check_map(line, index) check_concept(line, index) check_names(line, index) check_tags(line, index) check_def(line, index) check_table(line, index) check_row(line, index) check_col(line, index) check_template(line, index) check_code(line, index) check_type(line, index) check_path(line, index) check_features(line, index) check_problem(line, index) check_cases(line, index) check_case(line, index) check_desc(line, index) check_ask(line, index) check_text(line, index) check_answer(line, index) check_step(line, index) check_unknown(line, index) @ok = false unless @outputs[index][:state] == :ok @ok = false if @outputs[index][:type] == :unkown end @ok end private def check_empty_lines(line, index) return unless line.strip.size.zero? || line.start_with?("#") @outputs[index][:type] = :empty @outputs[index][:level] = -1 @outputs[index][:state] = :ok end def check_map(line, index) if index.zero? @outputs[index][:type] = :map if line.start_with?("%map{") @outputs[index][:state] = :ok else @outputs[index][:state] = :err @outputs[index][:msg] = "Start with %map{" end elsif index.positive? && line.include?("%map{") @outputs[index][:state] = :err @outputs[index][:type] = :map @outputs[index][:msg] = "Write %map on line 0" end end def check_concept(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%concept" @outputs[index][:type] = :concept @outputs[index][:level] = 1 @outputs[index][:state] = :ok if find_parent(index) != :map @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(map) not found!" elsif !line.match(/^\s\s%concept\s*$/) binding.break @outputs[index][:state] = :err @outputs[index][:msg] = "Write 2 spaces before %concept, and no text after" end end def check_names(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%names" @outputs[index][:type] = :names @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :concept @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(concept) not found!" elsif !line.start_with? " %names" elsif !line.match(/^\s\s\s\s%names\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %names" end end def check_tags(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%tags" @outputs[index][:type] = :tags @outputs[index][:level] = 2 @outputs[index][:state] = :ok if line.strip == "%tags" @outputs[index][:state] = :err @outputs[index][:msg] = "Please, fill with concept tags!" elsif find_parent(index) != :concept @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(concept) not found!" elsif !line.match(/^\s\s\s\s%tags\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %tags" end end def check_def(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%def" @outputs[index][:type] = :def @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :concept @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(concept) not found!" elsif !line.match(/^\s\s\s\s%def[\s{]/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %def" else items = line.strip.split if items.size < 2 @outputs[index][:state] = :err @outputs[index][:msg] = "%def has no definition" end end end def check_code(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%code" @outputs[index][:type] = :code @outputs[index][:level] = 1 @outputs[index][:state] = :ok if find_parent(index) != :map @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(map) not found!" elsif !line.match(/^\s\s%code\s*$/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 2 spaces before %code, and no text after" end end def check_type(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%type" @outputs[index][:type] = :type @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :code @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(code) not found!" elsif !line.match(/^\s\s\s\s%type\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %type" end end def check_path(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%path" @outputs[index][:type] = :path @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :code @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(code) not found!" elsif !line.match(/^\s\s\s\s%path\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %type" end end def check_features(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%features" @outputs[index][:type] = :features @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :code @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(code) not found!" elsif !line.match(/^\s\s\s\s%features\s*$/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %features, and no text after" end end def check_problem(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%problem" @outputs[index][:type] = :problem @outputs[index][:level] = 1 @outputs[index][:state] = :ok if find_parent(index) != :map @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(map) not found!" elsif !line.match(/^\s\s%problem\s*$/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 2 spaces before %problem, and no text after" end end def check_cases(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%cases" @outputs[index][:type] = :cases @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :problem @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(problem) not found!" elsif !line.match(/^\s\s\s\s%cases{\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %cases" end end def check_case(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%case " @outputs[index][:type] = :case @outputs[index][:level] = 3 @outputs[index][:state] = :ok if find_parent(index) != :cases @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(cases) not found!" elsif !line.match(/^\s\s\s\s\s\s%case\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 6 spaces before %case" end end def check_desc(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%desc" @outputs[index][:type] = :desc @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :problem @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(problem) not found!" elsif !line.match(/^\s\s\s\s%desc\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %desc" end end def check_ask(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%ask" @outputs[index][:type] = :ask @outputs[index][:level] = 2 @outputs[index][:state] = :ok if find_parent(index) != :problem @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(problem) not found!" elsif !line.match(/^\s\s\s\s%ask/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 4 spaces before %ask" end end def check_text(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%text" @outputs[index][:type] = :text @outputs[index][:level] = 3 @outputs[index][:state] = :ok if find_parent(index) != :ask @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(ask) not found!" elsif !line.match(/^\s\s\s\s\s\s%text\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 6 spaces before %text" end end def check_answer(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%answer" @outputs[index][:type] = :answer @outputs[index][:level] = 3 @outputs[index][:state] = :ok if find_parent(index) != :ask @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(ask) not found!" elsif !line.match(/^\s\s\s\s\s\s%answer[\s|\{type:]/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 6 spaces before %answer, then space or {type:" end end def check_step(line, index) return unless @outputs[index][:state] == :none return unless line.include? "%step" @outputs[index][:type] = :step @outputs[index][:level] = 3 @outputs[index][:state] = :ok if find_parent(index) != :ask @outputs[index][:state] = :err @outputs[index][:msg] = "Parent(ask) not found!" elsif !line.match(/^\s\s\s\s\s\s%step\s/) @outputs[index][:state] = :err @outputs[index][:msg] = "Write 6 spaces before %step" end end def check_unknown(line, index) return unless @outputs[index][:state] == :none @outputs[index][:type] = :unknown @outputs[index][:level] = count_spaces(line) / 2 @outputs[index][:state] = :err @outputs[index][:msg] = "Unknown tag with parent(#{find_parent(index)})!" end def find_parent(index) current_level = @outputs[index][:level] return :noparent if current_level.zero? i = index - 1 while i >= 0 return @outputs[i][:type] if @outputs[i][:level] == current_level - 1 i -= 1 end :noparent end def count_spaces(line) a = line.split("%") a[0].count(" ") end end