Module: Line

Defined in:
lib/line.rb

Constant Summary collapse

JARO_SIMILARITY_THRESHOLD =
0.88
MIN_LENGTH_SIMILARITY_THRESHOLD =
0.2
MAX_LENGTH_SIMILARITY_THRESHOLD =
5
COVERAGE_INVALID =
nil
TOKEN_SPLIT_REGEX =
/[\s,.&|^+=*\/-]/
MAX_MEANING_LENGTH =
400
NOT_WHITESPACE_REGEX =
/[^\s]/
BEAUTYSPACE_REGEX =
/\s/
MEANINGLESS_KEYWORDS =
{
  "" => true,
  "//" => true,
  "/*" => true,
  "*/" => true,
  "#" => true,
  "else" => true,
  "end" => true,
  "rescue" => true,
  "{" => true,
  "}" => true,
  "[" => true,
  "]" => true,
  "(" => true,
  ")" => true,
  "<" => true,
  ">" => true,
  "/>" => true
}

Class Method Summary collapse

Class Method Details

.beauty?(a_line, b_line) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
118
119
# File 'lib/line.rb', line 113

def Line.beauty?(a_line, b_line)
  a_start = a_line[:text].index(NOT_WHITESPACE_REGEX)
  b_start = b_line[:text].index(NOT_WHITESPACE_REGEX)

  a_start == b_start &&
    a_line[:text].gsub(BEAUTYSPACE_REGEX, "") == b_line[:text].gsub(BEAUTYSPACE_REGEX, "")
end

.change!(old_line, line) ⇒ Object

TODO: Don’t move/change lines twice.



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/line.rb', line 51

def Line.change!(old_line, line)
  past_revisions = old_line.delete(:revisions) || []
  {
    text: line[:text],
    coverage: line[:coverage],
    commit: line[:commit],
    issues: line[:issues],
    errors: line[:errors],
    bugs: line[:bugs],
    revisions: line[:revisions] + [old_line] + past_revisions
  }
end

.meaningless?(text) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/line.rb', line 90

def Line.meaningless?(text)
  MEANINGLESS_KEYWORDS[text] == true ||
    text.length > MAX_MEANING_LENGTH ||
    text.split(TOKEN_SPLIT_REGEX).length <= 1
end

.merge_error!(line, error, depth) ⇒ Object



68
69
70
71
72
73
74
75
# File 'lib/line.rb', line 68

def Line.merge_error!(line, error, depth)
  return if line[:errors].any? { |line_error| line_error[:error_id] == error[:error_id] }

  line[:errors].unshift({
    error_id: error[:error_id],
    depth: depth
  })
end

.move!(old_line, line) ⇒ Object



64
65
66
# File 'lib/line.rb', line 64

def Line.move!(old_line, line)
  Line.change!(old_line, line)
end

.new_line(text, file_name, line_num, commit) ⇒ Object

TODO: return line_id only.



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/line.rb', line 37

def Line.new_line(text, file_name, line_num, commit)
  line = {
    text: text,
    coverage: COVERAGE_INVALID,
    commit: commit.id,
    issues: commit.issue_id.blank? ? [] : [commit.issue_id],
    bugs: commit.bug_id.blank? ? [] : [commit.bug_id],
    errors: [],
    revisions: []
  }
  line
end

.relevant?(line) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/line.rb', line 77

def Line.relevant?(line)
  MEANINGLESS_KEYWORDS[line[:text].strip()].nil?
end

.relevant_change?(line) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
84
85
86
87
88
# File 'lib/line.rb', line 81

def Line.relevant_change?(line)
  return false if not relevant?(line)
  if line.has_key?(:change)
    a_line = {text: line.dig(:change, :change_text)}
    return trailing?(line, a_line) || beauty?(line, a_line)
  end
  return true
end

.score(line) ⇒ Object



103
104
105
106
107
108
109
110
111
# File 'lib/line.rb', line 103

def Line.score(line)
  score = 0
  line[:errors].each { |error| score += 2.0 / (error[:depth] + 1) }
  score += 3 * line[:bugs].count
  score += 0.75 * line[:revisions].count
  score += 3 if line[:coverage] == 0
  score += 1.5 if line[:coverage].nil?
  score
end

.similar?(text_a, text_b) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
99
100
101
# File 'lib/line.rb', line 96

def Line.similar?(text_a, text_b)
  length_similarity = text_a.length.to_f / text_b.length.to_f
  length_similarity > MIN_LENGTH_SIMILARITY_THRESHOLD &&
    length_similarity < MAX_LENGTH_SIMILARITY_THRESHOLD &&
    text_a.jarowinkler_similar(text_b) > JARO_SIMILARITY_THRESHOLD
end

.trailing?(a_line, b_line) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/line.rb', line 121

def Line.trailing?(a_line, b_line)
  a_line[:text].rstrip == b_line[:text].rstrip
end