Skip to content

Commit 749a72d

Browse files
nevinerajcouball
authored andcommitted
Memoize all of the significant calls in Git::Status
When the status has many entries, there were substantial inefficiencies in this class - calling predicates like `changed?(filename)` would iterate the status, constructing a transient `changed` subhash, then test that subhash to see if the file in question was in it (for example). After this, it will _keep_ those sub-hashes for reuse on the Status instance, as well as downcased versions if they happen to get requested (by case-insensitive calls).
1 parent 2bacccc commit 749a72d

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

lib/git/status.rb

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def initialize(base)
2222
#
2323
# @return [Enumerable]
2424
def changed
25-
@files.select { |_k, f| f.type == 'M' }
25+
@_changed ||= @files.select { |_k, f| f.type == 'M' }
2626
end
2727

2828
#
@@ -34,19 +34,15 @@ def changed
3434
# changed?('lib/git.rb')
3535
# @return [Boolean]
3636
def changed?(file)
37-
if ignore_case?
38-
changed.keys.map(&:downcase).include?(file.downcase)
39-
else
40-
changed.member?(file)
41-
end
37+
case_aware_include?(:changed, :lc_changed, file)
4238
end
4339

4440
# Returns an Enumerable containing files that have been added.
4541
# File path starts at git base directory
4642
#
4743
# @return [Enumerable]
4844
def added
49-
@files.select { |_k, f| f.type == 'A' }
45+
@_added ||= @files.select { |_k, f| f.type == 'A' }
5046
end
5147

5248
# Determines whether the given file has been added to the repository
@@ -58,11 +54,7 @@ def added
5854
# added?('lib/git.rb')
5955
# @return [Boolean]
6056
def added?(file)
61-
if ignore_case?
62-
added.keys.map(&:downcase).include?(file.downcase)
63-
else
64-
added.member?(file)
65-
end
57+
case_aware_include?(:added, :lc_added, file)
6658
end
6759

6860
#
@@ -71,7 +63,7 @@ def added?(file)
7163
#
7264
# @return [Enumerable]
7365
def deleted
74-
@files.select { |_k, f| f.type == 'D' }
66+
@_deleted ||= @files.select { |_k, f| f.type == 'D' }
7567
end
7668

7769
#
@@ -83,11 +75,7 @@ def deleted
8375
# deleted?('lib/git.rb')
8476
# @return [Boolean]
8577
def deleted?(file)
86-
if ignore_case?
87-
deleted.keys.map(&:downcase).include?(file.downcase)
88-
else
89-
deleted.member?(file)
90-
end
78+
case_aware_include?(:deleted, :lc_deleted, file)
9179
end
9280

9381
#
@@ -96,7 +84,7 @@ def deleted?(file)
9684
#
9785
# @return [Enumerable]
9886
def untracked
99-
@files.select { |_k, f| f.untracked }
87+
@_untracked ||= @files.select { |_k, f| f.untracked }
10088
end
10189

10290
#
@@ -108,11 +96,7 @@ def untracked
10896
# untracked?('lib/git.rb')
10997
# @return [Boolean]
11098
def untracked?(file)
111-
if ignore_case?
112-
untracked.keys.map(&:downcase).include?(file.downcase)
113-
else
114-
untracked.member?(file)
115-
end
99+
case_aware_include?(:untracked, :lc_untracked, file)
116100
end
117101

118102
def pretty
@@ -290,5 +274,33 @@ def ignore_case?
290274
rescue Git::FailedError
291275
@_ignore_case = false
292276
end
277+
278+
def downcase_keys(hash)
279+
hash.map { |k, v| [k.downcase, v] }.to_h
280+
end
281+
282+
def lc_changed
283+
@_lc_changed ||= changed.transform_keys(&:downcase)
284+
end
285+
286+
def lc_added
287+
@_lc_added ||= added.transform_keys(&:downcase)
288+
end
289+
290+
def lc_deleted
291+
@_lc_deleted ||= deleted.transform_keys(&:downcase)
292+
end
293+
294+
def lc_untracked
295+
@_lc_untracked ||= untracked.transform_keys(&:downcase)
296+
end
297+
298+
def case_aware_include?(cased_hash, downcased_hash, file)
299+
if ignore_case?
300+
send(downcased_hash).include?(file.downcase)
301+
else
302+
send(cased_hash).include?(file)
303+
end
304+
end
293305
end
294306
end

0 commit comments

Comments
 (0)