diff --git a/shapeshift/init.lua b/shapeshift/init.lua index 6688027..2a45959 100644 --- a/shapeshift/init.lua +++ b/shapeshift/init.lua @@ -69,7 +69,8 @@ end --- Partially applies `shapeshift.table` with a given prototype. -- The special option `__extra` can be "drop", "keep" or absent to either drop -- keys that are not in the prototype, keep them "as is" in the result or --- (default) throw an error respectively. +-- (default) throw an error respectively. It can also be a function, in which +-- case it is treated as a validation/transformation for the key. -- @tparam table prototype A table mapping keys to value-validations. -- @tparam string extra When not nil, overrides `__extra` property. -- @usage @@ -83,9 +84,26 @@ function shapeshift.table(prototype, extra) return function(subject) local success, result = validate_table(prototype, subject) if success then - for key in pairs(subject) do + for key, value in pairs(subject) do if not prototype[key] then - result[key]=subject[key] + result[key] = value + end + end + end + return success, result + end + elseif type(extra) == "function" then + return function(subject) + local success, result = validate_table(prototype, subject) + if success then + for key, value in pairs(subject) do + if not prototype[key] then + local key_success, key_result = extra(key, subject[key]) + if not key_success then + return false, string.format("Key %s failed validation: %s", tostring(key), key_result) + else + result[key_result] = value + end end end end diff --git a/spec/shapeshift_spec.moon b/spec/shapeshift_spec.moon index dee0192..958e85e 100644 --- a/spec/shapeshift_spec.moon +++ b/spec/shapeshift_spec.moon @@ -28,6 +28,11 @@ describe 'shapeshift', -> it 'respects the __extra option', -> assert.same { foo: "bar" }, select 2, shapeshift.table(__extra: "keep")(foo: "bar") assert.same { }, select 2, shapeshift.table(__extra: "drop")(foo: "bar") + it 'accepts validations for the __extra option', -> + assert.same { foo: "bar" }, select 2, shapeshift.table(__extra: shapeshift.is.string)(foo: "bar") + assert.false shapeshift.table(__extra: shapeshift.is.number)(foo: "bar") + it 'accepts transformations for the __extra option', -> + assert.same { ["1"]: "bar" }, select 2, shapeshift.table(__extra: shapeshift.tostring){"bar"} describe 'default', -> it 'Returns the default only when subject is nil', ->