Ramda, find value in sub array - ramda.js

My previous javascript underscore function:
export const getQuantity = (obj, name: string) => {
const quantityInIfcObject = _.findWhere(obj.quantities, { name: quantity });
return quantityInIfcObject ? quantityInIfcObject.value : null;
};
const quantity = getQuantity(obj, 'area');
What would a Ramda-version of this look like?
Tried this:
export const getQuantity = (name) => R.pipe(
R.map((o: IIfcObject) => o.quantities),
R.find(R.propEq('name', name)),
R.map((q: IIfcQuantity) => q.value)
)(quantity);
const quantity = getQuantity(obj, 'area');
Not working. In the examples I've read of pipe there's no arguments. Maybe wrong to use pipe here?

You should get the quantities (R.prop), find the name, and get the value if exists, or null if it doesn't:
export const getQuantity = (name) => R.pipe(
R.prop('quantities'),
R.find(R.propEq('name', name)),
R.propOr(null, 'value'),
)(quantity);
Calling the function is a two steps process, since R.pipe returns a function when invoked. When you call getQuantity('area'), R.pipe will return a function. That function expects an object to operate on:
const getQuantityForArea = getQuantity('area');
const quantity = getQuantityForArea(obj);
You can call it in one step by combining both calls:
const quantity = getQuantity('area')(obj);

Related

calling an array method on a computed property

I have an array:
const arr = []
I then have a computed property:
const filtered_arr = computed(() => {
//...
}
I then have another computed property: filtered_arr2 where I want to call some() method on the first filtered_arr.
But getting errors since filtered_arr is not an actual array.
const filtered_arr2 = computed(() => {
filtered_arr.some((e)=>{}) // <- error
}
UPDATED:
Getting several errors :
some is not a function
Container is not set or can not be properly recognized. Use container() method to set it
I think my whole approach is buggy...
From the API documentation...
computed()#
Takes a getter function and returns a readonly reactive ref object
and
ref()#
Takes an inner value and returns a reactive and mutable ref object, which has a single property .value that points to the inner value
So with that in mind, you'll need to use the .value property within your setup
const filtered_arr = computed(() => {
// return some array
});
const filtered_arr2 = computed(() => {
const isPresent = filtered_arr.value.some(...);
// return some other value
});

VeeValidate use custom rule globally

I have a custom veevalidate rule that I use to see if the value entered is already in an array in that component. I want to use this rule in different components with different arrays. Is there a way to do this? Here is my current rule in just one component
const isUnique = (value) => {
const reg = new RegExp(`^${value}$`, 'i');
const inputValue = this.myArray.filter(str => reg.test(str));
if (inputValue.length > 0) {
return {
valid: false,
data: {
message: `The ${inputValue} already exists.`,
},
};
}
return { valid: true };
};
Validator.extend('unique', {
validate: isUnique,
getMessage: (field, params, data) => data.message,
});
You sure can - either you can use the existing rule called oneOf which is documented here, or you can change your rule to accept parameters. It looks like your rule is case-insensitive, so probably you'd want to stick with that. All you would need to do is accept a 2nd parameter to your isUnique function and then use that instead of this.myArray:
const isUnique = (value, values) => {
const reg = new RegExp(`^${value}$`, 'i');
const inputValue = values.filter(str => reg.test(str));
Then in your template, you would call it like this:
<ValidationProvider :rules="{isUnique:myArray}">

Return last item in an Object of arrays via a computed property?

I am trying to create a computed property that will return just the filename in a string (basically, just returning the last item in an array)
I have a data object named attachments like so:
{"abcAttachments":["abc/2019/301902007/acme.pdf","abc/2019/201123007/abc.pdf"],"attachments":["attachments/2019/2da007/hello.png","attachments/2019/2320002007/blue.png"]}
What I want to do is return only the filenames from the above Object of arrays, not the entire path of the filenames. For instance, just acme.pdf and not abc/2019/301902007/acme.pdf
Thus, I tried to do the following computed property:
filenames() {
const files = this.attachments.attachments
const newArr = files.map(x => x.split('/'))
return newArr[newArr.length - 1]
}
The above code does not just return the last item (it lists all the items). Any tips on how I can get this to work?
You need to slightly modify your map function:
See JSFiddle:
https://jsfiddle.net/bwrymeha/
var obj = {"abcAttachments":["abc/2019/301902007/acme.pdf","abc/2019/201123007/abc.pdf"],"attachments":["attachments/2019/2da007/hello.png","attachments/2019/2320002007/blue.png"]};
let result = obj.attachments.map((item) => {
// First split using '/', then return the last item of that split
// which should be the filename.
let split = item.split('/');
return split[split.length - 1];
});
alert(result);
// returns ['hello.png','blue.png']
If you need just filename from all attachments you need to do the following:
filenames() {
const result = []
const files = this.attachments
Object.keys(files).forEach(key => {
// Here we have "abcAttachments" and "attachments" as "key"
files[key].map(file => {
// Split every file by '/'
const arr = file.split('/')
if (arr.length) {
result.push(arr[arr.length - 1])
}
})
})
return result
}

Sinon stub withArgs ignores extra arguments

My production code looks like:
exports.convertWord = number => { /* some logic here */ }
exports.methodUnderTest = () => {
return exports.convertWord(1);
}
Test code:
const mockConvertToWord = sinon.stub();
mockConvertToWord.withArgs(1).returns('one');
fileUnderTest.convertWord = mockConvertToWord;
const result = fileUnderTest.methodUnderTest();
expect(result).toBeEqual('one');
Test above is green. I expect my test will break if I change prod code to this:
exports.convertWord = number => { /* some logic here */ }
exports.methodUnderTest = () => {
return exports.convertWord(1, 'another arg');
}
but it's not. Sinon works fine even when I pass extra params which I didn't point in withArgs method. How can I tell sinon to return value only when method has been called with exact number of params?
stub
One way to do this is to use stub.callsFake(fakeFunction):
mockConvertToWord.callsFake((...args) => args.length === 1 && args[0] === 1 ? 'one' : undefined);
An alternative approach with a stub is to use a sinon.assert to make sure the stub was called with the epected arguments as noted by #deerawan.
mock
Another approach is to use a mock:
const mock = sinon.mock(fileUnderTest);
mock.expects('convertWord').withExactArgs(1).returns("one");
const result = fileUnderTest.methodUnderTest();
expect(result).toBeEqual('one');
mock.verify();
Another alternative, perhaps you can try to check the call of convertToWord like
...
expect(result).toBeEqual('one');
// check the function
sinon.assert.alwaysCalledWithExactly(mockConvertToWord, '1');
Ref:
https://sinonjs.org/releases/v6.3.4/assertions/#sinonassertalwayscalledwithexactlyspy-arg1-arg2-
Hope it helps

Vuex Getters Method Style How to Return Function

According to the Vuex documentation, you can pass a payload to a getter method as long as the method returns a function.
https://vuex.vuejs.org/en/getters.html
I'm unclear on how I can format a function that returns a function.
In my case, I'd like to pass a product object to a getter method and use the product.price data along with data in the state to return a calculated price.
Here's a stripped down version of the approach I have currently:
const store = new Vuex.Store({
state: {
product: {
price: 12.99,
},
colors_front: 1,
colors_back: 0,
},
getters: {
printPrice: (state) => (product) => {
return (state, product) => {
var colors_front = state.print_product.colors_front,
colors_back = state.print_product.colors_back;
print_price = parseFloat(product.price) + parseFloat(colors_front * 2.25) + parseFloat(colors_back * 2.25);
return parseFloat(print_price).toFixed(2);
}
},
}
}
When I try to access this getter in my component, I'm receiving the code of the function as a text string.
<template>
<div>{{ printPrice(product) }}</div>
</template>
export default {
computed: {
...mapState(['product']),
...mapGetters(['printPrice']),
}
}
Can anyone help me understand getters that return functions better? Is there a more appropriate way to do this?
I figured since I'm not actually mutating the state data, this method belonged better as a getter than a mutator, but I'm open to all suggestions.
Thanks!
Problem is that your getter is returning a function that also returns a function, so, when Vuex runs the function, it returns another one which seems to be cast to string (maybe by the template parser?).
Just make sure to return one single function with the expected output by changing this:
printPrice: (state) => (product) => {
return (state, product) => {
var colors_front = state.print_product.colors_front,
colors_back = state.print_product.colors_back;
print_price = parseFloat(product.price) + parseFloat(colors_front * 2.25) + parseFloat(colors_back * 2.25);
return parseFloat(print_price).toFixed(2);
}
},
to this:
printPrice: (state) => (product) => {
var colors_front = state.print_product.colors_front,
colors_back = state.print_product.colors_back;
print_price = parseFloat(product.price) + parseFloat(colors_front * 2.25) + parseFloat(colors_back * 2.25);
return parseFloat(print_price).toFixed(2);
},
That way we removed the wrapping function in the first level returning function.