File: ruleset.rb

package info (click to toggle)
ruby-mdl 0.13.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 196 kB
  • sloc: ruby: 1,485; python: 40; makefile: 4; sh: 3
file content (144 lines) | stat: -rw-r--r-- 3,809 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
134
135
136
137
138
139
140
141
142
143
144
module MarkdownLint
  # defines a single rule
  class Rule
    attr_accessor :id, :description

    def initialize(id, description, fallback_docs: nil, &block)
      @id = id
      @description = description
      @generate_docs = fallback_docs
      @docs_overridden = false
      @aliases = []
      @tags = []
      @params = {}
      instance_eval(&block)
    end

    def check(&block)
      @check = block unless block.nil?
      @check
    end

    def tags(*tags)
      @tags = tags.flatten.map(&:to_sym) unless tags.empty?
      @tags
    end

    def aliases(*aliases)
      @aliases.concat(aliases)
      @aliases
    end

    def params(params = nil)
      @params.update(params) unless params.nil?
      @params
    end

    def docs(url = nil, &block)
      if block_given? != url.nil?
        raise ArgumentError, 'Give either a URL or a block, not both'
      end

      raise 'A docs url is already set within this rule' if @docs_overridden

      @generate_docs = block_given? ? block : lambda { |_, _| url }
      @docs_overridden = true
    end

    def docs_url
      @generate_docs&.call(id, description)
    end

    # This method calculates the number of columns in a table row
    #
    # @param [String] table_row A row of the table in question.
    # @return [Numeric] Number of columns in the row
    def number_of_columns_in_a_table_row(table_row)
      columns = table_row.strip.split('|')

      if columns.empty?
        # The stripped line consists of zero or more pipe characters
        # and nothing more.
        #
        # Examples of stripped rows:
        #   '||' --> one column
        #   '|||' --> two columns
        #   '|' --> zero columns
        [0, table_row.count('|') - 1].max
      else
        # Number of columns is the number of splited
        # segments with pipe separator. The first segment
        # is ignored when it's empty string because
        # someting like '|1|2|' is split into ['', '1', '2']
        # when using split('|') function.
        #
        # Some examples:
        #   '|foo|bar|' --> two columns
        #   '  |foo|bar|' --> two columns
        #   '|foo|bar' --> two columns
        #   'foo|bar' --> two columns
        columns.size - (columns[0].empty? ? 1 : 0)
      end
    end

    # This method returns all the rows of a table
    #
    # @param [Array<String>] lines Lines of a doc as an array
    # @param [Numeric] pos Position/index of the table in the array
    # @return [Array<String>] Rows of the table in an array
    def get_table_rows(lines, pos)
      table_rows = []
      while pos < lines.length
        line = lines[pos]

        # If the previous line is a table and the current line
        #   1) includes pipe character
        #   2) does not start with code block identifiers
        #     a) >= 4 spaces
        #     b) < 4 spaces and ``` right after
        #
        # it is possibly a table row
        unless line.include?('|') && !line.start_with?('    ') &&
               !line.strip.start_with?('```')
          break
        end

        table_rows << line
        pos += 1
      end

      table_rows
    end
  end

  # defines a ruleset
  class RuleSet
    attr_reader :rules

    def initialize
      @rules = {}
    end

    def rule(id, description, &block)
      @rules[id] =
        Rule.new(id, description, :fallback_docs => @fallback_docs, &block)
    end

    def load(rules_file)
      instance_eval(File.read(rules_file), rules_file)
      @rules
    end

    def docs(url = nil, &block)
      if block_given? != url.nil?
        raise ArgumentError, 'Give either a URL or a block, not both'
      end

      @fallback_docs = block_given? ? block : lambda { |_, _| url }
    end

    def load_default
      load(File.expand_path('rules.rb', __dir__))
    end
  end
end