Class: Goat::DOMDiff
Class Method Summary collapse
Instance Method Summary collapse
- #added(new, par, pos = nil) ⇒ Object
- #array_desc(old, new, par) ⇒ Object
- #attrs(node) ⇒ Object
- #body(node) ⇒ Object
- #compare_attrs(a, b) ⇒ Object
- #desc(old, new, par) ⇒ Object
- #diff ⇒ Object
- #dom_node?(node) ⇒ Boolean
- #domid(node) ⇒ Object
-
#initialize(old, new, id) ⇒ DOMDiff
constructor
A new instance of DOMDiff.
- #is_replacement?(d1, d2) ⇒ Boolean
- #localized_change(dold, dnew, par, changes) ⇒ Object
- #minimized_changes(ch) ⇒ Object
- #nested_application(ch) ⇒ Object
- #node_desc(old, new, par) ⇒ Object
- #old_and_new(d1, d2) ⇒ Object
- #removed(old, par, pos = nil) ⇒ Object
- #tag(node) ⇒ Object
Constructor Details
#initialize(old, new, id) ⇒ DOMDiff
Returns a new instance of DOMDiff.
872 873 874 875 876 877 |
# File 'lib/goat.rb', line 872 def initialize(old, new, id) @old = old @new = new @id = id @diffs = [] end |
Class Method Details
.diff(old, new, id) ⇒ Object
868 869 870 |
# File 'lib/goat.rb', line 868 def self.diff(old, new, id) self.new(old, new, id).diff end |
Instance Method Details
#added(new, par, pos = nil) ⇒ Object
917 |
# File 'lib/goat.rb', line 917 def added(new, par, pos=nil); [:add, new, par, pos]; end |
#array_desc(old, new, par) ⇒ Object
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
# File 'lib/goat.rb', line 949 def array_desc(old, new, par) #$stderr.puts "array_desc #{old.inspect} #{new.inspect} #{par.inspect}" chgs = Diff::LCS.diff(old, new).map do |diff| #$stderr.puts "diff: #{diff.inspect}" if is_replacement?(diff[0], diff[1]) dold, dnew = old_and_new(diff[0], diff[1]) old = dold.element new = dnew.element if dom_node?(old) && dom_node?(new) && tag(old) == tag(new) && compare_attrs(old, new) localized_change(dold, dnew, par, desc(body(old), body(new), domid(old))) elsif old.is_a?(Array) && new.is_a?(Array) #&& old.all?{|x| !dom_node?(x)} && new.all?{|x| !dom_node?(x)} array_desc(old, new, par) else [added(new, par, diff[1].position), removed(old, par, diff[0].position)] end else if diff.size == 1 diff = diff[0] if diff.action == '+' [added(diff.element, par, diff.position)] elsif diff.action == '-' [removed(diff.element, par, diff.position)] else raise "Don't understand diff in a bad way" end else $stderr.puts "Don't understand diff" #$stderr.puts "Diff failed" raise JustRerenderError end end end chgs.flatten(1) end |
#attrs(node) ⇒ Object
924 |
# File 'lib/goat.rb', line 924 def attrs(node); node[1] if node[1].is_a?(Hash); end |
#body(node) ⇒ Object
925 |
# File 'lib/goat.rb', line 925 def body(node); node[1].is_a?(Hash) ? node[2..-1] : node[1..-1]; end |
#compare_attrs(a, b) ⇒ Object
986 987 988 989 990 991 992 993 994 995 |
# File 'lib/goat.rb', line 986 def compare_attrs(a, b) if a.is_a?(Hash) && b.is_a?(Hash) a_, b_ = a.clone, b.clone a.select{|k,v| a_.delete(k) if v =~ /^dom_/} b.select{|k,v| b_.delete(k) if v =~ /^dom_/} a_ == b_ else false end end |
#desc(old, new, par) ⇒ Object
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
# File 'lib/goat.rb', line 1015 def desc(old, new, par) #$stderr.puts "desc #{old.inspect} #{new.inspect} #{par.inspect}" #$stderr.puts "desc #{self.class.name} #{par.inspect}" if old.class != new.class [added(new, par), removed(old, par)] elsif old.is_a?(Array) dom_node?(old) ? node_desc(old, new, domid(old)) : array_desc(old, new, par) elsif old.is_a?(String) if old != new [added(new, par), removed(old, par)] end else raise TypeError.new("Unknown object in the DOM: #{old.class} #{new.class}") end end |
#diff ⇒ Object
879 880 881 |
# File 'lib/goat.rb', line 879 def diff nested_application(minimized_changes(desc(@old, @new, @id))) end |
#dom_node?(node) ⇒ Boolean
920 921 922 |
# File 'lib/goat.rb', line 920 def dom_node?(node) node.is_a?(Array) && node.first.is_a?(Symbol) end |
#domid(node) ⇒ Object
926 |
# File 'lib/goat.rb', line 926 def domid(node); attrs(node) ? attrs(node)[:id] : nil; end |
#is_replacement?(d1, d2) ⇒ Boolean
939 940 941 942 943 |
# File 'lib/goat.rb', line 939 def is_replacement?(d1, d2) d1 && d2 && ( (d1.action == '+' && d2.action == '-') || (d1.action == '-' && d2.action == '+')) end |
#localized_change(dold, dnew, par, changes) ⇒ Object
928 929 930 931 932 933 934 935 936 937 |
# File 'lib/goat.rb', line 928 def localized_change(dold, dnew, par, changes) old = dold.element new = dnew.element #$stderr.puts "changes: #{changes.inspect} / #{old.inspect} / #{par.inspect}" if changes.all?{|ch| ch[2].nil?} && par [added(new, par, dold.position), removed(old, par, dnew.position)] else changes end end |
#minimized_changes(ch) ⇒ Object
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 |
# File 'lib/goat.rb', line 899 def minimized_changes(ch) new = [] merged = Set.new ch.each do |c| if c[0] == :rem if n = ch.detect{|x| x[0] == :add && x[2] == c[2] && x[3] == c[3]} new << [:rep, *n[1..3]] merged << n else new << c end else new << c end end new.reject{|c| merged.include?(c)} end |
#nested_application(ch) ⇒ Object
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
# File 'lib/goat.rb', line 883 def nested_application(ch) applied = Set.new ch.sort_by{|x| x[3]}.each do |c| if (c[0] == :rem || c[0] == :add) && !applied.include?(c) if n = ch.detect{|x| x != c && x[2] == c[2] && x[3] >= c[3]} n[3] += (c[0] == :rem) ? -1 : 1 end end applied << c end ch end |
#node_desc(old, new, par) ⇒ Object
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
# File 'lib/goat.rb', line 997 def node_desc(old, new, par) #$stderr.puts "node_desc #{old.inspect} #{new.inspect} #{par.inspect}" if tag(old) != tag(new) || !compare_attrs(old, new) [removed(old, par), added(new, par)] else # only body changed (maybe) bold = body(old) bnew = body(new) if bold && bnew desc(bold, bnew, domid(old)) elsif bold && !bnew [removed(bold, domid(old))] else [added(bnew, domid(old))] end end end |
#old_and_new(d1, d2) ⇒ Object
945 946 947 |
# File 'lib/goat.rb', line 945 def old_and_new(d1, d2) d1.action == '+' ? [d2, d1] : [d1, d2] end |
#removed(old, par, pos = nil) ⇒ Object
918 |
# File 'lib/goat.rb', line 918 def removed(old, par, pos=nil); [:rem, old, par, pos]; end |
#tag(node) ⇒ Object
923 |
# File 'lib/goat.rb', line 923 def tag(node); node[0]; end |