Class: VirtualFile

Inherits:
Object
  • Object
show all
Defined in:
lib/virtual_file.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path, diff = nil) ⇒ VirtualFile

Returns a new instance of VirtualFile.



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/virtual_file.rb', line 18

def initialize(file_path, diff=nil)
  @path = file_path
  @file_id = nil
  @previous_file_id = nil
  @touched_at_times = []
  @commits = []
  @issues = []
  @bugs = []
  @lines = []
  @functions = []
  @business_value = 0
  @is_binary = diff.blank? ? false : diff.operation == :binary
end

Instance Attribute Details

#business_valueObject (readonly)

Returns the value of attribute business_value.



16
17
18
# File 'lib/virtual_file.rb', line 16

def business_value
  @business_value
end

#commitsObject (readonly)

Returns the value of attribute commits.



15
16
17
# File 'lib/virtual_file.rb', line 15

def commits
  @commits
end

#file_idObject (readonly)

Returns the value of attribute file_id.



13
14
15
# File 'lib/virtual_file.rb', line 13

def file_id
  @file_id
end

#issuesObject (readonly)

Returns the value of attribute issues.



14
15
16
# File 'lib/virtual_file.rb', line 14

def issues
  @issues
end

#linesObject (readonly)

Returns the value of attribute lines.



11
12
13
# File 'lib/virtual_file.rb', line 11

def lines
  @lines
end

#pathObject (readonly)

Returns the value of attribute path.



12
13
14
# File 'lib/virtual_file.rb', line 12

def path
  @path
end

Class Method Details

.from_json(file_id, json) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/virtual_file.rb', line 32

def self.from_json(file_id, json)
  file = VirtualFile.new(json["path"])
  touched_at_times = (json["touched_at_times"] || []).map { |time| DateTime.rfc3339(time) }
  lines = (json["lines"] || []).map { |line| line.deep_symbolize_keys }
  functions = (json["functions"] || []).map { |function| function.deep_symbolize_keys }

  file.instance_variable_set(:@file_id, file_id)
  file.instance_variable_set(:@previous_file_id, json["previous_file_id"])
  file.instance_variable_set(:@touched_at_times, touched_at_times)
  file.instance_variable_set(:@lines, lines)
  file.instance_variable_set(:@functions, functions)
  file.instance_variable_set(:@commits, json["commits"] || [])
  file.instance_variable_set(:@issues, json["issues"] || [])
  file.instance_variable_set(:@bugs, json["bugs"] || [])
  file.instance_variable_set(:@business_value, json["business_value"] || 0)
  file.instance_variable_set(:@is_binary, false)
  file
end

Instance Method Details

#apply_file_diff!(commit, file_diff) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/virtual_file.rb', line 71

def apply_file_diff!(commit, file_diff)
  touch(commit, file_diff)
  return if binary?

  context = file_diff.diffs
    .reduce(new_context(commit), &method(:apply_diff))

  new_lines = context[:new_lines]

  unchanged_lines = @lines[context[:position]..-1]
  new_lines.concat(unchanged_lines) if unchanged_lines

  @lines = new_lines
end

#as_jsonObject



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/virtual_file.rb', line 127

def as_json()
  {
    path: @path,
    previous_file_id: @previous_file_id,
    lines: @lines,
    functions: @functions.map { |function| function.as_json() },
    commits: @commits,
    issues: @issues,
    business_value: @business_value,
    bugs: @bugs
  }
end

#binary?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/virtual_file.rb', line 86

def binary?
  @is_binary
end

#buggy_lines_totalObject



155
156
157
158
159
160
161
162
# File 'lib/virtual_file.rb', line 155

def buggy_lines_total()
  @lines
    .map do |line|
      line[:revisions].flat_map { |revision| revision[:bugs] }.count +
        line[:bugs].count
    end
    .reduce(0, &:+)
end

#change_line!(line_change, line_number) ⇒ Object



102
103
104
# File 'lib/virtual_file.rb', line 102

def change_line!(line_change, line_number)
  @lines[line_number] = Line::change!(line_change, @lines[line_number])
end

#covered_linesObject



164
165
166
167
168
# File 'lib/virtual_file.rb', line 164

def covered_lines
  @lines
    .select { |line| line[:coverage] != nil && line[:coverage] > 0 }
    .count
end

#created_atObject



94
95
96
# File 'lib/virtual_file.rb', line 94

def created_at
  @touched_at_times.first
end

#errors_totalObject



146
147
148
149
150
151
152
153
# File 'lib/virtual_file.rb', line 146

def errors_total()
  @lines
    .map do |line|
      line[:revisions].flat_map { |revision| revision[:errors] }.count +
        line[:errors].count
    end
    .reduce(0, &:+)
end

#last_updated_atObject



98
99
100
# File 'lib/virtual_file.rb', line 98

def last_updated_at
  @touched_at_times.last
end

#merge_coverage!(file_coverage) ⇒ Object



116
117
118
119
120
# File 'lib/virtual_file.rb', line 116

def merge_coverage!(file_coverage)
  @lines.each_with_index do |line, index|
    line[:coverage] = file_coverage.dig("lines", (index + 1).to_s, "hits")
  end
end

#merge_error!(error, trace, depth) ⇒ Object



122
123
124
125
# File 'lib/virtual_file.rb', line 122

def merge_error!(error, trace, depth)
  line = @lines[trace[:line] - 1]
  Line::merge_error!(line, error, depth)
end

#move_line!(line_movement, line_number) ⇒ Object



106
107
108
109
110
111
112
113
114
# File 'lib/virtual_file.rb', line 106

def move_line!(line_movement, line_number)
  line = @lines[line_number]
  if line_movement[:text].strip() != line[:text].strip()
    # TODO: raise reconstruction error.
    Loggr.instance.warn("MISMATCH: #{line[:text]} VS #{line_movement[:text]}")
  else
    @lines[line_number] = Line::move!(line_movement, line)
  end
end

#plain_textObject



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

def plain_text
  @lines.map { |line| line[:text] }
end

#revisions_totalObject



140
141
142
143
144
# File 'lib/virtual_file.rb', line 140

def revisions_total()
  @lines
    .map { |line| line[:revisions].count }
    .reduce(0, &:+)
end

#saveObject



62
63
64
65
66
67
68
69
# File 'lib/virtual_file.rb', line 62

def save()
  @functions = Tracer
    .new
    .trace(@path, as_text())
    .map { |function| VirtualFunction.new(function, @path, @lines) }

  Cache::write_object(@file_id, as_json())
end

#touch(commit, file_diff) ⇒ Object



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

def touch(commit, file_diff)
  @path = file_diff.b_file_name
  @file_id = file_diff.b_file_id if not file_diff.b_file_id.nil?
  @previous_file_id = file_diff.a_file_id
  @touched_at_times << commit.date
  @commits << commit.id
  @issues << commit.issue_id if commit.issue_id.present?
  @bugs << commit.bug_id if commit.bug_id.present?
  @business_value += diff_business_value(commit, file_diff)
end

#uncovered_linesObject



170
171
172
173
174
# File 'lib/virtual_file.rb', line 170

def uncovered_lines
  @lines
    .select { |line| line[:coverage] == 0 }
    .count
end