Skip to content

Commit d18bd14

Browse files
committed
Add a way to elide diffs
When looking at a large diff for which many of the lines do not change, it can be difficult to locate the lines which do. Text-oriented diffs such as those you get from a conventional version control system solve this problem by removing those unchanged lines from the diff entirely. For instance, here is a section of the README with a line removed. Notice that only the part of the file we care about, which is around the line deleted, is displayed in the diff: ``` diff --git a/README.md b/README.md index 56b046c..b38f4ca 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,6 @@ SuperDiff.configure do |config| config.add_extra_differ_class(YourDiffer) config.add_extra_operation_tree_builder_class(YourOperationTreeBuilder) config.add_extra_operation_tree_class(YourOperationTree) - config.add_extra_diff_formatter_class(YourDiffFormatter) end ``` This commit implements a similar feature for data-oriented diffs. It adds two new configuration options to allow you to control the elision logic: * `diff_elision_enabled` — The elision logic is disabled by default so as not to surprise people, so setting this to `true` will turn it on. * `diff_elision_maximum` — This number controls what happens to unchanged lines (i.e. lines that are neither "insert" lines nor "delete" lines) that are in between changed lines. If a section of unchanged lines is beyond this number, the gem will elide (a fancy word for remove) the data structures within that section as much as possible until the limit is reached or it cannot go further. Elided lines are replaced with a `# ...` marker. Here are a few examples: \### Elision enabled If you add this to your test helper: ``` ruby SuperDiff.configure do |config| config.diff_elision_enabled = true end ``` And you have this test: ``` ruby expected = [ "Afghanistan", "Aland Islands", "Albania", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Aruba", "Australia" ] actual = [ "Afghanistan", "Aland Islands", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua And Barbuda", "Armenia", "Aruba", "Australia" ] expect(actual).to eq(expected) ``` Then you will get a diff that looks like: ``` [ # ... - "Albania", + "Algeria", # ... - "Argentina", + "Armenia", "Aruba", "Australia" ] ``` \### Elision enabled and maximum specified Configuration: ``` ruby SuperDiff.configure do |config| config.diff_elision_enabled = true config.diff_elision_maximum = 5 end ``` Test: ``` expected = [ "Afghanistan", "Aland Islands", "Albania", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Aruba", "Australia" ] actual = [ "Afghanistan", "Aland Islands", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua And Barbuda", "Armenia", "Aruba", "Australia" ] expect(actual).to eq(expected) ``` Resulting diff: ``` [ "Afghanistan", "Aland Islands", - "Albania", + "Algeria", "American Samoa", "Andorra", # ... "Antarctica", "Antigua And Barbuda", - "Argentina", + "Armenia", "Aruba", "Australia" ] ``` \### Elision enabled and maximum specified, but indentation limits complete elision Configuration: ``` ruby SuperDiff.configure do |config| config.diff_elision_enabled = true end ``` Test: ``` ruby expected = { foo: { bar: [ "one", "two", "three" ], baz: "qux", fizz: "buzz", zing: "bing" } } actual = [ foo: { bar: [ "one", "two", "tree" ], baz: "qux", fizz: "buzz", zing: "bing" } ] expect(actual).to eq(expected) ``` Resulting diff: ``` { foo: { bar: [ # ... - "three" + "tree" ], # ... } } ``` Notice how we cannot fully elide all of the unchanged lines in this case because otherwise the diff would look like this and it wouldn't make sense: ``` # ... - "three" + "tree" # ... ```
1 parent b911118 commit d18bd14

File tree

173 files changed

+15670
-2483
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

173 files changed

+15670
-2483
lines changed

CHANGELOG.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Breaking changes
6+
7+
* Diff formatters are now gone in favor of operation tree flatteners. If you
8+
have a custom diff formatter, you will want to inherit from
9+
SuperDiff::OperationTreeFlatteners::Base (or an appropriate subclass).
10+
Additionally, the `add_extra_diff_formatter_class` configuration option has
11+
disappeared; instead, operation tree classes are expected to have an
12+
`operation_tree_flattener_class` method, which should return your custom
13+
operation tree flattener class.
14+
15+
### Features
16+
17+
* Add the ability to compress long diffs by eliding sections of unchanged data
18+
(data which is present in both "expected" and "actual" values). This
19+
functionality is not enabled by default; rather, you will need to activate it.
20+
At a minimum, you will want to add this to your test helper:
21+
22+
``` ruby
23+
SuperDiff.configure do |config|
24+
config.diff_elision_enabled = true
25+
end
26+
```
27+
28+
By default the elision will be pretty aggressive, but if you want to preserve
29+
more of the unchanged lines in the diff, you can set `diff_elision_maximum`:
30+
31+
``` ruby
32+
SuperDiff.configure do |config|
33+
config.diff_elision_enabled = true
34+
config.diff_elision_maximum = 10
35+
end
36+
```
37+
38+
Here, the gem will try to keep at least 10 unchanged lines in between changed
39+
lines.
40+
41+
### Features
42+
43+
* Update inspection of Doubles to include stubbed methods and their values.
44+
45+
### Improvements
46+
47+
* Change how objects are inspected on a single line so that instance variables
48+
are always sorted.
49+
* Make a tweak to how hashes are presented in diffs and inspections: a hash that
50+
has a mixture of symbols and strings will be presented as though all keys are
51+
strings (i.e. hashrocket syntax).
52+
353
## 0.7.0 - 2021-05-07
454

555
### Features

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ SuperDiff.configure do |config|
202202
config.add_extra_differ_class(YourDiffer)
203203
config.add_extra_operation_tree_builder_class(YourOperationTreeBuilder)
204204
config.add_extra_operation_tree_class(YourOperationTree)
205-
config.add_extra_diff_formatter_class(YourDiffFormatter)
206205
end
207206
```
208207

config/zeus_plan.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ class CustomZeusPlan < Zeus::Plan
2020
:run_rspec_rails_test,
2121
)
2222

23-
def initialize(using_outside_of_zeus: false, color_enabled: false)
23+
def initialize(
24+
using_outside_of_zeus: false,
25+
color_enabled: false,
26+
configuration: {}
27+
)
2428
@test_plan = TestPlan.new(
2529
using_outside_of_zeus: using_outside_of_zeus,
2630
color_enabled: color_enabled,
31+
configuration: configuration,
2732
)
2833
end
2934
end

lib/super_diff.rb

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module SuperDiff
77
:ColorizedDocumentExtensions,
88
"super_diff/colorized_document_extensions",
99
)
10+
autoload :OperationTreeFlatteners, "super_diff/operation_tree_flatteners"
1011
autoload :Configuration, "super_diff/configuration"
1112
autoload :Csi, "super_diff/csi"
1213
autoload :DiffFormatters, "super_diff/diff_formatters"
@@ -16,6 +17,10 @@ module SuperDiff
1617
autoload :GemVersion, "super_diff/gem_version"
1718
autoload :Helpers, "super_diff/helpers"
1819
autoload :ImplementationChecks, "super_diff/implementation_checks"
20+
autoload :Line, "super_diff/line"
21+
autoload :TieredLines, "super_diff/tiered_lines"
22+
autoload :TieredLinesElider, "super_diff/tiered_lines_elider"
23+
autoload :TieredLinesFormatter, "super_diff/tiered_lines_formatter"
1924
autoload :ObjectInspection, "super_diff/object_inspection"
2025
autoload :OperationTrees, "super_diff/operation_trees"
2126
autoload :OperationTreeBuilders, "super_diff/operation_tree_builders"
@@ -24,18 +29,25 @@ module SuperDiff
2429

2530
def self.configure
2631
yield configuration
32+
configuration.updated
2733
end
2834

2935
def self.configuration
3036
@_configuration ||= Configuration.new
3137
end
3238

33-
def self.inspect_object(object, as_single_line:, indent_level: 0)
34-
ObjectInspection::Inspectors::Main.call(
35-
object,
36-
as_single_line: as_single_line,
37-
indent_level: indent_level,
38-
)
39+
def self.inspect_object(object, as_lines:, **rest)
40+
SuperDiff::RecursionGuard.guarding_recursion_of(object) do
41+
inspection_tree = ObjectInspection::InspectionTreeBuilders::Main.call(
42+
object
43+
)
44+
45+
if as_lines
46+
inspection_tree.render_to_lines(object, **rest)
47+
else
48+
inspection_tree.render_to_string(object)
49+
end
50+
end
3951
end
4052

4153
def self.time_like?(value)
@@ -45,6 +57,15 @@ def self.time_like?(value)
4557
value.is_a?(Time)
4658
end
4759

60+
def self.primitive?(value)
61+
case value
62+
when true, false, nil, Symbol, Numeric, Regexp, Class
63+
true
64+
else
65+
false
66+
end
67+
end
68+
4869
def self.insert_overrides(target_module, mod = nil, &block)
4970
if mod
5071
target_module.prepend(mod)

lib/super_diff/active_record.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
module SuperDiff
44
module ActiveRecord
5-
autoload :DiffFormatters, "super_diff/active_record/diff_formatters"
65
autoload :Differs, "super_diff/active_record/differs"
76
autoload(
87
:ObjectInspection,
@@ -16,6 +15,10 @@ module ActiveRecord
1615
:OperationTreeBuilders,
1716
"super_diff/active_record/operation_tree_builders",
1817
)
18+
autoload(
19+
:OperationTreeFlatteners,
20+
"super_diff/active_record/operation_tree_flatteners",
21+
)
1922

2023
SuperDiff.configure do |config|
2124
config.add_extra_differ_classes(
@@ -25,12 +28,9 @@ module ActiveRecord
2528
OperationTreeBuilders::ActiveRecordModel,
2629
OperationTreeBuilders::ActiveRecordRelation,
2730
)
28-
config.add_extra_diff_formatter_classes(
29-
DiffFormatters::ActiveRecordRelation,
30-
)
31-
config.add_extra_inspector_classes(
32-
ObjectInspection::Inspectors::ActiveRecordModel,
33-
ObjectInspection::Inspectors::ActiveRecordRelation,
31+
config.add_extra_inspection_tree_builder_classes(
32+
ObjectInspection::InspectionTreeBuilders::ActiveRecordModel,
33+
ObjectInspection::InspectionTreeBuilders::ActiveRecordRelation,
3434
)
3535
end
3636
end

lib/super_diff/active_record/diff_formatters.rb

Lines changed: 0 additions & 10 deletions
This file was deleted.

lib/super_diff/active_record/diff_formatters/active_record_relation.rb

Lines changed: 0 additions & 23 deletions
This file was deleted.

lib/super_diff/active_record/differs/active_record_relation.rb

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,10 @@ def self.applies_to?(expected, actual)
77
actual.is_a?(::ActiveRecord::Relation)
88
end
99

10-
def call
11-
DiffFormatters::ActiveRecordRelation.call(
12-
operation_tree,
13-
indent_level: indent_level,
14-
)
15-
end
16-
17-
private
10+
protected
1811

19-
def operation_tree
20-
OperationTreeBuilders::ActiveRecordRelation.call(
21-
expected: expected,
22-
actual: actual,
23-
)
12+
def operation_tree_builder_class
13+
OperationTreeBuilders::ActiveRecordRelation
2414
end
2515
end
2616
end

lib/super_diff/active_record/object_inspection.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@ module SuperDiff
22
module ActiveRecord
33
module ObjectInspection
44
autoload(
5-
:Inspectors,
6-
"super_diff/active_record/object_inspection/inspectors",
7-
)
8-
autoload(
9-
:MapExtension,
10-
"super_diff/active_record/object_inspection/map_extension",
5+
:InspectionTreeBuilders,
6+
"super_diff/active_record/object_inspection/inspection_tree_builders",
117
)
128
end
139
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module SuperDiff
2+
module ActiveRecord
3+
module ObjectInspection
4+
module InspectionTreeBuilders
5+
autoload(
6+
:ActiveRecordModel,
7+
"super_diff/active_record/object_inspection/inspection_tree_builders/active_record_model",
8+
)
9+
autoload(
10+
:ActiveRecordRelation,
11+
"super_diff/active_record/object_inspection/inspection_tree_builders/active_record_relation",
12+
)
13+
end
14+
end
15+
end
16+
end

0 commit comments

Comments
 (0)