diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 82796dc41..74483f2d2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,11 @@ require 'dtext' module ApplicationHelper + def diff_list_html(new, old, latest) + diff = SetDiff.new(new, old, latest) + render "diff_list", diff: diff + end + def wordbreakify(string) lines = string.scan(/.{1,10}/) wordbreaked_string = lines.map{|str| h(str)}.join("") diff --git a/app/helpers/artist_versions_helper.rb b/app/helpers/artist_versions_helper.rb index 927e02f4a..1f55b471e 100644 --- a/app/helpers/artist_versions_helper.rb +++ b/app/helpers/artist_versions_helper.rb @@ -1,42 +1,17 @@ module ArtistVersionsHelper def artist_version_other_names_diff(artist_version) - diff = artist_version.other_names_diff(artist_version.previous) - html = '' + new_names = artist_version.other_names + old_names = artist_version.previous.try(:other_names) + latest_names = artist_version.artist.other_names - diff[:added_names].each do |name| - prefix = diff[:obsolete_added_names].include?(name) ? '' : '' - html << prefix + h(name) + '' - end - diff[:removed_names].each do |name| - prefix = diff[:obsolete_removed_names].include?(name) ? '' : '' - html << prefix + h(name) + '' - end - diff[:unchanged_names].each do |name| - html << '' + h(name) + '' - html << " " - end - - html << "" - return html.html_safe + diff_list_html(new_names, old_names, latest_names) end def artist_version_urls_diff(artist_version) - diff = artist_version.urls_diff(artist_version.previous) - html = '" - html.html_safe + diff_list_html(new_urls, old_urls, latest_urls) end end diff --git a/app/javascript/src/styles/common/diffs.scss b/app/javascript/src/styles/common/diffs.scss index 87f956303..3b40b21a6 100644 --- a/app/javascript/src/styles/common/diffs.scss +++ b/app/javascript/src/styles/common/diffs.scss @@ -1,21 +1,21 @@ .diff-list { - ins, ins a { + .added, .added a { color: green; text-decoration: none; margin-right: 0.5em; } - ins.obsolete, ins.obsolete a { + .added.obsolete, .added.obsolete a { color: darkGreen; } - del, del a { + .removed, .removed a { color: red; text-decoration: line-through; margin-right: 0.5em; } - del.obsolete, del.obsolete a { + .removed.obsolete, .removed.obsolete a { color: darkRed; } } diff --git a/app/logical/set_diff.rb b/app/logical/set_diff.rb new file mode 100644 index 000000000..52558ef99 --- /dev/null +++ b/app/logical/set_diff.rb @@ -0,0 +1,35 @@ +class SetDiff + attr_reader :added, :removed, :obsolete_added, :obsolete_removed, :changed, :unchanged + + def initialize(new, old, latest) + new, old, latest = new.to_a, old.to_a, latest.to_a + + @added, @removed, @changed = changes(new, old) + @unchanged = new & old + @obsolete_added = added - latest + @obsolete_removed = removed & latest + end + + def changes(new, old) + added = new - old + removed = old - new + changed = [] + + removed.each do |removal| + if addition = find_similar(removal, added) + changed << [removal, addition] + added -= [addition] + removed -= [removal] + end + end + + [added, removed, changed] + end + + def find_similar(string, candidates, max_dissimilarity: 0.75) + distance = ->(other) { DidYouMean::Levenshtein.distance(string, other) } + max_distance = string.size * max_dissimilarity + + candidates.select { |candidate| distance[candidate] <= max_distance }.sort_by(&distance).first + end +end diff --git a/app/models/artist_version.rb b/app/models/artist_version.rb index 2d116114a..c1e84e9ab 100644 --- a/app/models/artist_version.rb +++ b/app/models/artist_version.rb @@ -50,40 +50,6 @@ class ArtistVersion < ApplicationRecord extend SearchMethods - def urls_diff(version) - latest_urls = artist.url_array || [] - new_urls = urls - old_urls = version.present? ? version.urls : [] - - added_urls = new_urls - old_urls - removed_urls = old_urls - new_urls - - return { - :added_urls => added_urls, - :removed_urls => removed_urls, - :obsolete_added_urls => added_urls - latest_urls, - :obsolete_removed_urls => removed_urls & latest_urls, - :unchanged_urls => new_urls & old_urls, - } - end - - def other_names_diff(version) - latest_names = artist.other_names || [] - new_names = other_names - old_names = version.present? ? version.other_names : [] - - added_names = new_names - old_names - removed_names = old_names - new_names - - return { - :added_names => added_names, - :removed_names => removed_names, - :obsolete_added_names => added_names - latest_names, - :obsolete_removed_names => removed_names & latest_names, - :unchanged_names => new_names & old_names, - } - end - def previous ArtistVersion.where("artist_id = ? and created_at < ?", artist_id, created_at).order("created_at desc").first end diff --git a/app/views/application/_diff_list.html.erb b/app/views/application/_diff_list.html.erb new file mode 100644 index 000000000..de5ebda10 --- /dev/null +++ b/app/views/application/_diff_list.html.erb @@ -0,0 +1,21 @@ +<%# diff %> + +