|
| 1 | +.. default-domain:: js |
| 2 | +.. highlight:: javascript |
| 3 | + |
| 4 | +====== |
| 5 | +samsam |
| 6 | +====== |
| 7 | + |
| 8 | + Same same, but different |
| 9 | + |
| 10 | +.. raw:: html |
| 11 | + |
| 12 | + <a href="http://travis-ci.org/busterjs/samsam" class="travis"> |
| 13 | + <img src="https://secure.travis-ci.org/busterjs/samsam.png"> |
| 14 | + </a> |
| 15 | + |
| 16 | +``samsam`` is a collection of predicate and comparison functions useful for |
| 17 | +identifiying the type of values and to compare values with varying degrees of |
| 18 | +strictness. |
| 19 | + |
| 20 | +``samsam`` is a general-purpose library with no dependencies. It works in |
| 21 | +browsers (including old and rowdy ones, like IE6) and Node. It will define |
| 22 | +itself as an AMD module if you want it to (i.e. if there's a ``define`` |
| 23 | +function available). |
| 24 | + |
| 25 | +``samsam`` was originally extracted from the |
| 26 | +`referee <http://github.com/busterjs/referee/>`_ assertion library, which |
| 27 | +ships with the Buster.JS testing framework. |
| 28 | + |
| 29 | +Predicate functions |
| 30 | +=================== |
| 31 | + |
| 32 | +``isArguments(object)`` |
| 33 | +----------------------- |
| 34 | + |
| 35 | +Returns ``true`` if ``object`` is an ``arguments`` object, ``false`` otherwise. |
| 36 | + |
| 37 | +``isElement(object)`` |
| 38 | +--------------------- |
| 39 | + |
| 40 | +Returns ``true`` if ``object`` is a DOM element node |
| 41 | + |
| 42 | +``isDate(object)`` |
| 43 | +------------------ |
| 44 | + |
| 45 | +Returns true if the object is a ``Date``, or *date-like*. Duck typing of date |
| 46 | +objects work by checking that the object has a ``getTime`` function whose return |
| 47 | +value equals the return value from the object's ``valueOf``. |
| 48 | + |
| 49 | +Comparison functions |
| 50 | +==================== |
| 51 | + |
| 52 | +``identical(x, y)`` |
| 53 | +------------------- |
| 54 | + |
| 55 | +Strict equality check according to `EcmaScript Harmony's ``egal``. |
| 56 | + |
| 57 | +**From the Harmony wiki:** |
| 58 | + |
| 59 | + An egal function simply makes available the internal ``SameValue`` function |
| 60 | + from section 9.12 of the ES5 spec. If two values are egal, then they are not |
| 61 | + observably distinguishable. |
| 62 | + |
| 63 | +``identical`` returns ``true`` when ``===`` is ``true``, except for ``-0`` and |
| 64 | +``+0``, where it returns ``false``. Additionally, it returns ``true`` when |
| 65 | +``NaN`` is compared to itself. |
| 66 | + |
| 67 | +``deepEqual(obj1, obj2)`` |
| 68 | +------------------------- |
| 69 | + |
| 70 | +Deep equal comparison. Two values are "deep equal" if: |
| 71 | + |
| 72 | + - They are identical |
| 73 | + - They are both date objects representing the same time |
| 74 | + - They are both primitives and ``a == b`` |
| 75 | + - They are both arrays containing elements that are all deepEqual |
| 76 | + - They are objects with the same set of properties, and each property |
| 77 | + in ``obj1`` is deepEqual to the corresponding property in ``obj2`` |
| 78 | + |
| 79 | +``match(object, matcher)`` |
| 80 | +-------------------------- |
| 81 | + |
| 82 | +Partial equality check. Compares ``object`` with matcher according a wide set of |
| 83 | +rules: |
| 84 | + |
| 85 | +**String matcher** |
| 86 | + |
| 87 | +In its simplest form, ``match`` performs a case insensitive substring match. |
| 88 | +When the matcher is a string, ``object`` is converted to a string, and the |
| 89 | +function returns ``true`` if the matcher is a case-insensitive substring of |
| 90 | +``object`` as a string. |
| 91 | + |
| 92 | +:: |
| 93 | + |
| 94 | + samsam.match("Give me something", "Give"); //true |
| 95 | + samsam.match("Give me something", "sumptn"); // false |
| 96 | + samsam.match({ toString: function () { return "yeah"; } }, "Yeah!"); // true |
| 97 | + |
| 98 | +The last example is not symmetric. When the matcher is a string, the ``object`` |
| 99 | +is coerced to a string - in this case using ``toString``. Changing the order of |
| 100 | +the arguments would cause the matcher to be an object, in which case different |
| 101 | +rules apply (see below). |
| 102 | + |
| 103 | +**Boolean matcher** |
| 104 | + |
| 105 | +Performs a strict (i.e. ``===``) match with the object. So, only ``true`` |
| 106 | +matches ``true``, and only ``false`` matches ``false``. |
| 107 | + |
| 108 | +**Regular expression matcher** |
| 109 | + |
| 110 | +When the matcher is a regular expression, the function will pass if |
| 111 | +``object.test(matcher)`` is ``true``. ``match`` is written in a generic way, so |
| 112 | +any object with a ``test`` method will be used as a matcher this way. |
| 113 | + |
| 114 | +:: |
| 115 | + |
| 116 | + samsam.match("Give me something", /^[a-z\s]$/i); // true |
| 117 | + samsam.match("Give me something", /[0-9]/); // false |
| 118 | + samsam.match({ toString: function () { return "yeah!"; } }, /yeah/); // true |
| 119 | + samsam.match(234, /[a-z]/); // false |
| 120 | + |
| 121 | +**Number matcher** |
| 122 | + |
| 123 | +When the matcher is a number, the assertion will pass if ``object == matcher``. |
| 124 | + |
| 125 | +:: |
| 126 | + |
| 127 | + samsam.match("123", 123); // true |
| 128 | + samsam.match("Give me something", 425); // false |
| 129 | + samsam.match({ toString: function () { return "42"; } }, 42); // true |
| 130 | + samsam.match(234, 1234); // false |
| 131 | + |
| 132 | +**Function matcher** |
| 133 | + |
| 134 | +When the matcher is a function, it is called with ``object`` as its only |
| 135 | +argument. ``match`` returns ``true`` if the function returns ``true``. A strict |
| 136 | +match is performed against the return value, so a boolean ``true`` is required, |
| 137 | +truthy is not enough. |
| 138 | + |
| 139 | +:: |
| 140 | + |
| 141 | + // true |
| 142 | + samsam.match("123", function (exp) { |
| 143 | + return exp == "123"; |
| 144 | + }); |
| 145 | + |
| 146 | + // false |
| 147 | + samsam.match("Give me something", function () { |
| 148 | + return "ok"; |
| 149 | + }); |
| 150 | + |
| 151 | + // true |
| 152 | + samsam.match({ |
| 153 | + toString: function () { |
| 154 | + return "42"; |
| 155 | + } |
| 156 | + }, function () { return true; }); |
| 157 | + |
| 158 | + // false |
| 159 | + samsam.match(234, function () {}); |
| 160 | + |
| 161 | +**Object matcher** |
| 162 | + |
| 163 | +As mentioned above, if an object matcher defines a ``test`` method, ``match`` |
| 164 | +will return ``true`` if ``matcher.test(object)`` returns truthy. |
| 165 | + |
| 166 | +If the matcher does not have a test method, a recursive match is performed. If |
| 167 | +all properties of ``matcher`` matches corresponding properties in ``object``, |
| 168 | +``match`` returns ``true``. Note that the object matcher does not care if the |
| 169 | +number of properties in the two objects are the same - only if all properties in |
| 170 | +the matcher recursively matches ones in ``object``. |
| 171 | + |
| 172 | +:: |
| 173 | + |
| 174 | + // true |
| 175 | + samsam.match("123", { |
| 176 | + test: function (arg) { |
| 177 | + return arg == 123; |
| 178 | + } |
| 179 | + }); |
| 180 | + |
| 181 | + // false |
| 182 | + samsam.match({}, { prop: 42 }); |
| 183 | + |
| 184 | + // true |
| 185 | + samsam.match({ |
| 186 | + name: "Chris", |
| 187 | + profession: "Programmer" |
| 188 | + }, { |
| 189 | + name: "Chris" |
| 190 | + }); |
| 191 | + |
| 192 | + // false |
| 193 | + samsam.match(234, { name: "Chris" }); |
| 194 | + |
| 195 | +**DOM elements** |
| 196 | + |
| 197 | +``match`` can be very helpful when comparing DOM elements, because it allows |
| 198 | +you to compare several properties with one call: |
| 199 | + |
| 200 | +:: |
| 201 | + |
| 202 | + var el = document.getElementById("myEl"); |
| 203 | + |
| 204 | + samsam.match(el, { |
| 205 | + tagName: "h2", |
| 206 | + className: "item", |
| 207 | + innerHTML: "Howdy" |
| 208 | + }); |
0 commit comments