Fix ^:displace and ^:replace handling in meta-merge
An object with the metadata flag `:displace` set signals that, if a merge conflict appears, this object is to be discarded. Likewise, `^:replace` signals that this object should be kept in a merge conflict. However, previous functionality only tested if the right element had the `:replace` flag, or if the left element had the `:displace` flag. This commit resolves this by checking whether the left element has a `:replace` flag and the right element has a `:displace` flag, and handles accordingly to the semantics explained in the previous paragraph. Whenever two elements where both has the `:displace` flag is merged, the leftmost is picked, and their metadata is merged. Likewise for the `:replace` flag. The elements will not lose their `:displace` and `:replace` flags, as they have not really been preferred over another element. The `nil?` tests have been placed at the top to reflect that nil is the lack of a value, not a value itself. As such, elements will not be "preferred" or "discarded" over nil/nothing.
This commit is contained in:
parent
9bb4a5acb3
commit
27fe39d618
1 changed files with 33 additions and 7 deletions
|
@ -232,23 +232,49 @@
|
||||||
:offline {:offline? true}
|
:offline {:offline? true}
|
||||||
:debug {:debug true}}))
|
:debug {:debug true}}))
|
||||||
|
|
||||||
|
(defn- displace?
|
||||||
|
"Returns true if the object is marked as displaceable"
|
||||||
|
[obj]
|
||||||
|
(-> obj meta :displace))
|
||||||
|
|
||||||
|
(defn- replace?
|
||||||
|
"Returns true if the object is marked as replaceable"
|
||||||
|
[obj]
|
||||||
|
(-> obj meta :replace))
|
||||||
|
|
||||||
(defn- meta-merge
|
(defn- meta-merge
|
||||||
"Recursively merge values based on the information in their metadata."
|
"Recursively merge values based on the information in their metadata."
|
||||||
[left right]
|
[left right]
|
||||||
(cond (or (-> left meta :displace)
|
(cond (nil? left) right
|
||||||
(-> right meta :replace))
|
(nil? right) left
|
||||||
|
|
||||||
|
(and (displace? left) ;; Pick the rightmost
|
||||||
|
(displace? right)) ;; if both are marked as displaceable
|
||||||
(with-meta right
|
(with-meta right
|
||||||
(merge (-> left meta (dissoc :displace))
|
(merge (meta left) (meta right)))
|
||||||
(-> right meta (dissoc :replace))))
|
|
||||||
|
(and (replace? left) ;; Pick the rightmost
|
||||||
|
(replace? right)) ;; if both are marked as replaceable
|
||||||
|
(with-meta right
|
||||||
|
(merge (meta left) (meta right)))
|
||||||
|
|
||||||
|
(or (displace? left)
|
||||||
|
(replace? right))
|
||||||
|
(with-meta right
|
||||||
|
(merge (-> right meta (dissoc :replace))
|
||||||
|
(-> left meta (dissoc :displace))))
|
||||||
|
|
||||||
|
(or (replace? left)
|
||||||
|
(displace? right))
|
||||||
|
(with-meta left
|
||||||
|
(merge (-> left meta (dissoc :replace))
|
||||||
|
(-> right meta (dissoc :displace))))
|
||||||
|
|
||||||
(-> left meta :reduce)
|
(-> left meta :reduce)
|
||||||
(-> left meta :reduce
|
(-> left meta :reduce
|
||||||
(reduce left right)
|
(reduce left right)
|
||||||
(with-meta (meta left)))
|
(with-meta (meta left)))
|
||||||
|
|
||||||
(nil? left) right
|
|
||||||
(nil? right) left
|
|
||||||
|
|
||||||
(and (map? left) (map? right))
|
(and (map? left) (map? right))
|
||||||
(merge-with meta-merge left right)
|
(merge-with meta-merge left right)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue