diff --git a/logic.js b/logic.js
index 6b827df..2ac983a 100644
--- a/logic.js
+++ b/logic.js
@@ -3,7 +3,8 @@
 Using a Universal Module Loader that should be browser, require, and AMD friendly
 http://ricostacruz.com/cheatsheets/umdjs.html
 */
-;(function(root, factory) {
+;
+(function(root, factory) {
   if (typeof define === "function" && define.amd) {
     define(factory);
   } else if (typeof exports === "object") {
@@ -15,7 +16,7 @@ http://ricostacruz.com/cheatsheets/umdjs.html
   "use strict";
   /* globals console:false */
 
-  if ( ! Array.isArray) {
+  if (!Array.isArray) {
     Array.isArray = function(arg) {
       return Object.prototype.toString.call(arg) === "[object Array]";
     };
@@ -28,7 +29,7 @@ http://ricostacruz.com/cheatsheets/umdjs.html
    */
   function arrayUnique(array) {
     var a = [];
-    for (var i=0, l=array.length; i<l; i++) {
+    for (var i = 0, l = array.length; i < l; i++) {
       if (a.indexOf(array[i]) === -1) {
         a.push(array[i]);
       }
@@ -72,17 +73,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html
       return a % b;
     },
     "log": function(a) {
-      console.log(a); return a;
+      console.log(a);
+      return a;
     },
     "in": function(a, b) {
-      if(!b || typeof b.indexOf === "undefined") return false;
+      if (!b || typeof b.indexOf === "undefined") return false;
       return (b.indexOf(a) !== -1);
     },
     "cat": function() {
       return Array.prototype.join.call(arguments, "");
     },
-    "substr":function(source, start, end) {
-      if(end < 0){
+    "substr": function(source, start, end) {
+      if (end < 0) {
         // JavaScript doesn't support negative end, this emulates PHP behavior
         var temp = String(source).substr(start);
         return temp.substr(0, temp.length + end);
@@ -100,9 +102,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html
       });
     },
     "-": function(a, b) {
-      if(b === undefined) {
+      if (b === undefined) {
         return -a;
-      }else{
+      } else {
         return a - b;
       }
     },
@@ -123,17 +125,17 @@ http://ricostacruz.com/cheatsheets/umdjs.html
     "var": function(a, b) {
       var not_found = (b === undefined) ? null : b;
       var data = this;
-      if(typeof a === "undefined" || a==="" || a===null) {
+      if (typeof a === "undefined" || a === "" || a === null) {
         return data;
       }
       var sub_props = String(a).split(".");
-      for(var i = 0; i < sub_props.length; i++) {
-        if(data === null) {
+      for (var i = 0; i < sub_props.length; i++) {
+        if (data === null) {
           return not_found;
         }
         // Descending into data
         data = data[sub_props[i]];
-        if(data === undefined) {
+        if (data === undefined) {
           return not_found;
         }
       }
@@ -150,10 +152,12 @@ http://ricostacruz.com/cheatsheets/umdjs.html
       var missing = [];
       var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;
 
-      for(var i = 0; i < keys.length; i++) {
+      for (var i = 0; i < keys.length; i++) {
         var key = keys[i];
-        var value = jsonLogic.apply({"var": key}, this);
-        if(value === null || value === "") {
+        var value = jsonLogic.apply({
+          "var": key,
+        }, this);
+        if (value === null || value === "") {
           missing.push(key);
         }
       }
@@ -162,11 +166,13 @@ http://ricostacruz.com/cheatsheets/umdjs.html
     },
     "missing_some": function(need_count, options) {
       // missing_some takes two arguments, how many (minimum) items must be present, and an array of keys (just like 'missing') to check for presence.
-      var are_missing = jsonLogic.apply({"missing": options}, this);
+      var are_missing = jsonLogic.apply({
+        "missing": options,
+      }, this);
 
-      if(options.length - are_missing.length >= need_count) {
+      if (options.length - are_missing.length >= need_count) {
         return [];
-      }else{
+      } else {
         return are_missing;
       }
     },
@@ -176,12 +182,25 @@ http://ricostacruz.com/cheatsheets/umdjs.html
 
   };
 
+  // For a better is_logic detection
+  var asymetricOperationsNames = [
+    "if", "?:", "and", "or",
+    "filter", "map", "reduce", "all", "none", "some",
+    "@",
+  ];
+
   jsonLogic.is_logic = function(logic) {
     return (
       typeof logic === "object" && // An object
       logic !== null && // but not null
-      ! Array.isArray(logic) && // and not an array
-      Object.keys(logic).length === 1 // with exactly one key
+      !Array.isArray(logic) && // and not an array
+      Object.keys(logic).length === 1 && // with exactly one key
+
+      (
+        typeof operations[Object.keys(logic)[0]] !== "undefined" ||
+        typeof operations[Object.keys(logic)[0].split(".")[0]] !== "undefined" ||
+        asymetricOperationsNames.indexOf(Object.keys(logic)[0]) !== -1
+      )
     );
   };
 
@@ -191,10 +210,10 @@ http://ricostacruz.com/cheatsheets/umdjs.html
   Spec and rationale here: http://jsonlogic.com/truthy
   */
   jsonLogic.truthy = function(value) {
-    if(Array.isArray(value) && value.length === 0) {
+    if (Array.isArray(value) && value.length === 0) {
       return false;
     }
-    return !! value;
+    return !!value;
   };
 
 
@@ -206,15 +225,16 @@ http://ricostacruz.com/cheatsheets/umdjs.html
     return logic[jsonLogic.get_operator(logic)];
   };
 
-  jsonLogic.apply = function(logic, data) {
+  jsonLogic.apply = function(logic, data, internal) {
     // Does this array contain logic? Only one way to find out.
-    if(Array.isArray(logic)) {
+    if (Array.isArray(logic)) {
       return logic.map(function(l) {
-        return jsonLogic.apply(l, data);
+        return jsonLogic.apply(l, data, true);
       });
     }
     // You've recursed to a primitive, stop!
-    if( ! jsonLogic.is_logic(logic) ) {
+    // If your are called from outside
+    if (!jsonLogic.is_logic(logic)) {
       return logic;
     }
 
@@ -224,15 +244,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html
     var values = logic[op];
     var i;
     var current;
-    var scopedLogic, scopedData, filtered, initial;
+    var scopedLogic;
+    var scopedData;
+    var filtered;
+    var initial;
 
     // easy syntax for unary operators, like {"var" : "x"} instead of strict {"var" : ["x"]}
-    if( ! Array.isArray(values)) {
+    if (!Array.isArray(values)) {
       values = [values];
     }
 
     // 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.
-    if(op === "if" || op == "?:") {
+    if (op === "if" || op == "?:") {
       /* 'if' should be called with a odd number of parameters, 3 or greater
       This works on the pattern:
       if( 0 ){ 1 }else{ 2 };
@@ -246,96 +269,95 @@ http://ricostacruz.com/cheatsheets/umdjs.html
       given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)
       given 0 parameters, return NULL (not great practice, but there was no Else)
       */
-      for(i = 0; i < values.length - 1; i += 2) {
-        if( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) {
-          return jsonLogic.apply(values[i+1], data);
+      for (i = 0; i < values.length - 1; i += 2) {
+        if (jsonLogic.truthy(jsonLogic.apply(values[i], data))) {
+          return jsonLogic.apply(values[i + 1], data);
         }
       }
-      if(values.length === i+1) return jsonLogic.apply(values[i], data);
+      if (values.length === i + 1) return jsonLogic.apply(values[i], data);
       return null;
-    }else if(op === "and") { // Return first falsy, or last
-      for(i=0; i < values.length; i+=1) {
+    } else if (op === "and") { // Return first falsy, or last
+      for (i = 0; i < values.length; i += 1) {
         current = jsonLogic.apply(values[i], data);
-        if( ! jsonLogic.truthy(current)) {
+        if (!jsonLogic.truthy(current)) {
           return current;
         }
       }
       return current; // Last
-    }else if(op === "or") {// Return first truthy, or last
-      for(i=0; i < values.length; i+=1) {
+    } else if (op === "or") { // Return first truthy, or last
+      for (i = 0; i < values.length; i += 1) {
         current = jsonLogic.apply(values[i], data);
-        if( jsonLogic.truthy(current) ) {
+        if (jsonLogic.truthy(current)) {
           return current;
         }
       }
       return current; // Last
-
-
-
-
-    }else if(op === 'filter'){
+    } else if (op === "filter") {
       scopedData = jsonLogic.apply(values[0], data);
       scopedLogic = values[1];
 
-      if ( ! Array.isArray(scopedData)) {
-          return [];
+      if (!Array.isArray(scopedData)) {
+        return [];
       }
       // Return only the elements from the array in the first argument,
       // that return truthy when passed to the logic in the second argument.
       // For parity with JavaScript, reindex the returned array
-      return scopedData.filter(function(datum){
-          return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum));
+      return scopedData.filter(function(datum) {
+        return jsonLogic.truthy(jsonLogic.apply(scopedLogic, datum));
       });
-  }else if(op === 'map'){
+    } else if (op === "map") {
       scopedData = jsonLogic.apply(values[0], data);
       scopedLogic = values[1];
 
-      if ( ! Array.isArray(scopedData)) {
-          return [];
+      if (!Array.isArray(scopedData)) {
+        return [];
       }
 
-      return scopedData.map(function(datum){
-          return jsonLogic.apply(scopedLogic, datum);
+      return scopedData.map(function(datum) {
+        return jsonLogic.apply(scopedLogic, datum);
       });
-
-  }else if(op === 'reduce'){
+    } else if (op === "reduce") {
       scopedData = jsonLogic.apply(values[0], data);
       scopedLogic = values[1];
-      initial = typeof values[2] !== 'undefined' ? values[2] : null;
+      initial = typeof values[2] !== "undefined" ? values[2] : null;
 
-      if ( ! Array.isArray(scopedData)) {
-          return initial;
+      if (!Array.isArray(scopedData)) {
+        return initial;
       }
 
       return scopedData.reduce(
-          function(accumulator, current){
-              return jsonLogic.apply(
-                  scopedLogic,
-                  {'current':current, 'accumulator':accumulator}
-              );
-          },
-          initial
+        function(accumulator, current) {
+          return jsonLogic.apply(
+            scopedLogic, {
+              "current": current,
+              "accumulator": accumulator,
+            }
+          );
+        },
+        initial
       );
-
-    }else if(op === "all") {
+    } else if (op === "all") {
       scopedData = jsonLogic.apply(values[0], data);
       scopedLogic = values[1];
       // All of an empty set is false. Note, some and none have correct fallback after the for loop
-      if( ! scopedData.length) {
+      if (!scopedData.length) {
         return false;
       }
-      for(i=0; i < scopedData.length; i+=1) {
-        if( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {
+      for (i = 0; i < scopedData.length; i += 1) {
+        if (!jsonLogic.truthy(jsonLogic.apply(scopedLogic, scopedData[i]))) {
           return false; // First falsy, short circuit
         }
       }
       return true; // All were truthy
-    }else if(op === "none") {
-      filtered = jsonLogic.apply({'filter' : values}, data);
+    } else if (op === "none") {
+      filtered = jsonLogic.apply({
+        "filter": values,
+      }, data);
       return filtered.length === 0;
-
-    }else if(op === "some") {
-      filtered = jsonLogic.apply({'filter' : values}, data);
+    } else if (op === "some") {
+      filtered = jsonLogic.apply({
+        "filter": values,
+      }, data);
       return filtered.length > 0;
     }
 
@@ -348,44 +370,44 @@ http://ricostacruz.com/cheatsheets/umdjs.html
     // The operation is called with "data" bound to its "this" and "values" passed as arguments.
     // Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments
     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
-    if(typeof operations[op] === "function") {
+    if (typeof operations[op] === "function") {
       return operations[op].apply(data, values);
-    }else if(op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position
+    } else if (op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position
       var sub_ops = String(op).split(".");
       var operation = operations;
-      for(i = 0; i < sub_ops.length; i++) {
+      for (i = 0; i < sub_ops.length; i++) {
         // Descending into operations
         operation = operation[sub_ops[i]];
-        if(operation === undefined) {
+        if (operation === undefined) {
           throw new Error("Unrecognized operation " + op +
-          " (failed at " + sub_ops.slice(0, i+1).join(".") + ")");
+            " (failed at " + sub_ops.slice(0, i + 1).join(".") + ")");
         }
       }
 
       return operation.apply(data, values);
     }
 
-    throw new Error("Unrecognized operation " + op );
+    throw new Error("Unrecognized operation " + op);
   };
 
   jsonLogic.uses_data = function(logic) {
     var collection = [];
 
-    if( jsonLogic.is_logic(logic) ) {
+    if (jsonLogic.is_logic(logic)) {
       var op = jsonLogic.get_operator(logic);
       var values = logic[op];
 
-      if( ! Array.isArray(values)) {
+      if (!Array.isArray(values)) {
         values = [values];
       }
 
-      if(op === "var") {
+      if (op === "var") {
         // This doesn't cover the case where the arg to var is itself a rule.
         collection.push(values[0]);
-      }else{
+      } else {
         // Recursion!
         values.map(function(val) {
-          collection.push.apply(collection, jsonLogic.uses_data(val) );
+          collection.push.apply(collection, jsonLogic.uses_data(val));
         });
       }
     }
@@ -403,30 +425,30 @@ http://ricostacruz.com/cheatsheets/umdjs.html
 
   jsonLogic.rule_like = function(rule, pattern) {
     // console.log("Is ". JSON.stringify(rule) . " like " . JSON.stringify(pattern) . "?");
-    if(pattern === rule) {
+    if (pattern === rule) {
       return true;
     } // TODO : Deep object equivalency?
-    if(pattern === "@") {
+    if (pattern === "@") {
       return true;
     } // Wildcard!
-    if(pattern === "number") {
+    if (pattern === "number") {
       return (typeof rule === "number");
     }
-    if(pattern === "string") {
+    if (pattern === "string") {
       return (typeof rule === "string");
     }
-    if(pattern === "array") {
+    if (pattern === "array") {
       // !logic test might be superfluous in JavaScript
-      return Array.isArray(rule) && ! jsonLogic.is_logic(rule);
+      return Array.isArray(rule) && !jsonLogic.is_logic(rule);
     }
 
-    if(jsonLogic.is_logic(pattern)) {
-      if(jsonLogic.is_logic(rule)) {
+    if (jsonLogic.is_logic(pattern)) {
+      if (jsonLogic.is_logic(rule)) {
         var pattern_op = jsonLogic.get_operator(pattern);
         var rule_op = jsonLogic.get_operator(rule);
 
-        if(pattern_op === "@" || pattern_op === rule_op) {
-        // echo "\nOperators match, go deeper\n";
+        if (pattern_op === "@" || pattern_op === rule_op) {
+          // echo "\nOperators match, go deeper\n";
           return jsonLogic.rule_like(
             jsonLogic.get_values(rule, false),
             jsonLogic.get_values(pattern, false)
@@ -436,22 +458,22 @@ http://ricostacruz.com/cheatsheets/umdjs.html
       return false; // pattern is logic, rule isn't, can't be eq
     }
 
-    if(Array.isArray(pattern)) {
-      if(Array.isArray(rule)) {
-        if(pattern.length !== rule.length) {
+    if (Array.isArray(pattern)) {
+      if (Array.isArray(rule)) {
+        if (pattern.length !== rule.length) {
           return false;
         }
         /*
           Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)
         */
-        for(var i = 0; i < pattern.length; i += 1) {
+        for (var i = 0; i < pattern.length; i += 1) {
           // If any fail, we fail
-          if( ! jsonLogic.rule_like(rule[i], pattern[i])) {
+          if (!jsonLogic.rule_like(rule[i], pattern[i])) {
             return false;
           }
         }
         return true; // If they *all* passed, we pass
-      }else{
+      } else {
         return false; // Pattern is array, rule isn't
       }
     }
diff --git a/tests/tests.js b/tests/tests.js
index b201bf6..e25c468 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -15,7 +15,7 @@ var download = function(url, dest, cb) {
   });
 };
 
-var remote_or_cache = function (remote_url, local_file, description, runner){
+var remote_or_cache = function(remote_url, local_file, description, runner){
   var parse_and_iterate = function(local_file, description, runner){
     fs.readFile(local_file, "utf8", function(error, body) {
       var tests;
@@ -36,7 +36,6 @@ var remote_or_cache = function (remote_url, local_file, description, runner){
 
       start();
     });
-
   };
 
 	// Only waiting on the request() is async
@@ -53,14 +52,13 @@ var remote_or_cache = function (remote_url, local_file, description, runner){
       parse_and_iterate(local_file, description, runner);
     }
   });
-
 };
 
 remote_or_cache(
   "http://jsonlogic.com/tests.json",
   "tests.json",
   "applies() tests",
-  function(test){
+  function(test) {
     var rule = test[0];
     var data = test[1];
     var expected = test[2];
@@ -79,7 +77,7 @@ remote_or_cache(
   "http://jsonlogic.com/rule_like.json",
   "rule_like.json",
   "rule_like() tests",
-  function(test){
+  function(test) {
     var rule = test[0];
     var pattern = test[1];
     var expected = test[2];
@@ -95,16 +93,10 @@ remote_or_cache(
 );
 
 
-
-
-
-
-QUnit.test( "Bad operator", function( assert ) {
-  assert.throws(
-    function() {
-      jsonLogic.apply({"fubar": []});
-    },
-    /Unrecognized operation/
+QUnit.test( "Bad operator should be trated as data", function( assert ) {
+  assert.deepEqual(
+    jsonLogic.apply({"fubar": []}),
+    {"fubar": []}
   );
 });
 
@@ -123,12 +115,10 @@ QUnit.test( "edge cases", function( assert ) {
 });
 
 QUnit.test( "Expanding functionality with add_operator", function( assert) {
-  // Operator is not yet defined
-  assert.throws(
-    function() {
-      jsonLogic.apply({"add_to_a": []});
-    },
-    /Unrecognized operation/
+  // Operator is not yet defined, so it's considered data
+  assert.deepEqual(
+    jsonLogic.apply({"add_to_a": []}),
+    {"add_to_a": []}
   );
 
   // Set up some outside data, and build a basic function operator
@@ -172,14 +162,12 @@ QUnit.test( "Expanding functionality with add_operator", function( assert) {
     42
   );
 
-  //Remove operation:
+  // Remove operation:
   jsonLogic.rm_operation("times");
 
-  assert.throws(
-    function() {
-      jsonLogic.apply({"times": [2,2]});
-    },
-    /Unrecognized operation/
+  assert.deepEqual(
+    jsonLogic.apply({"times": [2, 2]}),
+    {"times": [2, 2]}
   );
 
   // Calling a method that takes an array, but the inside of the array has rules, too
@@ -193,9 +181,6 @@ QUnit.test( "Expanding functionality with add_operator", function( assert) {
     ),
     42
   );
-
-
-
 });
 
 QUnit.test( "Expanding functionality with method", function( assert) {
@@ -317,3 +302,11 @@ QUnit.test("Control structures don't eval depth-first", function(assert) {
   jsonLogic.apply({"or": [{"push": [true]}, {"push": [true]}]});
   assert.deepEqual(i, [true]);
 });
+
+
+QUnit.test("Handle correctly single item objects", function(assert) {
+  assert.deepEqual(
+    jsonLogic.apply({"if": [true, {"item": 10}, "no"]}),
+    {"item": 10}
+  );
+});