Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/super_diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@ module SuperDiff
autoload :EqualityMatcher, "super_diff/equality_matcher"
autoload :EqualityMatchers, "super_diff/equality_matchers"
autoload :Helpers, "super_diff/helpers"
autoload :ImplementationChecks, "super_diff/implementation_checks"
autoload :NoDifferAvailableError, "super_diff/no_differ_available_error"
autoload(
:NoDiffFormatterAvailableError,
"super_diff/no_diff_formatter_available_error",
)
autoload(
:NoOperationalSequencerAvailableError,
"super_diff/no_operational_sequencer_available_error",
)
autoload :ObjectInspection, "super_diff/object_inspection"
autoload :OperationSequence, "super_diff/operation_sequence"
autoload :OperationSequences, "super_diff/operation_sequences"
autoload :OperationalSequencer, "super_diff/operational_sequencer"
autoload :OperationalSequencers, "super_diff/operational_sequencers"
autoload :OperationSequences, "super_diff/operation_sequences"
autoload :Operations, "super_diff/operations"
autoload :RecursionGuard, "super_diff/recursion_guard"

Expand Down
24 changes: 16 additions & 8 deletions lib/super_diff/diff_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,34 @@ class DiffFormatter
[
:indent_level!,
add_comma: false,
value_class: nil,
extra_classes: [],
],
)

def call
resolved_class.call(
operations,
indent_level: indent_level,
add_comma: add_comma?,
)
if resolved_class
resolved_class.call(
operations,
indent_level: indent_level,
add_comma: add_comma?,
value_class: value_class
)
else
raise NoDiffFormatterAvailableError.create(operations)
end
end

private

attr_query :add_comma?

def resolved_class
(DiffFormatters::DEFAULTS + extra_classes).find do |klass|
klass.applies_to?(operations)
end
available_classes.find { |klass| klass.applies_to?(operations) }
end

def available_classes
DiffFormatters::DEFAULTS + extra_classes
end
end
end
8 changes: 6 additions & 2 deletions lib/super_diff/diff_formatters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ module DiffFormatters
autoload :Hash, "super_diff/diff_formatters/hash"
autoload :MultilineString, "super_diff/diff_formatters/multiline_string"

# TODO: Why doesn't this include CustomObject and DefaultObject?
DEFAULTS = [Array, Hash, MultilineString].freeze
DEFAULTS = [
Array,
Hash,
CustomObject,
DefaultObject,
].freeze
end
end
1 change: 1 addition & 0 deletions lib/super_diff/diff_formatters/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ def self.applies_to?(_operations)
raise NotImplementedError
end

include ImplementationChecks
extend AttrExtras.mixin

method_object(
Expand Down
4 changes: 1 addition & 3 deletions lib/super_diff/diff_formatters/default_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ def value_class
if @value_class
@value_class
else
raise NotImplementedError.new(
"You must override #value_class in your subclass.",
)
unimplemented_instance_method!
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/super_diff/differ.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Differ
index_in_collection: nil,
omit_empty: false,
extra_classes: [],
extra_operation_sequence_classes: [],
extra_operational_sequencer_classes: [],
extra_diff_formatter_classes: [],
],
Expand All @@ -22,6 +23,7 @@ def call
actual,
indent_level: indent_level,
index_in_collection: index_in_collection,
extra_operation_sequence_classes: extra_operation_sequence_classes,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
Expand Down
13 changes: 2 additions & 11 deletions lib/super_diff/differs/array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,10 @@ def self.applies_to?(expected, actual)
expected.is_a?(::Array) && actual.is_a?(::Array)
end

def call
DiffFormatters::Array.call(operations, indent_level: indent_level)
end

private

def operations
OperationalSequencers::Array.call(
expected: expected,
actual: actual,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
def operational_sequencer_class
OperationalSequencers::Array
end
end
end
Expand Down
25 changes: 24 additions & 1 deletion lib/super_diff/differs/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,51 @@ def self.applies_to?(_expected, _actual)
raise NotImplementedError
end

extend ImplementationChecks
extend AttrExtras.mixin
include ImplementationChecks

method_object(
:expected,
:actual,
[
:indent_level!,
index_in_collection: nil,
extra_operation_sequence_classes: [],
extra_operational_sequencer_classes: [],
extra_diff_formatter_classes: [],
],
)

def call
raise NotImplementedError
operations.to_diff(
indent_level: indent_level,
collection_prefix: nil,
add_comma: false,
)
end

protected

def indentation
" " * (indent_level * 2)
end

def operational_sequencer_class
unimplemented_instance_method!
end

private

def operations
operational_sequencer_class.call(
expected: expected,
actual: actual,
extra_operation_sequence_classes: extra_operation_sequence_classes,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
end
end
end
end
13 changes: 2 additions & 11 deletions lib/super_diff/differs/custom_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,10 @@ def self.applies_to?(expected, actual)
actual.respond_to?(:attributes_for_super_diff)
end

def call
operations.to_diff(indent_level: indent_level)
end

private

def operations
OperationalSequencers::CustomObject.call(
expected: expected,
actual: actual,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
def operational_sequencer_class
OperationalSequencers::CustomObject
end
end
end
Expand Down
5 changes: 1 addition & 4 deletions lib/super_diff/differs/default_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ def self.applies_to?(expected, actual)
expected.class == actual.class
end

def call
operations.to_diff(indent_level: indent_level)
end

private

def operations
OperationalSequencer.call(
expected: expected,
actual: actual,
all_or_nothing: true,
extra_operation_sequence_classes: extra_operation_sequence_classes,
extra_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
Expand Down
13 changes: 2 additions & 11 deletions lib/super_diff/differs/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,10 @@ def self.applies_to?(expected, actual)
expected.is_a?(::Hash) && actual.is_a?(::Hash)
end

def call
DiffFormatters::Hash.call(operations, indent_level: indent_level)
end

private

def operations
OperationalSequencers::Hash.call(
expected: expected,
actual: actual,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
def operational_sequencer_class
OperationalSequencers::Hash
end
end
end
Expand Down
16 changes: 2 additions & 14 deletions lib/super_diff/differs/multiline_string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@ def self.applies_to?(expected, actual)
(expected.include?("\n") || actual.include?("\n"))
end

def call
DiffFormatters::MultilineString.call(
operations,
indent_level: indent_level,
)
end

private

def operations
OperationalSequencers::MultilineString.call(
expected: expected,
actual: actual,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
def operational_sequencer_class
OperationalSequencers::MultilineString
end
end
end
Expand Down
13 changes: 2 additions & 11 deletions lib/super_diff/differs/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,10 @@ def self.applies_to?(expected, actual)
OperationalSequencers::TimeLike.applies_to?(expected, actual)
end

def call
operations.to_diff(indent_level: indent_level)
end

private

def operations
OperationalSequencers::TimeLike.call(
expected: expected,
actual: actual,
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
extra_diff_formatter_classes: extra_diff_formatter_classes,
)
def operational_sequencer_class
OperationalSequencers::TimeLike
end
end
end
Expand Down
19 changes: 19 additions & 0 deletions lib/super_diff/implementation_checks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module SuperDiff
module ImplementationChecks
protected def unimplemented_instance_method!
raise(
NotImplementedError,
"#{self.class} must implement ##{caller_locations(1, 1).first.label}",
caller(1),
)
end

protected def unimplemented_class_method!
raise(
NotImplementedError,
"#{self} must implement .#{caller_locations(1, 1).first.label}",
caller(1),
)
end
end
end
19 changes: 19 additions & 0 deletions lib/super_diff/no_diff_formatter_available_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module SuperDiff
class NoDiffFormatterAvailableError < StandardError
def self.create(operations)
allocate.tap do |error|
error.operations = operations
error.__send__(:initialize)
end
end

attr_accessor :operations

def initialize
super(<<-MESSAGE)
There is no diff formatter available to handle an operations object of
#{operations.class}.
MESSAGE
end
end
end
33 changes: 33 additions & 0 deletions lib/super_diff/operation_sequence.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module SuperDiff
class OperationSequence
extend AttrExtras.mixin

method_object :value, [extra_classes: []]

def call
if resolved_class
begin
resolved_class.new([], value_class: value.class)
rescue ArgumentError
resolved_class.new([])
end
else
raise NoOperationalSequenceAvailableError.create(value)
end
end

private

def resolved_class
if value.respond_to?(:attributes_for_super_diff)
OperationSequences::CustomObject
else
available_classes.find { |klass| klass.applies_to?(value) }
end
end

def available_classes
extra_classes + OperationSequences::DEFAULTS
end
end
end
3 changes: 3 additions & 0 deletions lib/super_diff/operation_sequences.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ module OperationSequences
autoload :CustomObject, "super_diff/operation_sequences/custom_object"
autoload :DefaultObject, "super_diff/operation_sequences/default_object"
autoload :Hash, "super_diff/operation_sequences/hash"
autoload :MultilineString, "super_diff/operation_sequences/multiline_string"

DEFAULTS = [Array, Hash, CustomObject, DefaultObject].freeze
end
end
4 changes: 4 additions & 0 deletions lib/super_diff/operation_sequences/array.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
module SuperDiff
module OperationSequences
class Array < Base
def self.applies_to?(value)
value.is_a?(::Array)
end

def to_diff(indent_level:, collection_prefix:, add_comma:)
DiffFormatters::Array.call(
self,
Expand Down
Loading