管道,带有动态参数的 ramda
Pipes, ramda with dynamic arguments
cons columnDefs = [
{
label: 'The_First_Name',
value: getProp,
args: ['firstName'] // different number of arguments depending on function
},
{
label: 'City',
value: getNestedProperty,
args: ['location', 'city']
}
]
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
]
const getProp = (object, key) => R.prop(key, object);
const getNestedProperty = (obj, args) => R.path(..args, obj);
Ramda 管道映射数据:
const tableBuilder = R.pipe(R.map); // some ramda functions in here
const rows = tableBuilder(data, columnDefs);
想要的输出:
rows output:
[
{
The_First_Name: 'Joe',
city: 'London'
},
{
The_First_Name: 'Anna',
city: 'Stockholm'
}
]
每行的键是columnDefs
中的label
属性。该值是从 value
属性中的 Ramda
函数连同 args
属性中定义的参数一起获取的。
https://plnkr.co/edit/rOGh4zkyOEF24TLaCZ4e?p=preview
完全卡住了。这甚至可能与 Ramda 相关吗?或者最好用普通的 javascript?
您可以使用 applySpec
从另一个对象创建一个对象:
const obj = applySpec({
The_First_Name: prop('firstName'),
city: path(['location', 'city'])
})
obj({
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
});
//=> {"The_First_Name": "Joe", "city": "London"}
然后你可以使用那个函数来映射你的数组:
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
];
const obj = applySpec({
The_First_Name: prop('firstName'),
city: path(['location', 'city'])
})
console.log(
map(obj, data)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {applySpec, prop, path, map} = R;</script>
这就是将 columnDefs
转换为可以与 applySpec
一起使用的对象的方法:
const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));
const columnDefs = [
{
label: 'The_First_Name',
value: prop,
args: ['firstName'] // different number of arguments depending on function
},
{
label: 'City',
value: path,
args: [['location', 'city']]
}
]
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
]
const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));
console.log(
map(applySpec(specs(columnDefs)), data)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {apply, compose, mergeAll, map, prop, path, applySpec} = R;</script>
以下应该有效:
const tableBuilder = (objs, spec) => objs .map (
obj => Object .assign ( ...spec.map (
( {label, value, args} ) => ( { [label]: value (obj, args) } )
))
)
const getProp = (object, key) => R.prop (key, object);
const getNestedProperty = (obj, args) => R.path (args, obj);
const columnDefs = [
{label: 'The_First_Name', value: getProp, args: ['firstName']},
{label: 'City', value: getNestedProperty, args: ['location', 'city']}
]
const data = [
{firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
{firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]
console .log (
tableBuilder (data, columnDefs)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>
const {prop, path} = R </script>
但它的工作主要是偶然的。您可能需要重新考虑一下函数的定义方式。
这是调用 prop (['firstName'], obj)
的等效项,它恰好像 prop ('firstName', obj)
一样工作,但只是出于与 'foo' + ['bar']
产生 'foobar'
相同的原因。这是一个巧合,你可能不应该依赖它。
问题是你想统一对待接受单个参数的函数和接受参数数组的函数。这是个问题。您可能需要使其保持一致。
虽然您可以为此编写 Ramda 注释,但我不确定它是否更具可读性。也许用 mergeAll (spec.map (
替换 Object .assign (...spec.map (
会更干净。如果您不介意更改参数顺序,可能还有更多 clean-up。但这已经相当可读了。
更新
@customcommander 的回答让我相信 Ramda 确实可以在这里增加一些价值。这要求您愿意为 value
函数交换参数顺序,并愿意将其作为完全柯里化函数 (tableBuilder (columnDefs) (data)
) 调用,但这确实会产生一些非常好的代码。
这主要是 customcommander 的工作,但我对其进行了一些调整以使函数更具可读性:
const spec = ({label, value, args}) => ({[label]: value(args)})
const tableBuilder = pipe(
map(spec),
mergeAll,
applySpec,
map
)
const columnDefs = [
{label: 'The_First_Name', value: prop, args: ['firstName']},
{label: 'City', value: path, args: ['location', 'city']}
]
const data = [
{firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
{firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]
console .log (
tableBuilder (columnDefs) (data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script><script>
const {prop, path, pipe, map, mergeAll, applySpec} = R </script>
这与之前 prop
的问题相同,但请注意,您可以在此处将其替换为 path
而不会造成任何损害。要点是所有 value
函数都应该有相同的输入(一组值和要处理的对象)。如果它们是这样,那么这应该适用于它们中的任何一个。
cons columnDefs = [
{
label: 'The_First_Name',
value: getProp,
args: ['firstName'] // different number of arguments depending on function
},
{
label: 'City',
value: getNestedProperty,
args: ['location', 'city']
}
]
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
]
const getProp = (object, key) => R.prop(key, object);
const getNestedProperty = (obj, args) => R.path(..args, obj);
Ramda 管道映射数据:
const tableBuilder = R.pipe(R.map); // some ramda functions in here
const rows = tableBuilder(data, columnDefs);
想要的输出:
rows output:
[
{
The_First_Name: 'Joe',
city: 'London'
},
{
The_First_Name: 'Anna',
city: 'Stockholm'
}
]
每行的键是columnDefs
中的label
属性。该值是从 value
属性中的 Ramda
函数连同 args
属性中定义的参数一起获取的。
https://plnkr.co/edit/rOGh4zkyOEF24TLaCZ4e?p=preview
完全卡住了。这甚至可能与 Ramda 相关吗?或者最好用普通的 javascript?
您可以使用 applySpec
从另一个对象创建一个对象:
const obj = applySpec({
The_First_Name: prop('firstName'),
city: path(['location', 'city'])
})
obj({
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
});
//=> {"The_First_Name": "Joe", "city": "London"}
然后你可以使用那个函数来映射你的数组:
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
];
const obj = applySpec({
The_First_Name: prop('firstName'),
city: path(['location', 'city'])
})
console.log(
map(obj, data)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {applySpec, prop, path, map} = R;</script>
这就是将 columnDefs
转换为可以与 applySpec
一起使用的对象的方法:
const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));
const columnDefs = [
{
label: 'The_First_Name',
value: prop,
args: ['firstName'] // different number of arguments depending on function
},
{
label: 'City',
value: path,
args: [['location', 'city']]
}
]
const data = [
{
firstName: 'Joe',
lastName: 'Smith',
location: {
city: 'London'
}
},
{
firstName: 'Anna',
lastName: 'Andersson',
location: {
city: 'Stockholm'
}
}
]
const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));
console.log(
map(applySpec(specs(columnDefs)), data)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {apply, compose, mergeAll, map, prop, path, applySpec} = R;</script>
以下应该有效:
const tableBuilder = (objs, spec) => objs .map (
obj => Object .assign ( ...spec.map (
( {label, value, args} ) => ( { [label]: value (obj, args) } )
))
)
const getProp = (object, key) => R.prop (key, object);
const getNestedProperty = (obj, args) => R.path (args, obj);
const columnDefs = [
{label: 'The_First_Name', value: getProp, args: ['firstName']},
{label: 'City', value: getNestedProperty, args: ['location', 'city']}
]
const data = [
{firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
{firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]
console .log (
tableBuilder (data, columnDefs)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>
const {prop, path} = R </script>
但它的工作主要是偶然的。您可能需要重新考虑一下函数的定义方式。
这是调用 prop (['firstName'], obj)
的等效项,它恰好像 prop ('firstName', obj)
一样工作,但只是出于与 'foo' + ['bar']
产生 'foobar'
相同的原因。这是一个巧合,你可能不应该依赖它。
问题是你想统一对待接受单个参数的函数和接受参数数组的函数。这是个问题。您可能需要使其保持一致。
虽然您可以为此编写 Ramda 注释,但我不确定它是否更具可读性。也许用 mergeAll (spec.map (
替换 Object .assign (...spec.map (
会更干净。如果您不介意更改参数顺序,可能还有更多 clean-up。但这已经相当可读了。
更新
@customcommander 的回答让我相信 Ramda 确实可以在这里增加一些价值。这要求您愿意为 value
函数交换参数顺序,并愿意将其作为完全柯里化函数 (tableBuilder (columnDefs) (data)
) 调用,但这确实会产生一些非常好的代码。
这主要是 customcommander 的工作,但我对其进行了一些调整以使函数更具可读性:
const spec = ({label, value, args}) => ({[label]: value(args)})
const tableBuilder = pipe(
map(spec),
mergeAll,
applySpec,
map
)
const columnDefs = [
{label: 'The_First_Name', value: prop, args: ['firstName']},
{label: 'City', value: path, args: ['location', 'city']}
]
const data = [
{firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
{firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]
console .log (
tableBuilder (columnDefs) (data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script><script>
const {prop, path, pipe, map, mergeAll, applySpec} = R </script>
这与之前 prop
的问题相同,但请注意,您可以在此处将其替换为 path
而不会造成任何损害。要点是所有 value
函数都应该有相同的输入(一组值和要处理的对象)。如果它们是这样,那么这应该适用于它们中的任何一个。