Skip to content

Commit ba0c5d3

Browse files
authored
Merge pull request #2 from satotake/prototype
prototyping
2 parents 973fb5f + 8d4e22f commit ba0c5d3

File tree

3 files changed

+220
-13
lines changed

3 files changed

+220
-13
lines changed

__tests__/jp-numerals.ts

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,111 @@
1-
import DummyClass from "../src/jp-numerals"
1+
import { jpNumerals, Numeral, NumeralZero } from '../src/jp-numerals'
2+
import { JpNumeralUnit } from '../src/type'
23

3-
/**
4-
* Dummy test
5-
*/
6-
describe("Dummy test", () => {
7-
it("works if true is truthy", () => {
8-
expect(true).toBeTruthy()
4+
describe('Numeral Class', () => {
5+
it('can handle integer', () => {
6+
const n = new Numeral(JpNumeralUnit., 123_4567)
7+
expect(n.unit).toEqual(JpNumeralUnit.)
8+
expect(n.raw).toEqual(123_4567)
9+
10+
expect(n.rank).toEqual(1)
11+
expect(n.digits).toEqual(123)
12+
expect(n.character).toEqual('万')
13+
14+
expect(n.toString()).toEqual('123万')
15+
expect(n.toNumeralObj()).toEqual({
16+
unit: JpNumeralUnit.,
17+
character: '万',
18+
rank: 1,
19+
digits: 123
20+
})
21+
})
22+
23+
it('can handle float', () => {
24+
const n = new Numeral(JpNumeralUnit., 123_4567.789)
25+
expect(n.raw).toEqual(123_4567.789)
26+
27+
expect(n.digits).toEqual(123)
28+
expect(n.character).toEqual('万')
29+
30+
expect(n.toNumeralObj()).toEqual({
31+
unit: JpNumeralUnit.,
32+
character: '万',
33+
rank: 1,
34+
digits: 123
35+
})
36+
})
37+
38+
it('raise error if number is negative', () => {
39+
expect(() => new Numeral(JpNumeralUnit., -123_4567.789)).toThrow()
40+
})
41+
})
42+
43+
describe('class NumeralZero', () => {
44+
it('exclude "零" for stringification', () => {
45+
const n = new NumeralZero(JpNumeralUnit., 123_4567)
46+
expect(n.toString()).toEqual('4567')
47+
})
48+
49+
it('can display decimal number', () => {
50+
const n = new NumeralZero(JpNumeralUnit., 123_4567.89)
51+
expect(n.toString()).toEqual('4567.89')
952
})
53+
})
54+
55+
describe('jpNumerals', () => {
56+
it('can handle integer', () => {
57+
const n = jpNumerals(12_3456_7890)
58+
expect(n.toTuples()).toEqual([[12, '億'], [3456, '万'], [7890, '']])
59+
60+
expect(n.toArray()).toEqual([
61+
new Numeral(JpNumeralUnit., 12_3456_7890),
62+
new Numeral(JpNumeralUnit., 12_3456_7890),
63+
new Numeral(JpNumeralUnit., 12_3456_7890)
64+
])
65+
66+
expect(n.toNumeralObjs()).toEqual([
67+
{
68+
unit: JpNumeralUnit.,
69+
character: '億',
70+
rank: 2,
71+
digits: 12
72+
},
73+
{
74+
unit: JpNumeralUnit.,
75+
character: '万',
76+
rank: 1,
77+
digits: 3456
78+
},
79+
{
80+
unit: JpNumeralUnit.,
81+
character: '',
82+
rank: 0,
83+
digits: 7890
84+
}
85+
])
86+
87+
expect(n.toString()).toEqual('12億3456万7890')
88+
expect(n.toNumber()).toEqual(1234567890)
89+
})
90+
91+
it('can handle float', () => {
92+
const n = jpNumerals(12_3456_7890.123)
93+
expect(n.toTuples()).toEqual([[12, '億'], [3456, '万'], [7890.123, '']])
94+
})
95+
96+
it('throw error if number is negative', () => {
97+
expect(() => jpNumerals(-12_3456_7890.123)).toThrow()
98+
})
99+
100+
it('can use base as option', () => {
101+
const n_base = jpNumerals(12_3456, JpNumeralUnit.)
102+
const n = jpNumerals(12_3456_0000)
103+
104+
expect(n_base.toTuples()).toEqual(n.toTuples())
105+
expect(n_base.toArray()).toEqual(n.toArray())
106+
expect(n_base.toNumeralObjs()).toEqual(n.toNumeralObjs())
10107

11-
it("DummyClass is instantiable", () => {
12-
expect(new DummyClass()).toBeInstanceOf(DummyClass)
108+
expect(n_base.toString()).toEqual(n.toString())
109+
expect(n_base.toNumber()).toEqual(1234560000)
13110
})
14111
})

src/jp-numerals.ts

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,78 @@
1-
// Import here Polyfills if needed. Recommended core-js (npm i -D core-js)
2-
// import "core-js/fn/array.find"
3-
// ...
4-
export default class DummyClass {
1+
import { JpNumeralUnit, NumeralObj, Numerals } from './type'
52

3+
export class Numeral {
4+
raw: number
5+
unit: JpNumeralUnit
6+
constructor(unit: JpNumeralUnit, raw: number) {
7+
if (raw < 0) {
8+
throw Error('Number must be positive or 0')
9+
}
10+
11+
this.raw = raw
12+
this.unit = unit
13+
}
14+
15+
get character(): string {
16+
return JpNumeralUnit[this.unit]
17+
}
18+
19+
get rank(): number {
20+
return this.unit
21+
}
22+
23+
get digits(): number {
24+
return Math.floor(this.raw / Math.pow(10, this.rank * 4)) % Math.pow(10, 4)
25+
}
26+
27+
toString(): string {
28+
return `${this.digits}${this.character}`
29+
}
30+
toNumeralObj(): NumeralObj {
31+
const { unit, character, rank, digits } = this
32+
return { unit, character, rank, digits }
33+
}
34+
}
35+
36+
export class NumeralZero extends Numeral {
37+
get character(): string {
38+
return ''
39+
}
40+
41+
get digits(): number {
42+
const factor = 10 ** this.scale
43+
const val = (this.raw / Math.pow(10, this.rank * 4)) % Math.pow(10, 4)
44+
return Math.round(val * factor) / factor
45+
}
46+
47+
// TODO handling decimal points
48+
private get scale(): number {
49+
const s = this.raw.toString()
50+
return s.includes('.') ? s.split('.')[1].length : 0
51+
}
52+
}
53+
54+
export const jpNumerals = (n: number, base: JpNumeralUnit = JpNumeralUnit.): Numerals => {
55+
// TODO(handle negative)
56+
if (n < 0) {
57+
throw Error('number must be string')
58+
}
59+
60+
const raw = Math.abs(n) * Math.pow(10, base * 4)
61+
// in myriads
62+
63+
const unitLen = Object.keys(JpNumeralUnit).length / 2
64+
const numberLen = Math.ceil(Math.log10(raw) / 4)
65+
const len = Math.min(unitLen, numberLen)
66+
const numerals = new Array(len)
67+
.fill(NaN)
68+
.map((_, i) => (i === 0 ? new NumeralZero(i, raw) : new Numeral(i, raw)))
69+
.reverse()
70+
71+
return {
72+
toArray: () => numerals,
73+
toTuples: () => numerals.map(numeral => [numeral.digits, numeral.character]),
74+
toNumeralObjs: () => numerals.map(numeral => numeral.toNumeralObj()),
75+
toString: () => numerals.reduce((s, numeral) => `${s}${numeral}`, ''),
76+
toNumber: () => raw
77+
}
678
}

src/type.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Numeral } from './jp-numerals'
2+
3+
export enum JpNumeralUnit {
4+
,
5+
6+
,
7+
,
8+
,
9+
,
10+
,
11+
,
12+
,
13+
,
14+
,
15+
,
16+
,
17+
,
18+
恒河沙,
19+
阿僧祇,
20+
那由他,
21+
不可思議,
22+
無量大数
23+
}
24+
25+
export interface NumeralObj {
26+
unit: JpNumeralUnit
27+
character: string
28+
rank: number
29+
digits: number
30+
}
31+
32+
export interface Numerals {
33+
toArray: () => Numeral[]
34+
toTuples: () => [number, string][]
35+
toNumeralObjs: () => NumeralObj[]
36+
toString: () => string
37+
toNumber: () => number
38+
}

0 commit comments

Comments
 (0)