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.
889 890 891 892 893 894 |
# File 'lib/goat.rb', line 889 def initialize(old, new, id) @old = old @new = new @id = id @diffs = [] end |
Class Method Details
.diff(old, new, id) ⇒ Object
885 886 887 |
# File 'lib/goat.rb', line 885 def self.diff(old, new, id) self.new(old, new, id).diff end |
Instance Method Details
#added(new, par, pos = nil) ⇒ Object
934 |
# File 'lib/goat.rb', line 934 def added(new, par, pos=nil); [:add, new, par, pos]; end |
#array_desc(old, new, par) ⇒ Object
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
# File 'lib/goat.rb', line 966 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
941 |
# File 'lib/goat.rb', line 941 def attrs(node); node[1] if node[1].is_a?(Hash); end |
#body(node) ⇒ Object
942 |
# File 'lib/goat.rb', line 942 def body(node); node[1].is_a?(Hash) ? node[2..-1] : node[1..-1]; end |
#compare_attrs(a, b) ⇒ Object
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
# File 'lib/goat.rb', line 1003 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
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
# File 'lib/goat.rb', line 1032 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
896 897 898 |
# File 'lib/goat.rb', line 896 def diff nested_application(minimized_changes(desc(@old, @new, @id))) end |
#dom_node?(node) ⇒ Boolean
937 938 939 |
# File 'lib/goat.rb', line 937 def dom_node?(node) node.is_a?(Array) && node.first.is_a?(Symbol) end |
#domid(node) ⇒ Object
943 |
# File 'lib/goat.rb', line 943 def domid(node); attrs(node) ? attrs(node)[:id] : nil; end |
#is_replacement?(d1, d2) ⇒ Boolean
956 957 958 959 960 |
# File 'lib/goat.rb', line 956 def is_replacement?(d1, d2) d1 && d2 && ( (d1.action == '+' && d2.action == '-') || (d1.action == '-' && d2.action == '+')) end |
#localized_change(dold, dnew, par, changes) ⇒ Object
945 946 947 948 949 950 951 952 953 954 |
# File 'lib/goat.rb', line 945 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
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 |
# File 'lib/goat.rb', line 916 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
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
# File 'lib/goat.rb', line 900 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
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
# File 'lib/goat.rb', line 1014 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
962 963 964 |
# File 'lib/goat.rb', line 962 def old_and_new(d1, d2) d1.action == '+' ? [d2, d1] : [d1, d2] end |
#removed(old, par, pos = nil) ⇒ Object
935 |
# File 'lib/goat.rb', line 935 def removed(old, par, pos=nil); [:rem, old, par, pos]; end |
#tag(node) ⇒ Object
940 |
# File 'lib/goat.rb', line 940 def tag(node); node[0]; end |