使用Ramdajs将Imperative转换为功能风格范例 [英] Converting Imperative to Functional style paradigm using Ramdajs

查看:158
本文介绍了使用Ramdajs将Imperative转换为功能风格范例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下脚本创建一个过滤一些输入数据的对象。
它使用几个嵌套 forEach 以声明方式编码。



我想知道哪个用于使用 ramdajs lodash ,特别是我会有兴趣了解如果使用管道< a>在这种情况下是适当的,否则就是另一种方式。



一个代码示例将会很感激(特别是对于ramdajs)。谢谢。


$ b

var data = {type:stylesheet, stylesheet:{rules:[{type:keyframes,name:bounce,keyframes:[{type:keyframe,values:[from, 20%,53%,80%,to],声明:[{type:声明,属性:animation-timing-function,value立方贝兹(0.215,0.610,0.355,1.000),位置:{start:{line:3,column:5},end:{line:3, :72}}},{type:declaration,property:transform, value:translate3d(0,0,0),position:{start:{line:4,column:5},end:{line:4,列:34}}}],position:{start:{line:2,column:3},end:{line:5,column:4}} },{type:keyframe,values:[40%,43%],声明:[{type:declaration,property函数,值:立方贝塞尔(0.755,0.050,0.855,0.060),位置:{开始:{行:8,列:5},结束:{ line:8,column:72}}},{ type:声明,属性:transform,value:translate3d(0,-30px,0),position:{start:{line:9, :5,end:{line:9,column:40}}}],position:{start:{line:7,column:3}结尾:{line:10,column:4}}},{type:keyframe,values:[70%],declarations:[{type:声明,属性:动画定时功能,值:立方贝塞尔(0.755,0.050,0.855,0.060),位置:{start:{line 列:5},结束:{行:13, column:72}}},{type:declaration,property:transform,value:translate3d(0,-15px,0),position:{start :{line:14,column:5},end:{line:14,column:40}}}],position:{start:{line 12,column:3},end:{line:15,column:4}},{type:keyframe,values:[90%],声明:[{type:declaration,property:transform,value:translate3d(0,-4px,0),position:{start:{line :18,列:5},结束:{ line:18,column:37}}}],position:{start:{line:17,column:3},end:{line column:4}}}],position:{start:{line:1,column:1},end:{line:20,column:2} }},{type:rule,selectors:[.bounce],declarations:[{type:declaration,property:animation-name :bounce,position:{start:{line:23,column:3},end:{line:23,column:25}},{键入:声明,属性:变换原点,值: 中心底,位置:{start:{line:24,column:3},end:{line:24,column:34}}]位置:{start:{line:22,column:1},end:{line:25,column:2}},{type:keyframes ,name:spark,keyframes:[{type:keyframe,values:[0%,50%],声明:[{type:声明,属性:transform,value:translate3d(0,0,0),position:{start:{line:29,column:5}结束:{line:29,column:34}}}],position:{ start:{line:28,column:3},end:{line:30,column:4}},{type:keyframe,values :[100%],声明:[{type:declaration,property:transform,value:translate3d(0,-4px,0),position: {start:{line:32,column:5},end:{line:32,column:37}}}],position:{start line:31,column:3},end:{line:33,column:4}}}],position:{start:{line column:1},end:{line:34 ,column:2}}},{type:rule,selectors:[.spark],declarations:[{type:declaration,property:animation -name,value:spark,position:{start:{line:37,column:3},end:{line:37,column 24}},{type:declaration,property:transform-origin,value:center center,position:{start:{line:38,列:3},end:{line:38,column:34}}}],position:{start:{line:36,column:1}, end:{line:39,column:2}}}],parsingErro rs:[]}}; var result = {}; var kfs = data.stylesheet.rules.filter(function(rule){return rule.type ==='keyframes'}); kfs.forEach(function(kf){result [kf.name] = []; kf.keyframes.forEach(function(kfi){kfi.values.forEach(function(v){var r = {}; var vNew; vNew = v; if(v ==='from'){vNew = 0;} else if(v ==='to'){vNew = 100;} else {vNew = parseFloat(v);} r.offset = vNew; kfi.declarations.forEach(function(d){r [d.property] = d.value;}); result [kf.name] .push(r);});});}); console.log(result);

编辑:



到目前为止,我能够在ramdajs中实现这个结果:

  var rulesLense = R.lensPath(['stylesheet','rules']); 
var ruleView = R.view(rulesLense,obj);
var keyframes = R.filter(R.propEq('type','keyframes'));
var groupByKeyframe = R.groupBy(keyframe => {
return R.prop('name',keyframe);
});

var process = R.pipe(
keyframes,
groupByKeyframe
);
var result = process(ruleView);


解决方案

。要使用镜头修改结构,建议使用 applySpec evolve ,这些对于返回新版本的对象非常有用修改后的值。但是你正在寻找将数据转化为与原始树非常不同的东西,我认为它是AST。在Ramda中, pipe compose 是essentials,它可以通过编写小函数来构造代码。为了处理树,我使用 converge 进行分支, objOf zipObj 创建新的对象。同时 map 减少以使用列表。



在本例中,我将使用以下组合策略:

  transformAST 
^
|
|
getContentOfKeyframes
^ ^
| |
| |
processKeyframe processAnimation

首先,我们创建一个接收 values 和一个声明的数组,它返回一个数组,它在第一个位置有一个转换值数组,在第二个位置定位一个对象,其中的键是声明属性的值,并且这些值是其相应的声明

  var processKeyframe =(vals,declarations)=> [
//映射每个值
R.map(R.cond([
[R.equals('from'),R.always(0)],
[ R.equals('to'),R.always(100)],
[RT,parseFloat]
]),vals),
//收集所有属性值对并合并一个对象
R.reduce(R.merge,{},
R.map(R.converge(R.objOf,[
R.prop('property'),
.prop('value')
]),声明))
]

现在让我们创建一个处理动画的函数,它接收一个偏移量的数组和一个带有变换的对象,返回一个带有签名<$ c $的新对象的数组c> {offset:offset,... trasformations} 。

  var processAnimation =(offset, transf)=> 
R.map(R.pipe(
R.objOf('offset'),
R.merge(transf)),offset)



接下来,通过组合前两个函数来映射每个关键帧:

  var getContentOfKeyframes = R.map(R.pipe(
// process keyframes
R.converge(processKeyframe,[
R.prop('values'),
R.prop('声明')
]),
//处理动画
R.converge(processAnimation,[
R.nth(0),
R .nth(1)
])))

最后,我们定义函数,所需的属性从 data ,总结了每个关键帧,最后在最后阶段给出了所需的格式。

  var transformAST = R.pipe(
//获取`stylesheet.rules`属性
R.path(['stylesheet','rules']),
//只获得`type`属性为'keyframes`的对象
R.filter(R.propEq('typ e','keyframes')),
//映射`keyframes`中的每个项目
// //到一个对象{name:keyframe.name,content:[contentOfkeyframes]}
R .map((keyframe)=> ({
name:keyframe.name,
content:getContentOfKeyframes(keyframe.keyframes)
})),
//最后使用动画`name`作为键创建一个新对象
//并使用扁平内容作为值
R.converge(R.zipObj,[
R.map(R.prop('name')),
。 map(R.pipe(R.prop('content'),R.flatten))
)))

现在您可以直接处理AST传递数据对象的内容。

  var result = transformAST(data)

所有在一起。

  var processKeyframe =(vals,declarations)=> [
R.map(R.cond([
[R.equals('from'),R.always(0)],
[R.equals('to'), R.always(100)],
[RT,parseFloat]
]),vals),
R.reduce(R.merge,{},
R.map R.converge(R.objOf,[
R.prop('property'),
R.prop('value')
)),declarations))
]

var processAnimation =(offset,transf)=>
R.map(R.pipe(
R.objOf('offset'),
R.merge(transf)),offset)

var getContentOfKeyframes = R.map(R.pipe(
R.converge(processKeyframe,[
R.prop('values'),
R.prop('declarations')
)) ,
R.converge(processAnimation,[
R.nth(0),
R.nth(1)
])))

var transformAST = R.pipe(
R.path(['stylesheet','rules']),
R.filter(R.propEq('type','keyframes')),
.map((keyframe)=>({
name:keyframe.name,
content:getContentOfKeyframes(keyframe.keyframes)
})),
R.converge (R.zipObj,[
R.map(R.prop('name')),
R.map(R.pipe(R.prop('content'),R.flatten))
)))

var result = transformAST(data)


The following script create an object filtering some input data. It is coded in a declarative way using several nested forEach.

I would like to know which API to use in rewritting this code using ramdajs or lodash, specially I would be interested in understand if use of pipe is appropriate in this case otherwise another way.

An example of code would be appreciate (specially for ramdajs). Thanks.

  var data = {
    "type": "stylesheet",
    "stylesheet": {
      "rules": [{
        "type": "keyframes",
        "name": "bounce",
        "keyframes": [{
          "type": "keyframe",
          "values": [
            "from",
            "20%",
            "53%",
            "80%",
            "to"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "animation-timing-function",
            "value": "cubic-bezier(0.215, 0.610, 0.355, 1.000)",
            "position": {
              "start": {
                "line": 3,
                "column": 5
              },
              "end": {
                "line": 3,
                "column": 72
              }
            }
          }, {
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0,0,0)",
            "position": {
              "start": {
                "line": 4,
                "column": 5
              },
              "end": {
                "line": 4,
                "column": 34
              }
            }
          }],
          "position": {
            "start": {
              "line": 2,
              "column": 3
            },
            "end": {
              "line": 5,
              "column": 4
            }
          }
        }, {
          "type": "keyframe",
          "values": [
            "40%",
            "43%"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "animation-timing-function",
            "value": "cubic-bezier(0.755, 0.050, 0.855, 0.060)",
            "position": {
              "start": {
                "line": 8,
                "column": 5
              },
              "end": {
                "line": 8,
                "column": 72
              }
            }
          }, {
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0, -30px, 0)",
            "position": {
              "start": {
                "line": 9,
                "column": 5
              },
              "end": {
                "line": 9,
                "column": 40
              }
            }
          }],
          "position": {
            "start": {
              "line": 7,
              "column": 3
            },
            "end": {
              "line": 10,
              "column": 4
            }
          }
        }, {
          "type": "keyframe",
          "values": [
            "70%"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "animation-timing-function",
            "value": "cubic-bezier(0.755, 0.050, 0.855, 0.060)",
            "position": {
              "start": {
                "line": 13,
                "column": 5
              },
              "end": {
                "line": 13,
                "column": 72
              }
            }
          }, {
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0, -15px, 0)",
            "position": {
              "start": {
                "line": 14,
                "column": 5
              },
              "end": {
                "line": 14,
                "column": 40
              }
            }
          }],
          "position": {
            "start": {
              "line": 12,
              "column": 3
            },
            "end": {
              "line": 15,
              "column": 4
            }
          }
        }, {
          "type": "keyframe",
          "values": [
            "90%"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0,-4px,0)",
            "position": {
              "start": {
                "line": 18,
                "column": 5
              },
              "end": {
                "line": 18,
                "column": 37
              }
            }
          }],
          "position": {
            "start": {
              "line": 17,
              "column": 3
            },
            "end": {
              "line": 19,
              "column": 4
            }
          }
        }],
        "position": {
          "start": {
            "line": 1,
            "column": 1
          },
          "end": {
            "line": 20,
            "column": 2
          }
        }
      }, {
        "type": "rule",
        "selectors": [
          ".bounce"
        ],
        "declarations": [{
          "type": "declaration",
          "property": "animation-name",
          "value": "bounce",
          "position": {
            "start": {
              "line": 23,
              "column": 3
            },
            "end": {
              "line": 23,
              "column": 25
            }
          }
        }, {
          "type": "declaration",
          "property": "transform-origin",
          "value": "center bottom",
          "position": {
            "start": {
              "line": 24,
              "column": 3
            },
            "end": {
              "line": 24,
              "column": 34
            }
          }
        }],
        "position": {
          "start": {
            "line": 22,
            "column": 1
          },
          "end": {
            "line": 25,
            "column": 2
          }
        }
      }, {
        "type": "keyframes",
        "name": "spark",
        "keyframes": [{
          "type": "keyframe",
          "values": [
            "0%",
            "50%"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0,0,0)",
            "position": {
              "start": {
                "line": 29,
                "column": 5
              },
              "end": {
                "line": 29,
                "column": 34
              }
            }
          }],
          "position": {
            "start": {
              "line": 28,
              "column": 3
            },
            "end": {
              "line": 30,
              "column": 4
            }
          }
        }, {
          "type": "keyframe",
          "values": [
            "100%"
          ],
          "declarations": [{
            "type": "declaration",
            "property": "transform",
            "value": "translate3d(0,-4px,0)",
            "position": {
              "start": {
                "line": 32,
                "column": 5
              },
              "end": {
                "line": 32,
                "column": 37
              }
            }
          }],
          "position": {
            "start": {
              "line": 31,
              "column": 3
            },
            "end": {
              "line": 33,
              "column": 4
            }
          }
        }],
        "position": {
          "start": {
            "line": 27,
            "column": 1
          },
          "end": {
            "line": 34,
            "column": 2
          }
        }
      }, {
        "type": "rule",
        "selectors": [
          ".spark"
        ],
        "declarations": [{
          "type": "declaration",
          "property": "animation-name",
          "value": "spark",
          "position": {
            "start": {
              "line": 37,
              "column": 3
            },
            "end": {
              "line": 37,
              "column": 24
            }
          }
        }, {
          "type": "declaration",
          "property": "transform-origin",
          "value": "center center",
          "position": {
            "start": {
              "line": 38,
              "column": 3
            },
            "end": {
              "line": 38,
              "column": 34
            }
          }
        }],
        "position": {
          "start": {
            "line": 36,
            "column": 1
          },
          "end": {
            "line": 39,
            "column": 2
          }
        }
      }],
      "parsingErrors": []
    }
  };
  var result = {};
  var kfs = data.stylesheet.rules.filter(function(rule) {
    return rule.type === 'keyframes'
  });

  kfs.forEach(function(kf) {
    result[kf.name] = [];
    kf.keyframes.forEach(function(kfi) {
      kfi.values.forEach(function(v) {
        var r = {};
        var vNew;
        vNew = v;
        if (v === 'from') {
          vNew = 0;
        } else if (v === 'to') {
          vNew = 100;
        } else {
          vNew = parseFloat(v);
        }
        r.offset = vNew;
        kfi.declarations.forEach(function(d) {
          r[d.property] = d.value;

        });
        result[kf.name].push(r);
      });
    });
  });
  console.log(result);

EDIT:

So far I was able to achieve this result in ramdajs:

    var rulesLense = R.lensPath(['stylesheet', 'rules']);
    var ruleView = R.view(rulesLense, obj);
    var keyframes = R.filter(R.propEq('type', 'keyframes'));
    var groupByKeyframe = R.groupBy(keyframe => {
        return R.prop('name', keyframe);
    });

    var process = R.pipe(
        keyframes,
        groupByKeyframe  
    );
    var result = process(ruleView);

解决方案

Traversing complex structures by using just Ramda is hard but elegant. To modify a structure using lenses, applySpec and evolve is recommendable, these are very useful to return a new version of objects with modified values. But you are looking to transform the data in something very different to the original tree, which I assume is an AST. In Ramda, pipe and compose are essentials, it makes possible to structure the code by composing small functions. For working with trees I use converge for branching, objOf and zipObj to create new objects. Also map and reduce to work with lists.

I'm going to use the following composition strategy in this example:

          transformAST
               ^
               |
               |
      getContentOfKeyframes
         ^              ^
         |              |
         |              |
  processKeyframe   processAnimation

To start with, let's create a function that receives an array of values and an array of declarations, it returns an array which in the first position has an array of converted values, in the second position an object where the keys are the value of declaration property and the values are its corresponding declaration value.

var processKeyframe = (vals, declarations) => [
    // map each value
    R.map(R.cond([
        [R.equals('from'), R.always(0)],
        [R.equals('to'), R.always(100)],
        [R.T, parseFloat]
    ]), vals),
    // collect all property value pairs and merge in one object
    R.reduce(R.merge, {},
        R.map(R.converge(R.objOf, [
            R.prop('property'),
            R.prop('value')
        ]), declarations))
]

Now let's create a function to process animations, it receives an array of offsets and an object with transformations, returns an array of new objects with the signature {offset: offset, ...trasformations}.

var processAnimation = (offsets, transf) => 
    R.map(R.pipe(
        R.objOf('offset'), 
        R.merge(transf)), offsets)

Next, map each keyframe by composing the two previous functions

var getContentOfKeyframes = R.map(R.pipe(
    // process keyframes
    R.converge(processKeyframe, [
        R.prop('values'),
        R.prop('declarations')
    ]),
    // process animations
    R.converge(processAnimation, [
        R.nth(0),
        R.nth(1)
    ])))

Finally, we define function that gets the needed properties from data, summarizes, each keyframe and finally gives the desired format in the last stage.

var transformAST = R.pipe(
    // get `stylesheet.rules` property
    R.path(['stylesheet', 'rules']),
    // get only object whose `type` property is `keyframes`
    R.filter(R.propEq('type', 'keyframes')), 
    // map each item in `keyframes` collection
    // to an object {name: keyframe.name, content: [contentOfkeyframes] }
    R.map((keyframe) => ({
        name    : keyframe.name,
        content : getContentOfKeyframes(keyframe.keyframes)
    })),
    // finally make a new object using animation `name` as keys
    // and using a flatten content as values
    R.converge(R.zipObj, [
        R.map(R.prop('name')),
        R.map(R.pipe(R.prop('content'), R.flatten))
    ]))

Now you can process the AST directly passing the data object.

var result = transformAST(data)

All together.

var processKeyframe = (vals, declarations) => [
    R.map(R.cond([
        [R.equals('from'), R.always(0)],
        [R.equals('to'), R.always(100)],
        [R.T, parseFloat]
    ]), vals),
    R.reduce(R.merge, {},
        R.map(R.converge(R.objOf, [
            R.prop('property'),
            R.prop('value')
        ]), declarations))
]

var processAnimation = (offsets, transf) => 
    R.map(R.pipe(
        R.objOf('offset'), 
        R.merge(transf)), offsets)

var getContentOfKeyframes = R.map(R.pipe(
    R.converge(processKeyframe, [
        R.prop('values'),
        R.prop('declarations')
    ]),
    R.converge(processAnimation, [
        R.nth(0),
        R.nth(1)
    ])))

var transformAST = R.pipe(
    R.path(['stylesheet', 'rules']),
    R.filter(R.propEq('type', 'keyframes')), 
    R.map((keyframe) => ({
        name    : keyframe.name,
        content : getContentOfKeyframes(keyframe.keyframes)
    })),
    R.converge(R.zipObj, [
        R.map(R.prop('name')),
        R.map(R.pipe(R.prop('content'), R.flatten))
    ]))

var result = transformAST(data)

这篇关于使用Ramdajs将Imperative转换为功能风格范例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆