summaryrefslogtreecommitdiff
path: root/lib/diff/lcs/change.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diff/lcs/change.rb')
-rw-r--r--lib/diff/lcs/change.rb155
1 files changed, 114 insertions, 41 deletions
diff --git a/lib/diff/lcs/change.rb b/lib/diff/lcs/change.rb
index 7977be5..520aeda 100644
--- a/lib/diff/lcs/change.rb
+++ b/lib/diff/lcs/change.rb
@@ -1,107 +1,133 @@
# frozen_string_literal: true
+# typed: strict
# Represents a simplistic (non-contextual) change. Represents the removal or
# addition of an element from either the old or the new sequenced
# enumerable.
class Diff::LCS::Change
- INTEGER = 1.class # Fixnum is deprecated in Ruby 2.4
+ extend T::Sig
+
+ ArrayT = T.type_alias{
+ T.any(
+ [String, Integer, T.untyped],
+ [String, Integer, T.untyped, Integer, T.untyped],
+ [String, [Integer, T.untyped], [Integer, T.untyped]]
+ )
+ }
+
+ ChangeT = T.type_alias { T.any(Diff::LCS::Change, Diff::LCS::ContextChange) }
# The only actions valid for changes are '+' (add), '-' (delete), '='
# (no change), '!' (changed), '<' (tail changes from first sequence), or
# '>' (tail changes from second sequence). The last two ('<>') are only
# found with Diff::LCS::diff and Diff::LCS::sdiff.
- VALID_ACTIONS = %w(+ - = ! > <).freeze
+ VALID_ACTIONS = T.let(%w(+ - = ! > <).freeze, T::Array[String])
+ sig { params(action: T.any(String, Diff::LCS::Change)).returns(T::Boolean) }
def self.valid_action?(action)
- VALID_ACTIONS.include? action
+ return false unless action.kind_of?(String)
+
+ VALID_ACTIONS.include?(action)
end
# Returns the action this Change represents.
+ sig { returns(String) }
attr_reader :action
+
# Returns the position of the Change.
+ sig { returns(Integer) }
attr_reader :position
+
# Returns the sequence element of the Change.
+ sig { returns(T.untyped) }
attr_reader :element
- def initialize(*args)
- @action, @position, @element = *args
+ sig {
+ params(
+ action: String,
+ position: Integer,
+ element: T.untyped,
+ _: T.untyped
+ ).void
+ }
+ def initialize(action, position, element, *_)
+ @action = action
+ @position = position
+ @element = element
fail "Invalid Change Action '#{@action}'" unless Diff::LCS::Change.valid_action?(@action)
- fail 'Invalid Position Type' unless @position.kind_of? INTEGER
+ fail 'Invalid Position Type' unless @position.kind_of? Integer
end
+ sig { params(_args: T.untyped).returns(String) }
def inspect(*_args)
"#<#{self.class}: #{to_a.inspect}>"
end
+ sig { returns(ArrayT) }
def to_a
[@action, @position, @element]
end
alias to_ary to_a
+ sig { params(arr: ArrayT).returns(ChangeT) }
def self.from_a(arr)
arr = arr.flatten(1)
case arr.size
when 5
- Diff::LCS::ContextChange.new(*(arr[0...5]))
+ Diff::LCS::ContextChange.new(arr[0], arr[1], arr[2], arr[3], arr[4])
when 3
- Diff::LCS::Change.new(*(arr[0...3]))
+ Diff::LCS::Change.new(arr[0], arr[1], arr[2])
else
fail 'Invalid change array format provided.'
end
end
- def to_change(action)
- args =
- case action
- when '-'
- [action, old_position, old_element]
- when '+'
- [action, new_position, new_element]
- else
- fail 'Invalid action for creating a change'
- end
-
- Diff::LCS::Change.new(*args)
- end
-
include Comparable
+ sig { params(other: ChangeT).returns(T::Boolean) }
def ==(other)
- (self.class == other.class) and
- (action == other.action) and
- (position == other.position) and
- (element == other.element)
+ self.class == other.class &&
+ action == other.action &&
+ position == other.position &&
+ element == other.element
end
+ sig { params(other: Diff::LCS::Change).returns(Integer) }
def <=>(other)
r = action <=> other.action
- r = position <=> other.position if r.zero?
- r = element <=> other.element if r.zero?
+ r = position <=> other.position if T.must(r).zero?
+ r = element <=> other.element if T.must(r).zero?
r
end
+ sig { returns(T::Boolean) }
def adding?
@action == '+'
end
+ sig { returns(T::Boolean) }
def deleting?
@action == '-'
end
+ sig { returns(T::Boolean) }
def unchanged?
@action == '='
end
+ sig { returns(T::Boolean) }
def changed?
@action == '!'
end
+ sig { returns(T::Boolean) }
def finished_a?
@action == '>'
end
+ sig { returns(T::Boolean) }
def finished_b?
@action == '<'
end
@@ -111,27 +137,51 @@ end
# elements in the old and the new sequenced enumerables as well as the action
# taken.
class Diff::LCS::ContextChange < Diff::LCS::Change
+ extend T::Sig
+
# We don't need these two values.
undef :position
undef :element
# Returns the old position being changed.
+ sig { returns(Integer) }
attr_reader :old_position
+
# Returns the new position being changed.
+ sig { returns(Integer) }
attr_reader :new_position
+
# Returns the old element being changed.
+ sig { returns(T.untyped) }
attr_reader :old_element
+
# Returns the new element being changed.
+ sig { returns(T.untyped) }
attr_reader :new_element
- def initialize(*args)
- @action, @old_position, @old_element, @new_position, @new_element = *args
+ sig {
+ params(
+ action: String,
+ old_position: Integer,
+ old_element: T.untyped,
+ new_position: Integer,
+ new_element: T.untyped,
+ _: T.untyped
+ ).void
+ }
+ def initialize(action, old_position, old_element, new_position, new_element, *_)
+ @action = action
+ @old_position = old_position
+ @old_element = old_element
+ @new_position = new_position
+ @new_element = new_element
fail "Invalid Change Action '#{@action}'" unless Diff::LCS::Change.valid_action?(@action)
- fail 'Invalid (Old) Position Type' unless @old_position.nil? or @old_position.kind_of? INTEGER
- fail 'Invalid (New) Position Type' unless @new_position.nil? or @new_position.kind_of? INTEGER
+ fail 'Invalid (Old) Position Type' unless @old_position.nil? or @old_position.kind_of? Integer
+ fail 'Invalid (New) Position Type' unless @new_position.nil? or @new_position.kind_of? Integer
end
+ sig { returns(ArrayT) }
def to_a
[
@action,
@@ -142,12 +192,26 @@ class Diff::LCS::ContextChange < Diff::LCS::Change
alias to_ary to_a
+ sig { params(action: String).returns(Diff::LCS::Change) }
+ def to_change(action)
+ case action
+ when '-'
+ Diff::LCS::Change.new(action, old_position, old_element)
+ when '+'
+ Diff::LCS::Change.new(action, new_position, new_element)
+ else
+ fail 'Invalid action for creating a change'
+ end
+ end
+
+ sig { params(arr: ArrayT).returns(ChangeT) }
def self.from_a(arr)
Diff::LCS::Change.from_a(arr)
end
# Simplifies a context change for use in some diff callbacks. '<' actions
# are converted to '-' and '>' actions are converted to '+'.
+ sig { returns(T.any(Diff::LCS::Change, Diff::LCS::ContextChange)) }
def simplify
args =
case action
@@ -164,24 +228,33 @@ class Diff::LCS::ContextChange < Diff::LCS::Change
# Simplifies a context change for use in some diff callbacks. '<' actions
# are converted to '-' and '>' actions are converted to '+'.
+ sig {
+ params(event: Diff::LCS::ContextChange).returns(T.any(
+ Diff::LCS::Change,
+ Diff::LCS::ContextChange
+ ))
+ }
def self.simplify(event)
event.simplify
end
+ sig { params(other: ChangeT).returns(T::Boolean) }
def ==(other)
- (self.class == other.class) and
- (@action == other.action) and
- (@old_position == other.old_position) and
- (@new_position == other.new_position) and
- (@old_element == other.old_element) and
- (@new_element == other.new_element)
+ return false unless other.kind_of?(Diff::LCS::ContextChange)
+
+ @action == other.action &&
+ @old_position == other.old_position &&
+ @new_position == other.new_position &&
+ @old_element == other.old_element &&
+ @new_element == other.new_element
end
+ sig { params(other: Diff::LCS::ContextChange).returns(Integer) }
def <=>(other)
r = @action <=> other.action
- r = @old_position <=> other.old_position if r.zero?
- r = @new_position <=> other.new_position if r.zero?
- r = @old_element <=> other.old_element if r.zero?
+ r = @old_position <=> other.old_position if T.must(r).zero?
+ r = @new_position <=> other.new_position if T.must(r).zero?
+ r = @old_element <=> other.old_element if T.must(r).zero?
r = @new_element <=> other.new_element if r.zero?
r
end