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}
|
||||
: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
|
||||
"Recursively merge values based on the information in their metadata."
|
||||
[left right]
|
||||
(cond (or (-> left meta :displace)
|
||||
(-> right meta :replace))
|
||||
(cond (nil? left) right
|
||||
(nil? right) left
|
||||
|
||||
(and (displace? left) ;; Pick the rightmost
|
||||
(displace? right)) ;; if both are marked as displaceable
|
||||
(with-meta right
|
||||
(merge (-> left meta (dissoc :displace))
|
||||
(-> right meta (dissoc :replace))))
|
||||
(merge (meta left) (meta right)))
|
||||
|
||||
(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
|
||||
(reduce left right)
|
||||
(with-meta (meta left)))
|
||||
|
||||
(nil? left) right
|
||||
(nil? right) left
|
||||
|
||||
(and (map? left) (map? right))
|
||||
(merge-with meta-merge left right)
|
||||
|
||||
|
|
Loading…
Reference in a new issue