These are chat archives for ramda/ramda

5th
Sep 2016
Matt Stewart
@mattste
Sep 05 2016 05:51

Anyone have advice on mapping from one object form to another?

const inputData = {
  id: "userId",
  email: "email@email.com",
  phone: "+11111111",
  firstName: "John",
  elastName: "Madden",
  displayFirst: "Coach",
  displayLast: "Madden",
  teams: ["Celtics”, "Manchester"]
}

const outputData = {
  id: "userId",
  userInfo: {
    local: {
      firstName: "John",
      lastName: "Madden",
      email: "email@email.com",
      phone: "+1111111",
    },
    displayFirst: "Coach",
    displayLast: "Madden",
    teams: ["Celtics", "Manchester"]
  }
}

I originally reached for lenses, but it looks like lens(getter, setter) doesn’t let you change the path used for the setter. My code looked very messy to make something work. An added bonus would be an easy way to convert back to the other format.

Aldwin Vlasblom
@Avaq
Sep 05 2016 07:37
@mattste Might have a look at;
R.applySpec
Matt Stewart
@mattste
Sep 05 2016 07:38
@Avaq "creates a function producing an object of the same structure” how can I fix that part?
Aldwin Vlasblom
@Avaq
Sep 05 2016 07:39
const inutToOutut = applySpec({
  id: prop('id'),
  userInfo: applySpec({ local: applySpec({ firstName: prop('firstName') }) }),
  //...etc
})
inutToOutut(input) //output
Matt Stewart
@mattste
Sep 05 2016 07:42
Hmm. What does this extra verbosity get me over just doing a normal JS mapping such as userInfo: { local: { firstName: data.firstName} }?
Aldwin Vlasblom
@Avaq
Sep 05 2016 07:42
Alternatively, you could just use a closure:
const inputToOutput = x => ({
  id: x.id,
  userInfo: { local: { firstName: x.firstName } }
})
Matt Stewart
@mattste
Sep 05 2016 07:42
(Sorry, rather new to FP and Ramda).
Well, the reason why I was looking at lenses is because I also want to do some validation checks. So I wanted to just say “get firstname with this lens, then run these functions, then set it on this path on the destination"
I could always do the mapping as you propose then the validation stuff separately using lenses, but was wondering if there were any more elegant options.
Aldwin Vlasblom
@Avaq
Sep 05 2016 07:45
I'm not familiar with this per-value kind of validation/mapping approach. Personally I usually: 1. Validate input structure; 2. Map to output structure; 3. Validate output structure. I use something like tcomb or sanctuary-def to define business rules for structure validation.
const inputToOutput = pipe(
  UserDatabaseRecord, //ensure input is correct using a tcomb interface
  mapper, //map to other structure
  User //ensure output is correct using a tcomb interface
)
Something like that. I'd be interested to see other peoples answers to your question though. :)
Matt Stewart
@mattste
Sep 05 2016 07:49
Both of those look very interesting. Thank you for that. This is definitely an area where I wish I had types (although I’d still have to deal with the mapping between). I’m curious why validate the output? I would need a step there to map back to the original input form.
Syaiful Bahri
@syaiful6
Sep 05 2016 09:29
@mattste what's do you mean by change the path? Rambda's Lens implementation is minimalist as far as i know, maybe you should look https://github.com/fantasyland/fantasy-lenses, it allow you to combine your lens, example: run location lens then firstName lens, so it possible to run your firstName on your input structure then reuse it for your output.
Churchill Lee
@FeliciousX
Sep 05 2016 13:31
if you have an array of functions
how would u run all of those functions? using the same value as argument?
const fns = [ fn... ];

fns.forEach( fn => fn ( x ) )
is there a ramda operator that does that?
.ap ?
R.ap([ fns ], [ x ] )
Tushar Mathur
@tusharmath
Sep 05 2016 13:39
Screen Shot 2016-09-05 at 7.08.24 PM.png
Ramda's compose function gets bailed out by chrome.
Is there a way to fix this?
Churchill Lee
@FeliciousX
Sep 05 2016 13:41
R.ap( arrayOfFns, R.of( x ) )
Denis Stoyanov
@xgrommx
Sep 05 2016 14:06
R.sequence(always, arrayOfFns)(x))
R.converge(() =>{}, arrayOfFns)(x)
Rafe
@rjmk
Sep 05 2016 15:19
@tusharmath I believe that issues is caused by properties being attached to functions. I don't know if that happens within Ramda but it's quite common in a lot of codebases. I'm not sure how to get around it
Tushar Mathur
@tusharmath
Sep 05 2016 15:50
@rjmk Thanks for that link. Really helpful
James Forbes
@JAForbes
Sep 05 2016 23:18
@FeliciousX R.ap([ x ], fns)
Scott Christopher
@scott-christopher
Sep 05 2016 23:46
@syaiful6 The lenses available in Ramda can also be composed.
@ram-bot
const L = compose(lensProp('x'), lensProp('y'), lensProp('z'))
const sqXYZ = over(L, x => x * x)
sqXYZ({ x: { y: { z: 5 }}})
ram-bot
@ram-bot
Sep 05 2016 23:47
{ x: { y: { z: 25 } } }
Scott Christopher
@scott-christopher
Sep 05 2016 23:49
https://github.com/ramda/ramda-lens also exists if you're after something a bit more featureful.
Or if you want a batteries-included option https://github.com/flunc/optics
Matt Stewart
@mattste
Sep 05 2016 23:52
@scott-christopher do you know if any of those let you specify the path used for the lens’s setter function (preferrably itself a lens)?
Scott Christopher
@scott-christopher
Sep 05 2016 23:53
@ram-bot
const L = lensPath(['x', 'y', 'z'])
const sqXYZ = over(L, x => x * x)
sqXYZ({ x: { y: { z: 5 }}})
ram-bot
@ram-bot
Sep 05 2016 23:53
{ x: { y: { z: 25 } } }
Scott Christopher
@scott-christopher
Sep 05 2016 23:53
@mattste do you mean like that ^
Matt Stewart
@mattste
Sep 05 2016 23:57
Not quite. Something like this:
const Lsrc = lensPath([‘firstName’])
const Ldst = lensPath(compose(lensPath[‘userInfo’, ‘local’], Lsrc))
const firstNameCapitalized = over(Lsrc, Ldst, name => capitalize(name))
firstNameCapitalized({firstName: ‘Scott’})
// { userInfo: {local: {firstName: ‘SCOTT’}}}