Andreas Launila wrote: > Another variation would be to use a combination of constrain and RSpec's > should/should_not. > > constrain (x + y).must == z > constrain (x + y).must_not == z > > It might chop up the constraint a bit, but it reads well. One could > possibly also drop the constraint part. It would be nicer with a > negative form of constrain though (or some other fitting word) since it > would make it easier to be consistent. As an example there's a domain > constraint which basically says that x must be in a given range. > Negating the constraint is possible and might be written as follows. > > constrain x.in(1..17) > constrain x.not_in(1..17) > > The above takes a different form than the linear constraints. To make it > consistent with the mixed variation of linear constraint syntax one > could rewrite it as. > > constrain (1..17).must(include(x)) > constrain (1..17).must_not(include(x)) > Not necessarily. It could also be written as constrain x.must(be_in(1..17)) constrain x.must_not(be_in(1..17)) Which is both consistent and reads well (possibly apart from the parenthesis). Another way of making it clear that we're specifying constraints could be to place them all in a block. E.g. something like the following. in_a_solution do (x + y).must == z x.must > z y.must_not be_in(1..4) distinct x,y,z end Possibly also sending the variables through the method with the block (which would clearly declare which variables that constitute a solution). in_a_solution_with(x,y,z) do |x,y,z| (x + y).must == z x.must > z y.must_not be_in(1..4) distinct x,y,z end -- Andreas Launila