refactor state for features to contain references to phones

This commit is contained in:
Sorrel Bri 2019-12-04 20:28:48 -08:00
parent 741af7f76e
commit faec991cd0
3 changed files with 79 additions and 36 deletions

View file

@ -1,13 +1,19 @@
import {stateReducer} from './stateReducer'; import {stateReducer} from './stateReducer';
describe('Features', () => { describe('Features', () => {
const state = { const state = {}
features: [ beforeEach(() => {
'low', 'high','back', 'rounded', 'sonorant', state.phones = {
'nasal', 'obstruent', 'occlusive', 'plosive', a: {features: {occlusive: true}, grapheme: 'a'},
'prenasalized', 'aspirated', 'coronal' n: {features: {occlusive: false}, grapheme: 'n'}
]
}; };
state.features = {
occlusive: {
positive: [state.phones.n],
negative: [state.phones.a]
}
};
});
it('features returned unaltered', () => { it('features returned unaltered', () => {
const action = {type: ''}; const action = {type: ''};
@ -16,7 +22,13 @@ describe('Features', () => {
it('feature addition returns new feature list', () => { it('feature addition returns new feature list', () => {
const action = {type: 'ADD_FEATURE', value: {feature: 'anterior'}}; const action = {type: 'ADD_FEATURE', value: {feature: 'anterior'}};
expect(stateReducer(state, action)).toEqual({...state, features:[...state.features, action.value.feature]}) expect(stateReducer(state, action)).toEqual(
}) {...state,
features:{...state.features,
anterior:{ positive:[], negative:[] }
}
}
);
});
}); });

View file

@ -5,15 +5,24 @@ const initState = () => {
} }
const addPhones = (phones, phone) => { const addPhones = (phones, phone) => {
let node = {} let node = {};
phone.split('').forEach((graph, index) => { phone.split('').forEach((graph, index) => {
if (index) node[graph] = {} if (index) node[graph] = {}
if (!index && !phones[graph]) phones[graph] = {} if (!index && !phones[graph]) phones[graph] = {}
node = index === 0 ? phones[graph] : node[graph]; node = index === 0 ? phones[graph] : node[graph];
if (index === phone.length - 1) node.grapheme = phone;
}) })
return phones; return phones;
} }
const findPhone = (phones, phone) => {
let node;
phone.split('').forEach((graph, index) => {
node = index === 0 ? phones[graph] : node[graph];
});
return node;
}
const addFeatureToPhone = (phones, phone, featureKey, featureValue) => { const addFeatureToPhone = (phones, phone, featureKey, featureValue) => {
let node = {} let node = {}
phone.split('').forEach((graph, index) => { phone.split('').forEach((graph, index) => {
@ -44,20 +53,38 @@ const stateReducer = (state, action) => {
} }
case 'ADD_FEATURE': { case 'ADD_FEATURE': {
let newFeature = action.value.feature;
let positivePhones = action.value.positivePhones || []; let positivePhones = action.value.positivePhones || [];
let negativePhones = action.value.negativePhones || []; let negativePhones = action.value.negativePhones || [];
let newFeatureName = action.value.feature;
let newPhoneObject = [ let newPhoneObject = [
...positivePhones, ...negativePhones ...positivePhones, ...negativePhones
].reduce((phoneObject, phone) => addPhones(phoneObject, phone), state.phones) ].reduce((phoneObject, phone) => addPhones(phoneObject, phone), state.phones)
if (positivePhones) positivePhones = positivePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeature, true) if (positivePhones) {
, newPhoneObject);
if (negativePhones) negativePhones = negativePhones.reduce( positivePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeature, false) (phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, true)
, newPhoneObject); , newPhoneObject
return {...state, features:[...state.features, newFeature], phones: newPhoneObject} );
positivePhones = positivePhones.map( positivePhone => findPhone(newPhoneObject, positivePhone) )
// console.log(positivePhones)
}
if (negativePhones) {
negativePhones.reduce(
(phoneObject, positivePhone) => addFeatureToPhone(phoneObject, positivePhone, newFeatureName, false)
, newPhoneObject
);
negativePhones = negativePhones.map( negativePhone => findPhone(newPhoneObject, negativePhone) )
// console.log(negativePhones)
}
let newFeature = {[action.value.feature]: {positive: positivePhones, negative: negativePhones}};
return {...state, features:{...state.features, ...newFeature}, phones: newPhoneObject}
} }
default: default:

View file

@ -1,17 +1,16 @@
import {stateReducer} from './stateReducer'; import {stateReducer} from './stateReducer';
describe('Phones', () => { describe('Phones', () => {
const n_phone = {features: {nasal: true}} const n_phone = {features: {nasal: true}, grapheme: 'n'};
const state = { const state = {};
features: [
'nasal'
],
phones: { n: n_phone }
};
beforeEach(()=> { beforeEach(()=> {
state.features = [ 'nasal' ];
state.phones= { n: n_phone }; state.phones= { n: n_phone };
state.features = {
nasal: {
positive: [state.phones.n],
negative: []
}
};
}) })
it('phones returned unaltered', () => { it('phones returned unaltered', () => {
@ -23,7 +22,7 @@ describe('Phones', () => {
const action = {type: 'ADD_FEATURE', value: {feature: 'anterior', positivePhones: ['n']}}; const action = {type: 'ADD_FEATURE', value: {feature: 'anterior', positivePhones: ['n']}};
expect(stateReducer(state, action)).toEqual( expect(stateReducer(state, action)).toEqual(
{...state, {...state,
features:[...state.features, action.value.feature], features:{...state.features, anterior: { positive: [state.phones.n], negative: [] }},
phones:{...state.phones, n:{...state.phones.n, features: {...state.phones.n.features, anterior: true}}} phones:{...state.phones, n:{...state.phones.n, features: {...state.phones.n.features, anterior: true}}}
} }
) )
@ -33,8 +32,8 @@ describe('Phones', () => {
const action = {type: 'ADD_FEATURE', value: {feature: 'sonorant', negativePhones: ['t']}}; const action = {type: 'ADD_FEATURE', value: {feature: 'sonorant', negativePhones: ['t']}};
expect(stateReducer(state, action)).toEqual( expect(stateReducer(state, action)).toEqual(
{...state, {...state,
features:[...state.features, action.value.feature], features:{...state.features, sonorant: { positive: [], negative: [state.phones.t] }},
phones:{...state.phones, t:{features:{sonorant: false}}} phones:{...state.phones, t:{features:{sonorant: false}, grapheme: 't'}}
} }
); );
}); });
@ -43,9 +42,9 @@ describe('Phones', () => {
const action = {type: 'ADD_FEATURE', value: {feature: 'sonorant', positivePhones: ['n'], negativePhones: ['t']}}; const action = {type: 'ADD_FEATURE', value: {feature: 'sonorant', positivePhones: ['n'], negativePhones: ['t']}};
expect(stateReducer(state, action)).toEqual( expect(stateReducer(state, action)).toEqual(
{...state, {...state,
features:[...state.features, action.value.feature], features:{...state.features, sonorant: { positive: [state.phones.n], negative: [state.phones.t] }},
phones:{...state.phones, phones:{...state.phones,
t:{features:{sonorant: false}}, t:{features:{sonorant: false}, grapheme: 't'},
n:{...state.phones.n, features: {...state.phones.n.features, sonorant: true}} n:{...state.phones.n, features: {...state.phones.n.features, sonorant: true}}
} }
} }
@ -56,11 +55,16 @@ describe('Phones', () => {
const action = {type: 'ADD_FEATURE', value: {feature: 'aspirated', positivePhones: ['ntʰ'], negativePhones: ['n','t']}}; const action = {type: 'ADD_FEATURE', value: {feature: 'aspirated', positivePhones: ['ntʰ'], negativePhones: ['n','t']}};
expect(stateReducer(state, action)).toEqual( expect(stateReducer(state, action)).toEqual(
{...state, {...state,
features:[...state.features, action.value.feature], features:{...state.features,
aspirated: {
positive: [state.phones.n.t.ʰ],
negative: [state.phones.n, state.phones.t]
}
},
phones:{...state.phones, phones:{...state.phones,
t:{features:{aspirated: false}}, t:{features:{aspirated: false}, grapheme: 't'},
n:{...state.phones.n, features: {...state.phones.n.features, aspirated: false}, n:{...state.phones.n, features: {...state.phones.n.features, aspirated: false},
t: {ʰ:{features:{aspirated:true}}} t: {ʰ:{features:{aspirated:true}, grapheme: 'ntʰ'}}
} }
} }
} }