Description
Refactor fluent builder object Git::Log
to use explicit execution via a new #execute
method, improving API clarity and predictability.
Problem and Motivation
Currently, objects like Git::Log are fluent builders that build a command whose data fetched using a lazy-loading pattern. It is lazy-loading because the actual git command is executed implicitly when a data-access method (each, size, first, etc.) is called.
This is managed by an internal @dirty_flag
that must be checked by every accessor method. This design has several drawbacks:
- It's complex: The object must track its state (builder vs. result set) and the dirty flag logic must be implemented perfectly in every relevant method.
- It's hard to maintain: Adding new accessor methods is error-prone, as each must remember to check the dirty flag.
- It's unpredictable: Users may not realize when an expensive git command is being executed, which could lead to unexpected performance issues.
Proposed Solution
I propose we refactor these fluent interfaces to use explicit execution. This separates the query-building responsibility from the result-handling.
- The
Git::Log
object would become a pure query building object. Its methods (since, author, etc.) would only configure the command. - A new method,
#execute
, would be added. This method is the only one that runs the git command. - The
#execute
method would return a new, immutable result object. - All data-access methods (
each
,size
,first
,last
, etc.) would be moved to this new result object, operating on a static collection of commits.
Before:
# `git log` is run implicitly inside .size and .each
log = g.log.since('2 weeks ago').author('Scott')
puts "Found #{log.size} commits"
log.each do |commit|
# ...
end
After:
query = g.log.since('2 weeks ago').author('Scott')
results = query.execute
puts "Found #{results.size} commits"
results.each do |commit|
# ...
end
Benefits of This Change
- Predictable Performance: The developer knows exactly when the expensive git command is run.
- Clarity: The API becomes easier to reason about. You build a query, you execute it, you get results.
- Simpler Implementation: The complex and brittle dirty flag logic can be completely removed.
- Safer, Immutable Results: The result set is a stable snapshot and won't change unexpectedly.
Affected Classes
Git::Log
BREAKING CHANGE
This is a breaking API change and would require a major version bump (e.g., to v4.0.0). The benefits in terms of API robustness, predictability, and maintainability justify the change for a new major release.