Browse files

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.
  • Loading branch information...
hypirion committed Dec 28, 2012
1 parent 9bb4a5a commit 27fe39d618660da25a929169347edc2d5af4b5c7
Showing with 33 additions and 7 deletions.
  1. +33 −7 leiningen-core/src/leiningen/core/project.clj
@@ -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 (meta left) (meta right)))
+ (and (replace? left) ;; Pick the rightmost
+ (replace? right)) ;; if both are marked as replaceable
(with-meta right
- (merge (-> left meta (dissoc :displace))
- (-> right meta (dissoc :replace))))
+ (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)

0 comments on commit 27fe39d

Please sign in to comment.