Skip to content
Browse files

You can use checkers on the optional args

  • Loading branch information...
1 parent 89030e8 commit 5f8bc435a3bde99dfa29d2cb4a2827c326aa6a45 @marick committed Mar 20, 2013
View
29 src/midje/parsing/3_from_lexical_maps/from_fake_maps.clj
@@ -16,20 +16,25 @@
(fn [actual] (extended-= actual (exactly expected)))
(fn [actual] (extended-= actual expected))))
-(defn mkfn:arg-matchers-with-arity
+(defn mkfn:arglist-matcher-fixed-arity
"Generates a function that returns true if all the matchers return true for the actual args it's passed."
- [matchers]
+ [& arg-descriptions]
(fn [actual-args]
- (let [arg-matchers (map mkfn:arg-matcher matchers)]
- (and (= (count actual-args) (count arg-matchers))
- (extended-list-= actual-args arg-matchers)))))
-
-(defn mkfn:arg-matchers-without-arity
- "Generates a function that returns true if all the matchers return true but it ignores arity matching."
- [matchers]
- (fn [actual-args]
- (let [arg-matchers (map mkfn:arg-matcher matchers)]
- (extended-list-= actual-args arg-matchers))))
+ (extended-list-= actual-args
+ (map mkfn:arg-matcher arg-descriptions))))
+
+(defn mkfn:arglist-matcher-allowing-optional-args
+ "Generates a function that attempts to match required and optional args."
+ [& arg-descriptions]
+ (let [required-count (- (count arg-descriptions) 2)
+ required-arglist-descriptions (take required-count arg-descriptions)
+ rest-arg-description (last arg-descriptions)
+ required-arg-matchers (map mkfn:arg-matcher required-arglist-descriptions)
+ rest-arg-matcher (mkfn:arg-matcher rest-arg-description)]
+ (fn [actual-args]
+ (let [[required-actual rest-actual] (split-at required-count actual-args)]
+ (and (extended-list-= required-actual required-arg-matchers)
+ (extended-= rest-actual rest-arg-matcher))))))
(defmulti mkfn:result-supplier (fn [arrow & _] arrow))
View
17 src/midje/parsing/lexical_maps.clj
@@ -64,16 +64,11 @@
;; A fake map describes all or part of a temporary rebinding of a var with a function that
;; captures invocations and also returns canned values.
-(defn- arity-matcher? [arg]
- (boolean (= arg (symbol "&"))))
-
-(defn- some-ignore-arity-matcher? [args]
- (boolean (some arity-matcher? args)))
-
-(defn- arg-matchers-form [arg-matchers]
- (if (some-ignore-arity-matcher? arg-matchers)
- `(from-fake-maps/mkfn:arg-matchers-without-arity ~(vec (remove arity-matcher? arg-matchers)))
- `(from-fake-maps/mkfn:arg-matchers-with-arity ~(vec arg-matchers))))
+(defn- choose-mkfn-for-arglist-matcher [arg-matchers]
+ (letfn [(allows-optional-args? [args] (any? #(= % (symbol "&")) args))]
@josephwilk
josephwilk added a note Mar 21, 2013

Can I ask why letfn is preferred over small functions?

Curious for the reason as in my head small functions are more readable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ (if (allows-optional-args? arg-matchers)
+ `(from-fake-maps/mkfn:arglist-matcher-allowing-optional-args ~@arg-matchers)
+ `(from-fake-maps/mkfn:arglist-matcher-fixed-arity ~@arg-matchers))))
(defn fake [call-form fnref args arrow result overrides]
(let [source-details `{:call-form '~call-form
@@ -87,7 +82,7 @@
:var ~(fnref/as-var-form fnref)
:value-at-time-of-faking (if (bound? ~(fnref/as-var-form fnref))
~(fnref/as-form-to-fetch-var-value fnref))
- :arg-matchers ~(arg-matchers-form args)
+ :arg-matchers ~(choose-mkfn-for-arglist-matcher args)
:result-supplier (from-fake-maps/mkfn:result-supplier ~arrow ~result)
:times :default ; Default allows for a more attractive error in the most common case.
View
8 test/as_documentation/prerequisites__the_basics.clj
@@ -233,13 +233,11 @@
(provided
(letter desired-letter & anything) => ..letter-result..)))
-
-
-
-(future-fact "You can even apply a checker to the &rest argument"
+(fact "You can even apply a checker to the &rest argument"
(find-letter) => ..letter-result..
(provided
- (letter & (as-checker (fn [actual] (prn actual) true))) => ..letter-result..))
+ (letter & (just "this" "doesn't" "match")) => ..bogus-result.. :times 0
+ (letter & (just "x" "y" "z")) => ..letter-result..))
View
24 test/midje/parsing/3_from_lexical_maps/t_from_fake_maps.clj
@@ -10,8 +10,7 @@
(tabular
(facts "the arg matcher maker handles functions specially"
- ((mkfn:arg-matchers-with-arity [?expected]) [?actual]) => ?result
- ((mkfn:arg-matchers-without-arity [?expected]) [?actual]) => ?result)
+ ((apply mkfn:arglist-matcher-fixed-arity [?expected]) [?actual]) => ?result)
?expected ?actual ?result
1 1 TRUTHY
1 odd? falsey
@@ -34,12 +33,25 @@ anything odd? TRUTHY
odd? odd? TRUTHY
odd? 3 falsey)
-(fact "false if there is an arity mismatch"
- ((mkfn:arg-matchers-with-arity [anything]) [1 2 3]) => falsey)
+(fact "sometimes an arglist must be matched exactly"
+ ((mkfn:arglist-matcher-fixed-arity 1 2) [1 ]) => falsey
+ ((mkfn:arglist-matcher-fixed-arity 1 2) [1 2 ]) => truthy
+ ((mkfn:arglist-matcher-fixed-arity 1 2) [1 2 3]) => falsey)
+
+(fact "an arglist can allow rest args"
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & anything) [1 ]) => falsey
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & anything) [1 2 ]) => truthy
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & anything) [1 2 3]) => truthy
-(fact "ignoring arity mismatches"
- ((mkfn:arg-matchers-without-arity [anything]) [1 2 3]) => TRUTHY)
+ (fact "the required args are treated the same as the fixed-arity case"
+ ( (mkfn:arglist-matcher-allowing-optional-args 1 even? & anything) [1 2 3]) => falsey
+ ( (mkfn:arglist-matcher-allowing-optional-args 1 (as-checker even?) & anything) [1 2 3]) => truthy)
+ (fact "the argument after the & is treated as a checker"
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & (as-checker empty?)) [1 2]) => truthy
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & empty? ) [1 2]) => falsey
+ ((mkfn:arglist-matcher-allowing-optional-args 1 2 & (as-checker empty?)) [1 2 3]) => falsey))
+
(facts "about result suppliers used"
"returns identity for =>"
(let [arrow "=>"]

0 comments on commit 5f8bc43

Please sign in to comment.
Something went wrong with that request. Please try again.