Repository: rtfeldman/seamless-immutable
Pull request #116 (2016-03-25 17:36:43)

Add update and updateIn functions
Makes nested updates a lot easier.
All the [cool](http://swannodette.github.io/mori/#updateIn) [kids](https://facebook.github.io/immutable-js/docs/#/Map/update) have it😉


Patch:
diff --git a/README.md b/README.md
index 6fe1740..391e072 100644
--- a/README.md
+++ b/README.md
@@ -199,6 +199,34 @@ Immutable({type: {main: "parrot", sub: "Norwegian Blue"}, status: "alive"}).setI
 // returns Immutable({type: {main: "parrot", sub: "Norwegian Ridgeback"}, status: "alive"})
 ```
 
+### update
+
+Returns an Immutable Object with a single property updated using the provided updater function.
+
+```javascript
+function inc (x) { return x + 1 }
+Immutable({foo: 1}).update("foo", inc)
+// returns Immutable({foo: 2})
+```
+
+All additional arguments will be passed to the updater function.
+
+```javascript
+function add (x, y) { return x + y }
+Immutable({foo: 1}).update("foo", add, 10)
+// returns Immutable({foo: 11})
+```
+
+### updateIn
+
+Like [update](#update), but accepts a nested path to the property.
+
+```javascript
+function add (x, y) { return x + y }
+Immutable({foo: {bar: 1}}).updateIn(["foo", "bar"], add, 10)
+// returns Immutable({foo: {bar: 11}})
+```
+
 ### without
 
 ```javascript
diff --git a/seamless-immutable.development.js b/seamless-immutable.development.js
index 484e72c..26d67c3 100644
--- a/seamless-immutable.development.js
+++ b/seamless-immutable.development.js
@@ -151,6 +151,8 @@
     addPropertyTo(array, "asMutable", asMutableArray);
     addPropertyTo(array, "set", arraySet);
     addPropertyTo(array, "setIn", arraySetIn);
+    addPropertyTo(array, "update", update);
+    addPropertyTo(array, "updateIn", updateIn);
 
     for(var i = 0, length = array.length; i < length; i++) {
       array[i] = Immutable(array[i]);
@@ -430,6 +432,28 @@
     return makeImmutableObject(mutable, this);
   }
 
+  function update(property, updater) {
+    var restArgs = Array.prototype.slice.call(arguments, 2);
+    var initialVal = this[property];
+    return this.set(property, updater.apply(initialVal, [initialVal].concat(restArgs)));
+  }
+
+  function getInPath(obj, path) {
+    /*jshint eqnull:true */
+    for (var i = 0, l = path.length; obj != null && i < l; i++) {
+      obj = obj[path[i]];
+    }
+
+    return (i && i == l) ? obj : undefined;
+  }
+
+  function updateIn(path, updater) {
+    var restArgs = Array.prototype.slice.call(arguments, 2);
+    var initialVal = getInPath(this, path);
+
+    return this.setIn(path, updater.apply(initialVal, [initialVal].concat(restArgs)));
+  }
+
   function asMutableObject(opts) {
     var result = this.instantiateEmptyObject(), key;
 
@@ -467,6 +491,8 @@
     addPropertyTo(obj, "instantiateEmptyObject", instantiateEmptyObject);
     addPropertyTo(obj, "set", objectSet);
     addPropertyTo(obj, "setIn", objectSetIn);
+    addPropertyTo(obj, "update", update);
+    addPropertyTo(obj, "updateIn", updateIn);
 
     return makeImmutable(obj, mutatingObjectMethods);
   }
diff --git a/seamless-immutable.development.min.js b/seamless-immutable.development.min.js
index 77dbc46..c685691 100644
--- a/seamless-immutable.development.min.js
+++ b/seamless-immutable.development.min.js
@@ -1,1 +1,1 @@
-/* (c) 2016, Richard Feldman, github.com/rtfeldman/seamless-immutable/blob/master/LICENSE */!function(){"use strict";function a(a,b,c){Object.defineProperty(a,b,{enumerable:!1,configurable:!1,writable:!1,value:c})}function b(b,c){a(b,c,function(){throw new f("The "+c+" method cannot be invoked on an Immutable data structure.")})}function c(b){a(b,A,!0)}function d(a){return"object"==typeof a?null===a||Boolean(Object.getOwnPropertyDescriptor(a,A)):!0}function e(a){return!(null===a||"object"!=typeof a||a instanceof Array||a instanceof Date)}function f(a){var b=new Error(a);return b.__proto__=f,b}function g(a,d){c(a);for(var e in d)d.hasOwnProperty(e)&&b(a,d[e]);return Object.freeze(a),a}function h(b,c){var d=b[c];a(b,c,function(){return z(d.apply(b,arguments))})}function i(a,b){if(a in this&&this[a]===b)return this;var c=p.call(this);return c[a]=z(b),k(c)}function j(a,b){var c=a[0];if(1===a.length)return i.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d="object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):j.call(G,e,b),c in this&&f===d)return this;var g=p.call(this);return g[c]=d,k(g)}function k(b){for(var c in E)if(E.hasOwnProperty(c)){var d=E[c];h(b,d)}a(b,"flatMap",n),a(b,"asObject",q),a(b,"asMutable",p),a(b,"set",i),a(b,"setIn",j);for(var e=0,f=b.length;f>e;e++)b[e]=z(b[e]);return g(b,D)}function l(b){return a(b,"asMutable",m),g(b,F)}function m(){return new Date(this.getTime())}function n(a){if(0===arguments.length)return this;var b,c=[],d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this);e instanceof Array?c.push.apply(c,e):c.push(e)}return k(c)}function o(a){if("undefined"==typeof a&&0===arguments.length)return this;if("function"!=typeof a){var b=a instanceof Array?a:Array.prototype.slice.call(arguments);a=function(a,c){return-1!==b.indexOf(c)}}var c=this.instantiateEmptyObject();for(var d in this)this.hasOwnProperty(d)&&a(this[d],d)===!1&&(c[d]=this[d]);return y(c,{instantiateEmptyObject:this.instantiateEmptyObject})}function p(a){var b,c,d=[];if(a&&a.deep)for(b=0,c=this.length;c>b;b++)d.push(r(this[b]));else for(b=0,c=this.length;c>b;b++)d.push(this[b]);return d}function q(a){"function"!=typeof a&&(a=function(a){return a});var b,c={},d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this),f=e[0],g=e[1];c[f]=g}return y(c)}function r(a){return!a||"object"!=typeof a||!Object.getOwnPropertyDescriptor(a,A)||a instanceof Date?a:a.asMutable({deep:!0})}function s(a,b){for(var c in a)Object.getOwnPropertyDescriptor(a,c)&&(b[c]=a[c]);return b}function t(a,b){function c(a,c,f){var g=z(c[f]),j=i&&i(a[f],g,b),k=a[f];if(void 0!==d||void 0!==j||!a.hasOwnProperty(f)||g!==k&&g===g){var l;l=j?j:h&&e(k)&&e(g)?k.merge(g,b):g,(k!==l&&l===l||!a.hasOwnProperty(f))&&(void 0===d&&(d=s(a,a.instantiateEmptyObject())),d[f]=l)}}if(0===arguments.length)return this;if(null===a||"object"!=typeof a)throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not "+JSON.stringify(a));var d,f,g=a instanceof Array,h=b&&b.deep,i=b&&b.merger;if(g)for(var j=0;j<a.length;j++){var k=a[j];for(f in k)k.hasOwnProperty(f)&&c(this,k,f)}else for(f in a)Object.getOwnPropertyDescriptor(a,f)&&c(this,a,f);return void 0===d?this:y(d,{instantiateEmptyObject:this.instantiateEmptyObject})}function u(a,b){var c=a[0];if(1===a.length)return v.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d=this.hasOwnProperty(c)&&"object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):u.call(H,e,b),this.hasOwnProperty(c)&&f===d)return this;var g=s(this,this.instantiateEmptyObject());return g[c]=d,y(g,this)}function v(a,b){if(this.hasOwnProperty(a)&&this[a]===b)return this;var c=s(this,this.instantiateEmptyObject());return c[a]=z(b),y(c,this)}function w(a){var b,c=this.instantiateEmptyObject();if(a&&a.deep)for(b in this)this.hasOwnProperty(b)&&(c[b]=r(this[b]));else for(b in this)this.hasOwnProperty(b)&&(c[b]=this[b]);return c}function x(){return{}}function y(b,c){var d=c&&c.instantiateEmptyObject?c.instantiateEmptyObject:x;return a(b,"merge",t),a(b,"without",o),a(b,"asMutable",w),a(b,"instantiateEmptyObject",d),a(b,"set",v),a(b,"setIn",u),g(b,B)}function z(a,b){if(d(a))return a;if(a instanceof Array)return k(a.slice());if(a instanceof Date)return l(new Date(a.getTime()));var c=b&&b.prototype,e=c&&c!==Object.prototype?function(){return Object.create(c)}:x,f=e();for(var g in a)Object.getOwnPropertyDescriptor(a,g)&&(f[g]=z(a[g]));return y(f,{instantiateEmptyObject:e})}var A="__immutable_invariants_hold",B=["setPrototypeOf"],C=["keys"],D=B.concat(["push","pop","sort","splice","shift","unshift","reverse"]),E=C.concat(["map","filter","slice","concat","reduce","reduceRight"]),F=B.concat(["setDate","setFullYear","setHours","setMilliseconds","setMinutes","setMonth","setSeconds","setTime","setUTCDate","setUTCFullYear","setUTCHours","setUTCMilliseconds","setUTCMinutes","setUTCMonth","setUTCSeconds","setYear"]);f.prototype=Error.prototype;var G=z([]),H=z({});z.isImmutable=d,z.ImmutableError=f,Object.freeze(z),"object"==typeof module?module.exports=z:"object"==typeof exports?exports.Immutable=z:"object"==typeof window?window.Immutable=z:"object"==typeof global&&(global.Immutable=z)}();
\ No newline at end of file
+/* (c) 2016, Richard Feldman, github.com/rtfeldman/seamless-immutable/blob/master/LICENSE */!function(){"use strict";function a(a,b,c){Object.defineProperty(a,b,{enumerable:!1,configurable:!1,writable:!1,value:c})}function b(b,c){a(b,c,function(){throw new f("The "+c+" method cannot be invoked on an Immutable data structure.")})}function c(b){a(b,D,!0)}function d(a){return"object"==typeof a?null===a||Boolean(Object.getOwnPropertyDescriptor(a,D)):!0}function e(a){return!(null===a||"object"!=typeof a||a instanceof Array||a instanceof Date)}function f(a){var b=new Error(a);return b.__proto__=f,b}function g(a,d){c(a);for(var e in d)d.hasOwnProperty(e)&&b(a,d[e]);return Object.freeze(a),a}function h(b,c){var d=b[c];a(b,c,function(){return C(d.apply(b,arguments))})}function i(a,b){if(a in this&&this[a]===b)return this;var c=p.call(this);return c[a]=C(b),k(c)}function j(a,b){var c=a[0];if(1===a.length)return i.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d="object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):j.call(J,e,b),c in this&&f===d)return this;var g=p.call(this);return g[c]=d,k(g)}function k(b){for(var c in H)if(H.hasOwnProperty(c)){var d=H[c];h(b,d)}a(b,"flatMap",n),a(b,"asObject",q),a(b,"asMutable",p),a(b,"set",i),a(b,"setIn",j),a(b,"update",w),a(b,"updateIn",y);for(var e=0,f=b.length;f>e;e++)b[e]=C(b[e]);return g(b,G)}function l(b){return a(b,"asMutable",m),g(b,I)}function m(){return new Date(this.getTime())}function n(a){if(0===arguments.length)return this;var b,c=[],d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this);e instanceof Array?c.push.apply(c,e):c.push(e)}return k(c)}function o(a){if("undefined"==typeof a&&0===arguments.length)return this;if("function"!=typeof a){var b=a instanceof Array?a:Array.prototype.slice.call(arguments);a=function(a,c){return-1!==b.indexOf(c)}}var c=this.instantiateEmptyObject();for(var d in this)this.hasOwnProperty(d)&&a(this[d],d)===!1&&(c[d]=this[d]);return B(c,{instantiateEmptyObject:this.instantiateEmptyObject})}function p(a){var b,c,d=[];if(a&&a.deep)for(b=0,c=this.length;c>b;b++)d.push(r(this[b]));else for(b=0,c=this.length;c>b;b++)d.push(this[b]);return d}function q(a){"function"!=typeof a&&(a=function(a){return a});var b,c={},d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this),f=e[0],g=e[1];c[f]=g}return B(c)}function r(a){return!a||"object"!=typeof a||!Object.getOwnPropertyDescriptor(a,D)||a instanceof Date?a:a.asMutable({deep:!0})}function s(a,b){for(var c in a)Object.getOwnPropertyDescriptor(a,c)&&(b[c]=a[c]);return b}function t(a,b){function c(a,c,f){var g=C(c[f]),j=i&&i(a[f],g,b),k=a[f];if(void 0!==d||void 0!==j||!a.hasOwnProperty(f)||g!==k&&g===g){var l;l=j?j:h&&e(k)&&e(g)?k.merge(g,b):g,(k!==l&&l===l||!a.hasOwnProperty(f))&&(void 0===d&&(d=s(a,a.instantiateEmptyObject())),d[f]=l)}}if(0===arguments.length)return this;if(null===a||"object"!=typeof a)throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not "+JSON.stringify(a));var d,f,g=a instanceof Array,h=b&&b.deep,i=b&&b.merger;if(g)for(var j=0;j<a.length;j++){var k=a[j];for(f in k)k.hasOwnProperty(f)&&c(this,k,f)}else for(f in a)Object.getOwnPropertyDescriptor(a,f)&&c(this,a,f);return void 0===d?this:B(d,{instantiateEmptyObject:this.instantiateEmptyObject})}function u(a,b){var c=a[0];if(1===a.length)return v.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d=this.hasOwnProperty(c)&&"object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):u.call(K,e,b),this.hasOwnProperty(c)&&f===d)return this;var g=s(this,this.instantiateEmptyObject());return g[c]=d,B(g,this)}function v(a,b){if(this.hasOwnProperty(a)&&this[a]===b)return this;var c=s(this,this.instantiateEmptyObject());return c[a]=C(b),B(c,this)}function w(a,b){var c=Array.prototype.slice.call(arguments,2),d=this[a];return this.set(a,b.apply(d,[d].concat(c)))}function x(a,b){for(var c=0,d=b.length;null!=a&&d>c;c++)a=a[b[c]];return c&&c==d?a:void 0}function y(a,b){var c=Array.prototype.slice.call(arguments,2),d=x(this,a);return this.setIn(a,b.apply(d,[d].concat(c)))}function z(a){var b,c=this.instantiateEmptyObject();if(a&&a.deep)for(b in this)this.hasOwnProperty(b)&&(c[b]=r(this[b]));else for(b in this)this.hasOwnProperty(b)&&(c[b]=this[b]);return c}function A(){return{}}function B(b,c){var d=c&&c.instantiateEmptyObject?c.instantiateEmptyObject:A;return a(b,"merge",t),a(b,"without",o),a(b,"asMutable",z),a(b,"instantiateEmptyObject",d),a(b,"set",v),a(b,"setIn",u),a(b,"update",w),a(b,"updateIn",y),g(b,E)}function C(a,b){if(d(a))return a;if(a instanceof Array)return k(a.slice());if(a instanceof Date)return l(new Date(a.getTime()));var c=b&&b.prototype,e=c&&c!==Object.prototype?function(){return Object.create(c)}:A,f=e();for(var g in a)Object.getOwnPropertyDescriptor(a,g)&&(f[g]=C(a[g]));return B(f,{instantiateEmptyObject:e})}var D="__immutable_invariants_hold",E=["setPrototypeOf"],F=["keys"],G=E.concat(["push","pop","sort","splice","shift","unshift","reverse"]),H=F.concat(["map","filter","slice","concat","reduce","reduceRight"]),I=E.concat(["setDate","setFullYear","setHours","setMilliseconds","setMinutes","setMonth","setSeconds","setTime","setUTCDate","setUTCFullYear","setUTCHours","setUTCMilliseconds","setUTCMinutes","setUTCMonth","setUTCSeconds","setYear"]);f.prototype=Error.prototype;var J=C([]),K=C({});C.isImmutable=d,C.ImmutableError=f,Object.freeze(C),"object"==typeof module?module.exports=C:"object"==typeof exports?exports.Immutable=C:"object"==typeof window?window.Immutable=C:"object"==typeof global&&(global.Immutable=C)}();
\ No newline at end of file
diff --git a/seamless-immutable.production.min.js b/seamless-immutable.production.min.js
index fb07a64..098f333 100644
--- a/seamless-immutable.production.min.js
+++ b/seamless-immutable.production.min.js
@@ -1,1 +1,1 @@
-/* (c) 2016, Richard Feldman, github.com/rtfeldman/seamless-immutable/blob/master/LICENSE */!function(){"use strict";function a(a,b,c){Object.defineProperty(a,b,{enumerable:!1,configurable:!1,writable:!1,value:c})}function b(b){a(b,z,!0)}function c(a){return"object"==typeof a?null===a||Boolean(Object.getOwnPropertyDescriptor(a,z)):!0}function d(a){return!(null===a||"object"!=typeof a||a instanceof Array||a instanceof Date)}function e(a){var b=new Error(a);return b.__proto__=e,b}function f(a,c){b(a);return a}function g(b,c){var d=b[c];a(b,c,function(){return y(d.apply(b,arguments))})}function h(a,b){if(a in this&&this[a]===b)return this;var c=o.call(this);return c[a]=y(b),j(c)}function i(a,b){var c=a[0];if(1===a.length)return h.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d="object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):i.call(F,e,b),c in this&&f===d)return this;var g=o.call(this);return g[c]=d,j(g)}function j(b){for(var c in D)if(D.hasOwnProperty(c)){var d=D[c];g(b,d)}a(b,"flatMap",m),a(b,"asObject",p),a(b,"asMutable",o),a(b,"set",h),a(b,"setIn",i);for(var e=0,j=b.length;j>e;e++)b[e]=y(b[e]);return f(b,C)}function k(b){return a(b,"asMutable",l),f(b,E)}function l(){return new Date(this.getTime())}function m(a){if(0===arguments.length)return this;var b,c=[],d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this);e instanceof Array?c.push.apply(c,e):c.push(e)}return j(c)}function n(a){if("undefined"==typeof a&&0===arguments.length)return this;if("function"!=typeof a){var b=a instanceof Array?a:Array.prototype.slice.call(arguments);a=function(a,c){return-1!==b.indexOf(c)}}var c=this.instantiateEmptyObject();for(var d in this)this.hasOwnProperty(d)&&a(this[d],d)===!1&&(c[d]=this[d]);return x(c,{instantiateEmptyObject:this.instantiateEmptyObject})}function o(a){var b,c,d=[];if(a&&a.deep)for(b=0,c=this.length;c>b;b++)d.push(q(this[b]));else for(b=0,c=this.length;c>b;b++)d.push(this[b]);return d}function p(a){"function"!=typeof a&&(a=function(a){return a});var b,c={},d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this),f=e[0],g=e[1];c[f]=g}return x(c)}function q(a){return!a||"object"!=typeof a||!Object.getOwnPropertyDescriptor(a,z)||a instanceof Date?a:a.asMutable({deep:!0})}function r(a,b){for(var c in a)Object.getOwnPropertyDescriptor(a,c)&&(b[c]=a[c]);return b}function s(a,b){function c(a,c,f){var g=y(c[f]),j=i&&i(a[f],g,b),k=a[f];if(void 0!==e||void 0!==j||!a.hasOwnProperty(f)||g!==k&&g===g){var l;l=j?j:h&&d(k)&&d(g)?k.merge(g,b):g,(k!==l&&l===l||!a.hasOwnProperty(f))&&(void 0===e&&(e=r(a,a.instantiateEmptyObject())),e[f]=l)}}if(0===arguments.length)return this;if(null===a||"object"!=typeof a)throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not "+JSON.stringify(a));var e,f,g=a instanceof Array,h=b&&b.deep,i=b&&b.merger;if(g)for(var j=0;j<a.length;j++){var k=a[j];for(f in k)k.hasOwnProperty(f)&&c(this,k,f)}else for(f in a)Object.getOwnPropertyDescriptor(a,f)&&c(this,a,f);return void 0===e?this:x(e,{instantiateEmptyObject:this.instantiateEmptyObject})}function t(a,b){var c=a[0];if(1===a.length)return u.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d=this.hasOwnProperty(c)&&"object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):t.call(G,e,b),this.hasOwnProperty(c)&&f===d)return this;var g=r(this,this.instantiateEmptyObject());return g[c]=d,x(g,this)}function u(a,b){if(this.hasOwnProperty(a)&&this[a]===b)return this;var c=r(this,this.instantiateEmptyObject());return c[a]=y(b),x(c,this)}function v(a){var b,c=this.instantiateEmptyObject();if(a&&a.deep)for(b in this)this.hasOwnProperty(b)&&(c[b]=q(this[b]));else for(b in this)this.hasOwnProperty(b)&&(c[b]=this[b]);return c}function w(){return{}}function x(b,c){var d=c&&c.instantiateEmptyObject?c.instantiateEmptyObject:w;return a(b,"merge",s),a(b,"without",n),a(b,"asMutable",v),a(b,"instantiateEmptyObject",d),a(b,"set",u),a(b,"setIn",t),f(b,A)}function y(a,b){if(c(a))return a;if(a instanceof Array)return j(a.slice());if(a instanceof Date)return k(new Date(a.getTime()));var d=b&&b.prototype,e=d&&d!==Object.prototype?function(){return Object.create(d)}:w,f=e();for(var g in a)Object.getOwnPropertyDescriptor(a,g)&&(f[g]=y(a[g]));return x(f,{instantiateEmptyObject:e})}var z="__immutable_invariants_hold",A=["setPrototypeOf"],B=["keys"],C=A.concat(["push","pop","sort","splice","shift","unshift","reverse"]),D=B.concat(["map","filter","slice","concat","reduce","reduceRight"]),E=A.concat(["setDate","setFullYear","setHours","setMilliseconds","setMinutes","setMonth","setSeconds","setTime","setUTCDate","setUTCFullYear","setUTCHours","setUTCMilliseconds","setUTCMinutes","setUTCMonth","setUTCSeconds","setYear"]);e.prototype=Error.prototype;var F=y([]),G=y({});y.isImmutable=c,y.ImmutableError=e,Object.freeze(y),"object"==typeof module?module.exports=y:"object"==typeof exports?exports.Immutable=y:"object"==typeof window?window.Immutable=y:"object"==typeof global&&(global.Immutable=y)}();
\ No newline at end of file
+/* (c) 2016, Richard Feldman, github.com/rtfeldman/seamless-immutable/blob/master/LICENSE */!function(){"use strict";function a(a,b,c){Object.defineProperty(a,b,{enumerable:!1,configurable:!1,writable:!1,value:c})}function b(b){a(b,C,!0)}function c(a){return"object"==typeof a?null===a||Boolean(Object.getOwnPropertyDescriptor(a,C)):!0}function d(a){return!(null===a||"object"!=typeof a||a instanceof Array||a instanceof Date)}function e(a){var b=new Error(a);return b.__proto__=e,b}function f(a,c){b(a);return a}function g(b,c){var d=b[c];a(b,c,function(){return B(d.apply(b,arguments))})}function h(a,b){if(a in this&&this[a]===b)return this;var c=o.call(this);return c[a]=B(b),j(c)}function i(a,b){var c=a[0];if(1===a.length)return h.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d="object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):i.call(I,e,b),c in this&&f===d)return this;var g=o.call(this);return g[c]=d,j(g)}function j(b){for(var c in G)if(G.hasOwnProperty(c)){var d=G[c];g(b,d)}a(b,"flatMap",m),a(b,"asObject",p),a(b,"asMutable",o),a(b,"set",h),a(b,"setIn",i),a(b,"update",v),a(b,"updateIn",x);for(var e=0,j=b.length;j>e;e++)b[e]=B(b[e]);return f(b,F)}function k(b){return a(b,"asMutable",l),f(b,H)}function l(){return new Date(this.getTime())}function m(a){if(0===arguments.length)return this;var b,c=[],d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this);e instanceof Array?c.push.apply(c,e):c.push(e)}return j(c)}function n(a){if("undefined"==typeof a&&0===arguments.length)return this;if("function"!=typeof a){var b=a instanceof Array?a:Array.prototype.slice.call(arguments);a=function(a,c){return-1!==b.indexOf(c)}}var c=this.instantiateEmptyObject();for(var d in this)this.hasOwnProperty(d)&&a(this[d],d)===!1&&(c[d]=this[d]);return A(c,{instantiateEmptyObject:this.instantiateEmptyObject})}function o(a){var b,c,d=[];if(a&&a.deep)for(b=0,c=this.length;c>b;b++)d.push(q(this[b]));else for(b=0,c=this.length;c>b;b++)d.push(this[b]);return d}function p(a){"function"!=typeof a&&(a=function(a){return a});var b,c={},d=this.length;for(b=0;d>b;b++){var e=a(this[b],b,this),f=e[0],g=e[1];c[f]=g}return A(c)}function q(a){return!a||"object"!=typeof a||!Object.getOwnPropertyDescriptor(a,C)||a instanceof Date?a:a.asMutable({deep:!0})}function r(a,b){for(var c in a)Object.getOwnPropertyDescriptor(a,c)&&(b[c]=a[c]);return b}function s(a,b){function c(a,c,f){var g=B(c[f]),j=i&&i(a[f],g,b),k=a[f];if(void 0!==e||void 0!==j||!a.hasOwnProperty(f)||g!==k&&g===g){var l;l=j?j:h&&d(k)&&d(g)?k.merge(g,b):g,(k!==l&&l===l||!a.hasOwnProperty(f))&&(void 0===e&&(e=r(a,a.instantiateEmptyObject())),e[f]=l)}}if(0===arguments.length)return this;if(null===a||"object"!=typeof a)throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not "+JSON.stringify(a));var e,f,g=a instanceof Array,h=b&&b.deep,i=b&&b.merger;if(g)for(var j=0;j<a.length;j++){var k=a[j];for(f in k)k.hasOwnProperty(f)&&c(this,k,f)}else for(f in a)Object.getOwnPropertyDescriptor(a,f)&&c(this,a,f);return void 0===e?this:A(e,{instantiateEmptyObject:this.instantiateEmptyObject})}function t(a,b){var c=a[0];if(1===a.length)return u.call(this,c,b);var d,e=a.slice(1),f=this[c];if(d=this.hasOwnProperty(c)&&"object"==typeof f&&null!==f&&"function"==typeof f.setIn?f.setIn(e,b):t.call(J,e,b),this.hasOwnProperty(c)&&f===d)return this;var g=r(this,this.instantiateEmptyObject());return g[c]=d,A(g,this)}function u(a,b){if(this.hasOwnProperty(a)&&this[a]===b)return this;var c=r(this,this.instantiateEmptyObject());return c[a]=B(b),A(c,this)}function v(a,b){var c=Array.prototype.slice.call(arguments,2),d=this[a];return this.set(a,b.apply(d,[d].concat(c)))}function w(a,b){for(var c=0,d=b.length;null!=a&&d>c;c++)a=a[b[c]];return c&&c==d?a:void 0}function x(a,b){var c=Array.prototype.slice.call(arguments,2),d=w(this,a);return this.setIn(a,b.apply(d,[d].concat(c)))}function y(a){var b,c=this.instantiateEmptyObject();if(a&&a.deep)for(b in this)this.hasOwnProperty(b)&&(c[b]=q(this[b]));else for(b in this)this.hasOwnProperty(b)&&(c[b]=this[b]);return c}function z(){return{}}function A(b,c){var d=c&&c.instantiateEmptyObject?c.instantiateEmptyObject:z;return a(b,"merge",s),a(b,"without",n),a(b,"asMutable",y),a(b,"instantiateEmptyObject",d),a(b,"set",u),a(b,"setIn",t),a(b,"update",v),a(b,"updateIn",x),f(b,D)}function B(a,b){if(c(a))return a;if(a instanceof Array)return j(a.slice());if(a instanceof Date)return k(new Date(a.getTime()));var d=b&&b.prototype,e=d&&d!==Object.prototype?function(){return Object.create(d)}:z,f=e();for(var g in a)Object.getOwnPropertyDescriptor(a,g)&&(f[g]=B(a[g]));return A(f,{instantiateEmptyObject:e})}var C="__immutable_invariants_hold",D=["setPrototypeOf"],E=["keys"],F=D.concat(["push","pop","sort","splice","shift","unshift","reverse"]),G=E.concat(["map","filter","slice","concat","reduce","reduceRight"]),H=D.concat(["setDate","setFullYear","setHours","setMilliseconds","setMinutes","setMonth","setSeconds","setTime","setUTCDate","setUTCFullYear","setUTCHours","setUTCMilliseconds","setUTCMinutes","setUTCMonth","setUTCSeconds","setYear"]);e.prototype=Error.prototype;var I=B([]),J=B({});B.isImmutable=c,B.ImmutableError=e,Object.freeze(B),"object"==typeof module?module.exports=B:"object"==typeof exports?exports.Immutable=B:"object"==typeof window?window.Immutable=B:"object"==typeof global&&(global.Immutable=B)}();
\ No newline at end of file
diff --git a/src/seamless-immutable.js b/src/seamless-immutable.js
index 50104e4..46eebce 100644
--- a/src/seamless-immutable.js
+++ b/src/seamless-immutable.js
@@ -151,6 +151,8 @@
     addPropertyTo(array, "asMutable", asMutableArray);
     addPropertyTo(array, "set", arraySet);
     addPropertyTo(array, "setIn", arraySetIn);
+    addPropertyTo(array, "update", update);
+    addPropertyTo(array, "updateIn", updateIn);
 
     for(var i = 0, length = array.length; i < length; i++) {
       array[i] = Immutable(array[i]);
@@ -430,6 +432,28 @@
     return makeImmutableObject(mutable, this);
   }
 
+  function update(property, updater) {
+    var restArgs = Array.prototype.slice.call(arguments, 2);
+    var initialVal = this[property];
+    return this.set(property, updater.apply(initialVal, [initialVal].concat(restArgs)));
+  }
+
+  function getInPath(obj, path) {
+    /*jshint eqnull:true */
+    for (var i = 0, l = path.length; obj != null && i < l; i++) {
+      obj = obj[path[i]];
+    }
+
+    return (i && i == l) ? obj : undefined;
+  }
+
+  function updateIn(path, updater) {
+    var restArgs = Array.prototype.slice.call(arguments, 2);
+    var initialVal = getInPath(this, path);
+
+    return this.setIn(path, updater.apply(initialVal, [initialVal].concat(restArgs)));
+  }
+
   function asMutableObject(opts) {
     var result = this.instantiateEmptyObject(), key;
 
@@ -467,6 +491,8 @@
     addPropertyTo(obj, "instantiateEmptyObject", instantiateEmptyObject);
     addPropertyTo(obj, "set", objectSet);
     addPropertyTo(obj, "setIn", objectSetIn);
+    addPropertyTo(obj, "update", update);
+    addPropertyTo(obj, "updateIn", updateIn);
 
     return makeImmutable(obj, mutatingObjectMethods);
   }


Test patch:
diff --git a/test/ImmutableArray.spec.js b/test/ImmutableArray.spec.js
index 16b463d..716306d 100644
--- a/test/ImmutableArray.spec.js
+++ b/test/ImmutableArray.spec.js
@@ -3,6 +3,7 @@ var testFlatMap   = require("./ImmutableArray/test-flatMap.js");
 var testAsObject  = require("./ImmutableArray/test-asObject.js");
 var testAsMutable = require("./ImmutableArray/test-asMutable.js");
 var testSet       = require("./ImmutableArray/test-set.js");
+var testUpdate    = require("./ImmutableArray/test-update.js");
 var devBuild      = require("../seamless-immutable.development.js");
 var prodBuild     = require("../seamless-immutable.production.min.js");
 var getTestUtils  = require("./TestUtils.js");
@@ -21,6 +22,7 @@ var getTestUtils  = require("./TestUtils.js");
       testAsObject(config);
       testAsMutable(config);
       testSet(config);
+      testUpdate(config);
     });
   });
 });
diff --git a/test/ImmutableArray/test-update.js b/test/ImmutableArray/test-update.js
new file mode 100644
index 0000000..acbd208
--- /dev/null
+++ b/test/ImmutableArray/test-update.js
@@ -0,0 +1,66 @@
+var JSC          = require("jscheck");
+var assert       = require("chai").assert;
+var _            = require("lodash");
+var getTestUtils = require("../TestUtils.js");
+
+
+module.exports = function(config) {
+  var Immutable = config.implementation;
+  var TestUtils = getTestUtils(Immutable);
+  var check     = TestUtils.check;
+
+  function getPathComponent() {
+    // It's very convenient to use lodash.set, but it has funky behaviour
+    // with numeric keys.
+    var s = JSC.string()().replace(/[^\w]/g, '_');
+    return /^\d+$/.test(s) ? s + 'a' : s;
+  }
+
+  function dummyUpdater (x) {
+    return x + "updated";
+  }
+
+  describe("#update", function() {
+    it("updates an array element using updater function", function () {
+      check(100, [ JSC.array([TestUtils.TraversableObjectSpecifier, JSC.any()]) ], function(array) {
+        var immutable = Immutable(array);
+        var mutable = immutable.asMutable();
+        var index = JSC.integer(0, array.length);
+
+        immutable = immutable.update(index, dummyUpdater);
+        mutable[index] = dummyUpdater(mutable[index]);
+
+        TestUtils.assertJsonEqual(immutable, mutable);
+      });
+    });
+  });
+
+  describe("#updateIn", function() {
+    it("updates a property by path using updater function", function () {
+      check(100, [ JSC.array([TestUtils.TraversableObjectSpecifier]) ], function(array) {
+        var immutable = Immutable(array);
+        // var value = JSC.any()();
+
+        var idx = JSC.integer(0, array.length-1);
+        var key = JSC.one_of(_.keys(immutable[idx]))();
+
+        var util = require('util');
+        function printArr(arr) {
+          return '[\n\t>'+_.map(arr, util.inspect).join('\n\t>')+'\n]';
+        }
+
+        var mutable = immutable.asMutable();
+        TestUtils.assertJsonEqual(immutable, mutable);
+        if (Immutable.isImmutable(mutable[idx])) {
+          mutable[idx] = mutable[idx].asMutable();
+        }
+        mutable[idx][key] = dummyUpdater(mutable[idx][key]);
+
+        TestUtils.assertJsonEqual(
+          immutable.updateIn([idx, key], dummyUpdater),
+          mutable
+        );
+      });
+    });
+  });
+};
diff --git a/test/ImmutableObject.spec.js b/test/ImmutableObject.spec.js
index 40c4eac..c6e9d68 100644
--- a/test/ImmutableObject.spec.js
+++ b/test/ImmutableObject.spec.js
@@ -2,7 +2,8 @@ var testMerge     = require("./ImmutableObject/test-merge.js");
 var testCompat    = require("./ImmutableObject/test-compat.js");
 var testWithout   = require("./ImmutableObject/test-without.js");
 var testAsMutable = require("./ImmutableObject/test-asMutable.js");
-var testSet = require("./ImmutableObject/test-set.js");
+var testSet       = require("./ImmutableObject/test-set.js");
+var testUpdate    = require("./ImmutableObject/test-update.js");
 var testInstantiateEmptyObject = require("./ImmutableObject/test-instantiateEmptyObject.js");
 var devBuild      = require("../seamless-immutable.development.js");
 var prodBuild     = require("../seamless-immutable.production.min.js");
@@ -23,6 +24,7 @@ var getTestUtils  = require("./TestUtils.js");
       testAsMutable(config);
       testInstantiateEmptyObject(config);
       testSet(config);
+      testUpdate(config);
     });
   });
 });
diff --git a/test/ImmutableObject/test-update.js b/test/ImmutableObject/test-update.js
new file mode 100644
index 0000000..a25bf9c
--- /dev/null
+++ b/test/ImmutableObject/test-update.js
@@ -0,0 +1,88 @@
+var JSC          = require("jscheck");
+var assert       = require("chai").assert;
+var _            = require("lodash");
+var getTestUtils = require("../TestUtils.js");
+
+
+module.exports = function(config) {
+  var Immutable = config.implementation;
+  var TestUtils = getTestUtils(Immutable);
+  var check     = TestUtils.check;
+
+  function getPathComponent() {
+    // It's very convenient to use lodash.set, but it has funky behaviour
+    // with numeric keys.
+    var s = JSC.string()().replace(/[^\w]/g, '_');
+    return /^\d+$/.test(s) ? s + 'a' : s;
+  }
+
+  function dummyUpdater (x) {
+    return JSON.stringify(x) + "_updated";
+  }
+
+  function dummyUpdaterWithAggitionalArgs (x, y, z) {
+    return dummyUpdater(x) + y + z;
+  }
+
+  describe("#update", function() {
+    it("updates a property using updater function", function () {
+      check(100, [TestUtils.TraversableObjectSpecifier], function(ob) {
+        var immutable = Immutable(ob);
+        var mutable = immutable.asMutable({deep: true});
+        var prop = 'complex';
+
+        TestUtils.assertJsonEqual(
+          immutable.update(prop, dummyUpdater),
+          _.set(mutable, prop, dummyUpdater(_.get(mutable, prop)))
+        );
+      });
+    });
+
+    it("allows passing additional parameters to updater function", function () {
+      check(100, [TestUtils.TraversableObjectSpecifier], function(ob) {
+        var immutable = Immutable(ob);
+        var mutable = immutable.asMutable({deep: true});
+        var prop = 'complex';
+
+        TestUtils.assertJsonEqual(
+          immutable.update(prop, dummyUpdater, "agr1", 42),
+          _.set(mutable, prop, dummyUpdater(_.get(mutable, prop), "agr1", 42))
+        );
+      });
+    });
+  });
+
+  describe("#updateIn", function() {
+    it("updates a property in path using updater function", function () {
+      check(100, [TestUtils.TraversableObjectSpecifier], function(ob) {
+        var immutable = Immutable(ob);
+        var mutable = immutable.asMutable({deep: true});
+
+        TestUtils.assertJsonEqual(immutable, mutable);
+
+        var path = ['deep', 'complex'];
+
+        TestUtils.assertJsonEqual(
+          immutable.updateIn(path, dummyUpdater),
+          _.set(mutable, path, dummyUpdater(_.get(mutable, path)))
+        );
+      });
+    });
+
+    it("allows passing additional parameters to updater function", function () {
+      check(100, [TestUtils.TraversableObjectSpecifier], function(ob) {
+        var immutable = Immutable(ob);
+        var mutable = immutable.asMutable({deep: true});
+
+        TestUtils.assertJsonEqual(immutable, mutable);
+
+        var path = ['deep', 'complex'];
+
+        TestUtils.assertJsonEqual(
+          immutable.updateIn(path, dummyUpdater, "agr1", 42),
+          _.set(mutable, path, dummyUpdater(_.get(mutable, path), "agr1", 42))
+        );
+      });
+    });
+  });
+};