1
\$\begingroup\$

I have the follow matcher method that should do:

obj = {eins: 'one', zwei: 'two'}
queryA = {eins: 'one'}
queryB = {eins: 'one', zwei: 'deux'}

matcher(obj, queryA) // true
matcher(obj, queryB) // false

const matcher = curryRight(
  (state, query) => 
    flowRight([
      every(Boolean),
      map(
        (val, key) => {
          return  state[key] && state[key].match(new RegExp(val, 'ig'))
        }
      )
    ])(query)
)

Wanted: Because I plan on using this function, matcher() in filter(), it should take a query and returns a function which can take an object for equality check against that query. My version above does that, the improvement sought is can we extract the

(val, key) => { return state[key] && state[key].match(new RegExp(val, 'ig')) }

out so that I can in the future swap it out for some function which returns a boolean value?

Is there any way that the iteratee inside map may be split into two such that state is passed in separately? That way, I can refactor the .match(...) part out as a standalone function.

\$\endgroup\$
0
1
\$\begingroup\$

I have reviewed your code and I can make the following remarks:

FP concepts

I understand that you want to solve the issue of matching objects to queries. If you pass an object and a query you should be able to check if the query satisfies all parts or no. However to be honest with you you try too much in the wrong direction. All that curryRight, flowRight, partial etc are very interesting and useful but in the average programmer they don't really mean anything for the problem you are trying to tackle.

For example I was able to rewrite the code using lodash chain in 5 minutes and with better readability. I will post my code at the end but before that I'll comment a few things:

matcher(obj, queryA): Why the name matcher? What does it matches? An object, an array? I think its too generic and confusing. And why does it accepts 2 parameters? Ideally it should accept only one at the time.It should have been like makeMatcher(obj) => (query) => ... and now you would have more flexibility with naming.

const matcher = curryRight( (state, query) => flowRight([ every(Boolean), map( (val, key) => { return state[key] && state[key].match(new RegExp(val, 'ig')) } ) ])(query)

This looks too esoteric and I had to search for the documentation for both flowRight and curryRight and after that I had to run your code to the browser with breakpoints to understand the internals etc. At some point I stopped because I thought it took me enough time already and its not worth it. Its clearly too complicated to read and to understand, not only now but also in 2 years time when you revisit your code and think what exactly did you meant to do. My point is that in the current state is un-maintainable.

Anyway here is my take on this:

const makeMatcher = (obj) => (query) => {
  const matchesQuery = (val, key) => {
    return obj[key] && obj[key].includes(query[key]);
  };

  return _(query)
          .chain()
          .map(matchesQuery)
          .every(Boolean)
          .value();
}


const objMatches = makeMatcher(obj);
objMatches(queryA); // True
objMatches(queryB); // False

Note how the code speaks of its self and it doesn't have to exaggerate. Every name has a meaning with the right intent. A makeMatcher makes matchers and an objMatches returns a boolean by accepting a query and checking if its matches the query.

Inside the makeMatcher we simply chain over the query and validate that either every query parameter matches the object or in case of a mismatch we return false and that's it.

My point is that you should always have a birds eye view of your code and try to think of ways to make your work easier to handle. Search for alternatives and don't fall into the rabbit hole of applying things that they don't fit accurately. There is always a simpler method to do your job. Good luck with your FP endeavors.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the detail answer. the name matcher()b/c lodash's _.matches() takes a query then returns a func that waits for an object input. So that which matches is a matcher ;) So I should probably mention in an edit, what I wanted was a function that takes in a query, spits out a function which awaits an object input. In your implementation, which incidentally is very readable indeed, takes an object that spits out a function which awaits a query. \$\endgroup\$
    – Nik So
    Mar 2 '17 at 13:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.