strings-numeral 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +327 -0
- data/Rakefile +8 -0
- data/lib/strings-numeral.rb +1 -0
- data/lib/strings/numeral.rb +557 -0
- data/lib/strings/numeral/configuration.rb +58 -0
- data/lib/strings/numeral/extensions.rb +45 -0
- data/lib/strings/numeral/version.rb +7 -0
- data/strings-numeral.gemspec +34 -0
- data/tasks/console.rake +11 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +34 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0c3b788a344901a4da93755096f0c7657e6a28218ad6dc419eafcbc61be0aa98
|
4
|
+
data.tar.gz: 220f0401d2d1c6c4d1f39c01509a9265e142ab418f80a5e6339134c60d2e46ca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 959a8ccf4432fafb017afe51c8b27fddacd1d4ec8cbe672067ffe74dc15f22ec0c51955403382e8640a2826923044fba78ab894f385f8bb134afda9869934fe2
|
7
|
+
data.tar.gz: 263c41b90e351ffbcb5acc7905fecfff6a63c42d8dbd1b8f8ceaad0854291b7bec76fef55423443b2d54a6f78f7fc3ccd2973965a8ac1993b2b3095d893b928a
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Piotr Murach
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,327 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<img width="225" src="https://github.com/piotrmurach/strings/blob/master/assets/strings_logo.png" alt="strings logo" />
|
3
|
+
</div>
|
4
|
+
|
5
|
+
# Strings::Numeral
|
6
|
+
|
7
|
+
[![Gem Version](https://badge.fury.io/rb/strings-numeral.svg)][gem]
|
8
|
+
[![Build Status](https://secure.travis-ci.org/piotrmurach/strings-numeral.svg?branch=master)][travis]
|
9
|
+
[![Build status](https://ci.appveyor.com/api/projects/status/494htkcankqegwtg?svg=true)][appveyor]
|
10
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/de0c5ad1cba6715b7135/maintainability)][codeclimate]
|
11
|
+
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/strings-numeral/badge.svg?branch=master)][coverage]
|
12
|
+
[![Inline docs](http://inch-ci.org/github/piotrmurach/strings-numeral.svg?branch=master)][inchpages]
|
13
|
+
|
14
|
+
[gem]: http://badge.fury.io/rb/strings-numeral
|
15
|
+
[travis]: http://travis-ci.org/piotrmurach/strings-numeral
|
16
|
+
[appveyor]: https://ci.appveyor.com/project/piotrmurach/strings-numeral
|
17
|
+
[codeclimate]: https://codeclimate.com/github/piotrmurach/strings-numeral/maintainability
|
18
|
+
[coverage]: https://coveralls.io/github/piotrmurach/strings-numeral?branch=master
|
19
|
+
[inchpages]: http://inch-ci.org/github/piotrmurach/strings-numeral
|
20
|
+
|
21
|
+
> Express numbers as string numerals.
|
22
|
+
|
23
|
+
**Strings::Numeral** provides conversions of numbers to numerals component for [Strings](https://github.com/piotrmurach/strings).
|
24
|
+
|
25
|
+
## Features
|
26
|
+
|
27
|
+
* No monkey-patching String class
|
28
|
+
* Functional API that can be easily wrapped by other objects
|
29
|
+
* Instance based configuration
|
30
|
+
* Highly performant
|
31
|
+
|
32
|
+
## Installation
|
33
|
+
|
34
|
+
Add this line to your application's Gemfile:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
gem 'strings-numeral'
|
38
|
+
```
|
39
|
+
|
40
|
+
And then execute:
|
41
|
+
|
42
|
+
$ bundle
|
43
|
+
|
44
|
+
Or install it yourself as:
|
45
|
+
|
46
|
+
$ gem install strings-numeral
|
47
|
+
|
48
|
+
## Contents
|
49
|
+
|
50
|
+
* [1. Usage](#1-usage)
|
51
|
+
* [2. API](#2-api)
|
52
|
+
* [2.1 numeralize](#21-numeralize)
|
53
|
+
* [2.2 cardinalize](#22-cardinalize)
|
54
|
+
* [2.3 ordinalize](#23-ordinalize)
|
55
|
+
* [2.4 monetize](#24-monetize)
|
56
|
+
* [2.5 romanize](#25-romanize)
|
57
|
+
* [2.6 configuration](#26-configuration)
|
58
|
+
* [3. Extending core classes](#3-extending-core-classes)
|
59
|
+
|
60
|
+
## 1. Usage
|
61
|
+
|
62
|
+
**Strings::Numeral** helps to express any number as a numeral in words. It exposes few methods to achieve this. For example, you can express a number as a cardinal numeral using `cardinalize`:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
Strings::Numeral.cardinalize(1234)
|
66
|
+
# => "one thousand, two hundred thirty four"
|
67
|
+
```
|
68
|
+
|
69
|
+
But you're not limited to converting integers only. It can handle decimals as well:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
Strings::Numeral.cardinalize(1234.567)
|
73
|
+
# => "one thousand, two hundred thirty four and five hundred sixty seven thousandths"
|
74
|
+
```
|
75
|
+
|
76
|
+
For more options on how to customize formatting see [configuration](#25-configuration) section.
|
77
|
+
|
78
|
+
Similarly, you can convert a number to a ordinal numeral with `ordinalize`:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Strings::Numeral.ordinalize(1234)
|
82
|
+
# => "one thousand, two hundred thirty fourth"
|
83
|
+
```
|
84
|
+
|
85
|
+
You can also convert a number to a short ordinal:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
Strings::Numeral.ordinalize(1234, short: true)
|
89
|
+
# => "1234th"
|
90
|
+
```
|
91
|
+
|
92
|
+
Using `monetize` you can convert any number into a monetary numeral:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
Strings::Numeral.monetize(1234.567)
|
96
|
+
# => "one thousand, two hundred thirty four dollars and fifty seven cents",
|
97
|
+
```
|
98
|
+
|
99
|
+
To turn a number into a roman numeral use `romanize`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Strings::Numeral.romanize(2020)
|
103
|
+
# => "MMXX"
|
104
|
+
```
|
105
|
+
|
106
|
+
## 2. API
|
107
|
+
|
108
|
+
### 2.1 numeralize
|
109
|
+
|
110
|
+
The `normalize` is a wrapping method for the [cardinalize](#22-cardinalize) and [ordinalize](#23-ordinalize) methods. By default it converts a number to cardinal numeral:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
Strings::Numeral.numeralize(1234.567)
|
114
|
+
# => "one thousand, two hundred thirty four and five hundred sixty seven thousandths"
|
115
|
+
```
|
116
|
+
|
117
|
+
You can also make it convert to ordinal numerals using `:term` option:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
Strings::Numeral.numeralize(1234.567, term: :ord)
|
121
|
+
# => "one thousand, two hundred thirty fourth and five hundred sixty seven thousandths"
|
122
|
+
```
|
123
|
+
|
124
|
+
### 2.2 cardinalize
|
125
|
+
|
126
|
+
To express a number as a cardinal numeral use `cardinalize` or `cardinalise`.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
Strings::Numeral.cardinalize(1234)
|
130
|
+
# => "one thousand, two hundred thirty four"
|
131
|
+
```
|
132
|
+
|
133
|
+
You're not limited to integers only. You can also express decimal numbers as well:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
Strings::Numeral.cardinalize(123.456)
|
137
|
+
# => "one hundred twenty three and four hundred fifty six thousandths"
|
138
|
+
```
|
139
|
+
|
140
|
+
By default the fractional part of a decimal number is expressed as a fraction. If you wish to spell out fractional part digit by digit use `:decimal` option with `:digit` value:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
Strings::Numeral.cardinalize(123.456, decimal: :digit)
|
144
|
+
# => "one hundred twenty three point four five six"
|
145
|
+
```
|
146
|
+
|
147
|
+
You may prefer to use a different delimiter for thousand's. You can do use by passing the `:delimiter` option:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Strings::Numeral.cardinalize(1_234_567, delimiter: " and ")
|
151
|
+
# => "one million and two hundred thirty four thousand and five hundred sixty seven"
|
152
|
+
```
|
153
|
+
|
154
|
+
To change word that splits integer from factional part use `:separator` option:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
Strings::Numeral.cardinalize(1_234.567, separator: "dot")
|
158
|
+
# => "one thousand, two hundred thirty four dot five hundred sixty seven thousandths"
|
159
|
+
```
|
160
|
+
|
161
|
+
### 2.3 ordinalize
|
162
|
+
|
163
|
+
To express a number as a cardinal numeral use `ordinalize` or `ordinalise`.
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
Strings::Numeral.ordinalize(1234)
|
167
|
+
# => "one thousand, two hundred thirty fourth"
|
168
|
+
```
|
169
|
+
|
170
|
+
You're not limited to integers only. You can also express decimal numbers as well:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
Strings::Numeral.ordinalize(123.456)
|
174
|
+
# => "one hundred twenty third and four hundred fifty six thousandths"
|
175
|
+
```
|
176
|
+
|
177
|
+
By default the fractional part of a decimal number is expressed as a fraction. If you wish to spell out fractional part digit by digit use `:decimal` option with `:digit` value:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
Strings::Numeral.ordinalize(123.456, decimal: :digit)
|
181
|
+
# => "one hundred twenty third point four five six"
|
182
|
+
```
|
183
|
+
|
184
|
+
You may prefer to use a different delimiter for thousand's. You can do use by passing the `:delimiter` option:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
Strings::Numeral.ordinalize(1_234_567, delimiter: " and ")
|
188
|
+
# => "one million and two hundred thirty four thousand and five hundred sixty seventh"
|
189
|
+
```
|
190
|
+
|
191
|
+
To change word that splits integer from factional part use `:separator` option:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
Strings::Numeral.ordinalize(1_234.567, separator: "dot")
|
195
|
+
# => "one thousand, two hundred thirty fourth dot five hundred sixty seven thousandths"
|
196
|
+
```
|
197
|
+
|
198
|
+
### 2.4 monetize
|
199
|
+
|
200
|
+
To express a number as a monetary numeral use `monetize` or `monetise`.
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
Strings::Numeral.monetize(123.456)
|
204
|
+
# => "one hundred twenty three dollars and forty six cents",
|
205
|
+
```
|
206
|
+
|
207
|
+
By default `monetize` displays money using `USD` currency. You can change this with the `:currency` option that as value accepts internationally recognised symbols. Currently support currencies are: `EUR`, `GBP`, `JPY`, `PLN` and `USD`.
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
Strings::Numeral.monetize(123.456, currency: :jpy)
|
211
|
+
# => "one hundred twenty three yen and forty six sen"
|
212
|
+
```
|
213
|
+
|
214
|
+
### 2.5 romanize
|
215
|
+
|
216
|
+
To convert a number into a Roman numeral use `romanize`:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
Strings::Numeral.romanize(2020)
|
220
|
+
# => "MMXX"
|
221
|
+
```
|
222
|
+
|
223
|
+
### 2.6 configuration
|
224
|
+
|
225
|
+
All available configuration options are:
|
226
|
+
|
227
|
+
* `currency` - Adds currency words for integer and fractional parts. Supports `EUR`, `GBP`, `JPY`, `PLN` and `USD`. Defaults to `USD`.
|
228
|
+
* `decimal` - Formats fractional part of a number. The `:digit` value spells out every digit and the `:fraction` appends divider word. Defaults to `:fraction`.
|
229
|
+
* `delimiter` - Sets the thousands delimiter. Defaults to `", "`.
|
230
|
+
* `separator` - Sets the separator between the fractional and integer parts. Defaults to `"and"` for `:fraction` and `"point"` for `:digit` option.
|
231
|
+
* `trailing_zeros` - If `true` keeps trailing zeros at the end of the fractional part. Defaults to `false`.
|
232
|
+
|
233
|
+
The above options can be passed as keyword arguments:
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
Strings::Numeral.cardinalize("12.100", trailing_zeros: true, decimal: :digit)
|
237
|
+
# => "twelve point one zero zero"
|
238
|
+
```
|
239
|
+
|
240
|
+
Or you can configure the options for an instance:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
numeral = Strings::Numeral.new do |config|
|
244
|
+
config.delimiter "; "
|
245
|
+
config.separator "dot"
|
246
|
+
config.decimal :digit
|
247
|
+
config.trailing_zeros true
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
Once configured, you can use the instance like so:
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
numeral.cardinalize("1234.56700")
|
255
|
+
# => "one thousand; two hundred thirty four dot five six seven zero zero"
|
256
|
+
```
|
257
|
+
|
258
|
+
## 3. Extending Core Classes
|
259
|
+
|
260
|
+
Though it is highly discouraged to pollute core Ruby classes, you can add the required methods to `String`, `Float` and `Integer` classes using refinements.
|
261
|
+
|
262
|
+
For example, if you wish to only extend `Float` class with `cardinalize` method do:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
module MyFloatExt
|
266
|
+
refine Float do
|
267
|
+
def cardinalize(**options)
|
268
|
+
Strings::Numeral.cardinalize(self, **options)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
```
|
273
|
+
|
274
|
+
Then `cardinalize` method will be available for any float number where refinement is applied:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
using MyFloatExt
|
278
|
+
|
279
|
+
12.34.cardinalize
|
280
|
+
# => "twelve and thirty four"
|
281
|
+
```
|
282
|
+
|
283
|
+
However, if you want to include all the **Strings::Numeral** methods in `Float`, `Integer` and `String` classes, you can use provided extensions file:
|
284
|
+
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
require "strings/numeral/extensions"
|
288
|
+
|
289
|
+
using Strings::Numeral::Extensions
|
290
|
+
```
|
291
|
+
|
292
|
+
Alternatively, you can choose what class you wish to refine with all the methods:
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
require "bigdecimal"
|
296
|
+
require "strings/numeral/extensions"
|
297
|
+
|
298
|
+
module MyBigDecimalExt
|
299
|
+
refine BigDecimal do
|
300
|
+
include Strings::Numeral::Extensions::Methods
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
using MyBigDecimalExt
|
305
|
+
```
|
306
|
+
|
307
|
+
## Development
|
308
|
+
|
309
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
310
|
+
|
311
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
312
|
+
|
313
|
+
## Contributing
|
314
|
+
|
315
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/strings-numeral. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
316
|
+
|
317
|
+
## License
|
318
|
+
|
319
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
320
|
+
|
321
|
+
## Code of Conduct
|
322
|
+
|
323
|
+
Everyone interacting in the Strings::Numeral project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/strings-numeral/blob/master/CODE_OF_CONDUCT.md).
|
324
|
+
|
325
|
+
## Copyright
|
326
|
+
|
327
|
+
Copyright (c) 2019 Piotr Murach. See LICENSE for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "strings/numeral"
|
@@ -0,0 +1,557 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "numeral/configuration"
|
4
|
+
require_relative "numeral/version"
|
5
|
+
|
6
|
+
module Strings
|
7
|
+
class Numeral
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
NEGATIVE = "negative"
|
11
|
+
HUNDRED = "hundred"
|
12
|
+
ZERO = "zero"
|
13
|
+
AND = "and"
|
14
|
+
POINT = "point"
|
15
|
+
SPACE = " "
|
16
|
+
|
17
|
+
CARDINALS = {
|
18
|
+
0 => "",
|
19
|
+
1 => "one",
|
20
|
+
2 => "two",
|
21
|
+
3 => "three",
|
22
|
+
4 => "four",
|
23
|
+
5 => "five",
|
24
|
+
6 => "six",
|
25
|
+
7 => "seven",
|
26
|
+
8 => "eight",
|
27
|
+
9 => "nine",
|
28
|
+
10 => "ten",
|
29
|
+
11 => "eleven",
|
30
|
+
12 => "twelve",
|
31
|
+
13 => "thirteen",
|
32
|
+
14 => "fourteen",
|
33
|
+
15 => "fifteen",
|
34
|
+
16 => "sixteen",
|
35
|
+
17 => "seventeen",
|
36
|
+
18 => "eighteen",
|
37
|
+
19 => "nineteen",
|
38
|
+
20 => "twenty",
|
39
|
+
30 => "thirty",
|
40
|
+
40 => "forty",
|
41
|
+
50 => "fifty",
|
42
|
+
60 => "sixty",
|
43
|
+
70 => "seventy",
|
44
|
+
80 => "eighty",
|
45
|
+
90 => "ninety",
|
46
|
+
}.freeze
|
47
|
+
|
48
|
+
CARDINAL_TO_SHORT_ORDINAL = {
|
49
|
+
0 => "th",
|
50
|
+
1 => "st",
|
51
|
+
11 => "th",
|
52
|
+
2 => "nd",
|
53
|
+
12 => "th",
|
54
|
+
3 => "rd",
|
55
|
+
13 => "th",
|
56
|
+
4 => "th",
|
57
|
+
5 => "th",
|
58
|
+
6 => "th",
|
59
|
+
7 => "th",
|
60
|
+
8 => "th",
|
61
|
+
9 => "th"
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
CARDINAL_TO_ORDINAL = {
|
65
|
+
"zero" => "zeroth",
|
66
|
+
"one" => "first",
|
67
|
+
"two" => "second",
|
68
|
+
"three" => "third",
|
69
|
+
"four" => "fourth",
|
70
|
+
"five" => "fifth",
|
71
|
+
"six" => "sixth",
|
72
|
+
"seven" => "seventh",
|
73
|
+
"eight" => "eighth",
|
74
|
+
"nine" => "ninth",
|
75
|
+
"ten" => "tenth",
|
76
|
+
"eleven" => "eleventh",
|
77
|
+
"twelve" => "twelfth",
|
78
|
+
"thirteen" => "thirteenth",
|
79
|
+
"fourteen" => "fourteenth",
|
80
|
+
"fifteen" => "fifteenth",
|
81
|
+
"sixteen" => "sixteenth",
|
82
|
+
"seventeen" => "seventeenth",
|
83
|
+
"eighteen" => "eighteenth",
|
84
|
+
"nineteen" => "nineteenth",
|
85
|
+
"twenty" => "twentieth",
|
86
|
+
"thirty" => "thirtieth",
|
87
|
+
"forty" => "fortieth",
|
88
|
+
"fifty" => "fiftieth",
|
89
|
+
"sixty" => "sixtieth",
|
90
|
+
"seventy" => "seventieth",
|
91
|
+
"eighty" => "eightieth",
|
92
|
+
"ninety" => "ninetieth"
|
93
|
+
}.freeze
|
94
|
+
|
95
|
+
CARDINAL_TO_ROMAN = {
|
96
|
+
1 => "I",
|
97
|
+
4 => "IV",
|
98
|
+
5 => "V",
|
99
|
+
9 => "IX",
|
100
|
+
10 => "X",
|
101
|
+
40 => "XL",
|
102
|
+
50 => "L",
|
103
|
+
90 => "XC",
|
104
|
+
100 => "C",
|
105
|
+
400 => "CD",
|
106
|
+
500 => "D",
|
107
|
+
900 => "CM",
|
108
|
+
1000 => "M"
|
109
|
+
}.freeze
|
110
|
+
|
111
|
+
SCALES = [
|
112
|
+
"hundreds-tens-ones",
|
113
|
+
"thousand",
|
114
|
+
"million",
|
115
|
+
"billion",
|
116
|
+
"trillion",
|
117
|
+
"quadrillion",
|
118
|
+
"quintillion",
|
119
|
+
"sextillion",
|
120
|
+
"septillion",
|
121
|
+
"octillion",
|
122
|
+
"nonillion",
|
123
|
+
"decillion",
|
124
|
+
"undecillion",
|
125
|
+
"duodecillion",
|
126
|
+
"tredecillion",
|
127
|
+
"quattuordecillion",
|
128
|
+
"quindecillion",
|
129
|
+
"sexdecillion",
|
130
|
+
"septemdecillion",
|
131
|
+
"octodecillion",
|
132
|
+
"novemdecillion",
|
133
|
+
"vigintillion"
|
134
|
+
].freeze
|
135
|
+
|
136
|
+
DECIMAL_SLOTS = [
|
137
|
+
"tenths",
|
138
|
+
"hundredths",
|
139
|
+
"thousandths",
|
140
|
+
"ten-thousandths",
|
141
|
+
"hundred-thousandths",
|
142
|
+
"millionths",
|
143
|
+
"ten-millionths",
|
144
|
+
"hundred-millionths",
|
145
|
+
"billionths",
|
146
|
+
"ten-billionths",
|
147
|
+
"hundred-billionths",
|
148
|
+
"trillionths",
|
149
|
+
"quadrillionths",
|
150
|
+
"quintillionths",
|
151
|
+
"sextillionths",
|
152
|
+
"septillionths",
|
153
|
+
"octillionths",
|
154
|
+
"nonillionths",
|
155
|
+
"decillionths",
|
156
|
+
"undecillionths",
|
157
|
+
"duodecillionths",
|
158
|
+
"tredecillionths",
|
159
|
+
"quattuordecillionths",
|
160
|
+
"quindecillionths",
|
161
|
+
"sexdecillionths",
|
162
|
+
"septemdecillionths",
|
163
|
+
"octodecillionths",
|
164
|
+
"novemdecillionths",
|
165
|
+
"vigintillionths"
|
166
|
+
].freeze
|
167
|
+
|
168
|
+
CURRENCIES = {
|
169
|
+
eur: {
|
170
|
+
unit: "euro",
|
171
|
+
units: "euros",
|
172
|
+
decimal_unit: "cent",
|
173
|
+
decimal_units: "cents"
|
174
|
+
},
|
175
|
+
gbp: {
|
176
|
+
unit: "pound",
|
177
|
+
units: "pounds",
|
178
|
+
decimal_unit: "pence",
|
179
|
+
decimal_units: "pence",
|
180
|
+
},
|
181
|
+
jpy: {
|
182
|
+
unit: "yen",
|
183
|
+
units: "yen",
|
184
|
+
decimal_unit: "sen",
|
185
|
+
decimal_units: "sen",
|
186
|
+
},
|
187
|
+
pln: {
|
188
|
+
unit: "zloty",
|
189
|
+
units: "zlotys",
|
190
|
+
decimal_unit: "grosz",
|
191
|
+
decimal_units: "groszy"
|
192
|
+
},
|
193
|
+
usd: {
|
194
|
+
unit: "dollar",
|
195
|
+
units: "dollars",
|
196
|
+
decimal_unit: "cent",
|
197
|
+
decimal_units: "cents"
|
198
|
+
}
|
199
|
+
}.freeze
|
200
|
+
|
201
|
+
def self.instance
|
202
|
+
@instance ||= Numeral.new
|
203
|
+
end
|
204
|
+
|
205
|
+
class << self
|
206
|
+
def numeralize(num, **options)
|
207
|
+
instance.numeralize(num, **options)
|
208
|
+
end
|
209
|
+
alias :numeralise :numeralize
|
210
|
+
|
211
|
+
def cardinalize(num, **options)
|
212
|
+
instance.cardinalize(num, **options)
|
213
|
+
end
|
214
|
+
alias :cardinalise :cardinalize
|
215
|
+
|
216
|
+
def ordinalize(num, **options)
|
217
|
+
instance.ordinalize(num, **options)
|
218
|
+
end
|
219
|
+
alias :ordinalise :ordinalize
|
220
|
+
|
221
|
+
def ordinalize_short(num)
|
222
|
+
instance.ordinalize_short(num)
|
223
|
+
end
|
224
|
+
|
225
|
+
def monetize(num, **options)
|
226
|
+
instance.monetize(num, **options)
|
227
|
+
end
|
228
|
+
alias :monetise :monetize
|
229
|
+
|
230
|
+
def romanize(num)
|
231
|
+
instance.romanize(num)
|
232
|
+
end
|
233
|
+
alias :romanise :romanize
|
234
|
+
end
|
235
|
+
|
236
|
+
# Create numeral with custom configuration
|
237
|
+
#
|
238
|
+
# @yieldparam [Configuration]
|
239
|
+
#
|
240
|
+
# @return [Numeral]
|
241
|
+
#
|
242
|
+
# @api public
|
243
|
+
def initialize
|
244
|
+
@configuration = Configuration.new
|
245
|
+
if block_given?
|
246
|
+
yield @configuration
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Convert a number to a numeral
|
251
|
+
#
|
252
|
+
# @param [Numeric,String] num
|
253
|
+
# the number to convert
|
254
|
+
#
|
255
|
+
# @api public
|
256
|
+
def numeralize(num, **options)
|
257
|
+
case options.delete(:term)
|
258
|
+
when /ord/
|
259
|
+
ordinalize(num, **options)
|
260
|
+
else
|
261
|
+
cardinalize(num, **options)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Convert a number to a cardinal numeral
|
266
|
+
#
|
267
|
+
# @example
|
268
|
+
# cardinalize(1234)
|
269
|
+
# # => one thousand, two hundred thirty four
|
270
|
+
#
|
271
|
+
# @param [Numeric,String] num
|
272
|
+
#
|
273
|
+
# @return [String]
|
274
|
+
#
|
275
|
+
# @api public
|
276
|
+
def cardinalize(num, **options)
|
277
|
+
convert_numeral(num, **options)
|
278
|
+
end
|
279
|
+
alias :cardinalise :cardinalize
|
280
|
+
|
281
|
+
# Convert a number to an ordinal numeral
|
282
|
+
#
|
283
|
+
# @example
|
284
|
+
# ordinalize(1234)
|
285
|
+
# # => one thousand, two hundred thirty fourth
|
286
|
+
#
|
287
|
+
# ordinalize(12, short: true) # => 12th
|
288
|
+
#
|
289
|
+
# @param [Numeric,String] num
|
290
|
+
# the number to convert
|
291
|
+
#
|
292
|
+
# @return [String]
|
293
|
+
#
|
294
|
+
# @api public
|
295
|
+
def ordinalize(num, **options)
|
296
|
+
if options[:short]
|
297
|
+
ordinalize_short(num)
|
298
|
+
else
|
299
|
+
decimals = (num.to_i.abs != num.to_f.abs)
|
300
|
+
sentence = convert_numeral(num, **options)
|
301
|
+
separators = [AND, POINT,
|
302
|
+
options.fetch(:separator, @configuration.separator)].compact
|
303
|
+
|
304
|
+
if decimals && sentence =~ /(\w+) (#{Regexp.union(separators)})/
|
305
|
+
last_digits = $1
|
306
|
+
separator = $2
|
307
|
+
replacement = CARDINAL_TO_ORDINAL[last_digits]
|
308
|
+
pattern = /#{last_digits} #{separator}/
|
309
|
+
suffix = "#{replacement} #{separator}"
|
310
|
+
elsif sentence =~ /(\w+)$/
|
311
|
+
last_digits = $1
|
312
|
+
replacement = CARDINAL_TO_ORDINAL[last_digits]
|
313
|
+
pattern = /#{last_digits}$/
|
314
|
+
suffix = replacement
|
315
|
+
end
|
316
|
+
|
317
|
+
if replacement
|
318
|
+
sentence.sub(pattern, suffix)
|
319
|
+
else
|
320
|
+
sentence
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
alias :ordinalise :ordinalize
|
325
|
+
|
326
|
+
# Convert a number to a short ordinal form
|
327
|
+
#
|
328
|
+
# @example
|
329
|
+
# ordinalize_short(123) # => 123rd
|
330
|
+
#
|
331
|
+
# @param [Numeric, String] num
|
332
|
+
# the number to convert
|
333
|
+
#
|
334
|
+
# @return [String]
|
335
|
+
#
|
336
|
+
# @api private
|
337
|
+
def ordinalize_short(num)
|
338
|
+
num_abs = num.to_i.abs
|
339
|
+
|
340
|
+
num.to_i.to_s + (CARDINAL_TO_SHORT_ORDINAL[num_abs % 100] ||
|
341
|
+
CARDINAL_TO_SHORT_ORDINAL[num_abs % 10])
|
342
|
+
end
|
343
|
+
|
344
|
+
# Convert a number into a monetary numeral
|
345
|
+
#
|
346
|
+
# @example
|
347
|
+
# monetize(123.45)
|
348
|
+
# # => "one hundred twenty three dollars and forty five cents"
|
349
|
+
#
|
350
|
+
# @param [Numeric,String] num
|
351
|
+
# the number to convert
|
352
|
+
#
|
353
|
+
# @return [String]
|
354
|
+
#
|
355
|
+
# @api public
|
356
|
+
def monetize(num, **options)
|
357
|
+
sep = options.fetch(:separator, @configuration.separator)
|
358
|
+
curr_name = options.fetch(:currency, @configuration.currency)
|
359
|
+
n = "%0.2f" % num.to_s
|
360
|
+
decimals = (num.to_i.abs != num.to_f.abs)
|
361
|
+
sentence = convert_numeral(n, **options.merge(trailing_zeros: true))
|
362
|
+
dec_num = n.split(".")[1]
|
363
|
+
curr = CURRENCIES[curr_name.to_s.downcase.to_sym]
|
364
|
+
separators = [AND, POINT, sep].compact
|
365
|
+
|
366
|
+
if decimals
|
367
|
+
regex = /(\w+) (#{Regexp.union(separators)})/
|
368
|
+
sentence.sub!(regex, "\\1 #{curr[:units]} \\2")
|
369
|
+
else
|
370
|
+
sentence += SPACE + (num.to_i == 1 ? curr[:unit] : curr[:units])
|
371
|
+
end
|
372
|
+
|
373
|
+
if decimals
|
374
|
+
slots = Regexp.union(DECIMAL_SLOTS.map { |slot| slot.chomp('s') })
|
375
|
+
regex = /(#{slots})s?/i
|
376
|
+
suffix = dec_num.to_i == 1 ? curr[:decimal_unit] : curr[:decimal_units]
|
377
|
+
if sentence.sub!(regex, suffix).nil?
|
378
|
+
sentence += SPACE + suffix
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
sentence
|
383
|
+
end
|
384
|
+
alias :monetise :monetize
|
385
|
+
|
386
|
+
# Convert a number to a roman numeral
|
387
|
+
#
|
388
|
+
# @example
|
389
|
+
# romanize(2020) # => "MMXX"
|
390
|
+
#
|
391
|
+
# @param [Integer] num
|
392
|
+
# the number to convert
|
393
|
+
#
|
394
|
+
# @return [String]
|
395
|
+
#
|
396
|
+
# @api public
|
397
|
+
def romanize(num)
|
398
|
+
n = num.to_i
|
399
|
+
|
400
|
+
if n < 1 || n > 4999
|
401
|
+
raise Error, "'#{n}' is out of range"
|
402
|
+
end
|
403
|
+
|
404
|
+
CARDINAL_TO_ROMAN.keys.reverse_each.reduce([]) do |word, card|
|
405
|
+
while n >= card
|
406
|
+
n -= card
|
407
|
+
word << CARDINAL_TO_ROMAN[card]
|
408
|
+
end
|
409
|
+
word
|
410
|
+
end.join
|
411
|
+
end
|
412
|
+
|
413
|
+
private
|
414
|
+
|
415
|
+
# Convert a number into a numeral
|
416
|
+
#
|
417
|
+
# @param [Numeric] num
|
418
|
+
# the number to convert to numeral
|
419
|
+
# @param [String] delimiter
|
420
|
+
# sets the thousand's delimiter, defaults to `, `
|
421
|
+
# @param [String] decimal
|
422
|
+
# the decimal word conversion, defaults to `:fraction`
|
423
|
+
# @param [String] separator
|
424
|
+
# sets the separator between the fractional and integer numerals,
|
425
|
+
# defaults to `and` for fractions and `point` for digits
|
426
|
+
#
|
427
|
+
# @return [String]
|
428
|
+
# the number as numeral
|
429
|
+
#
|
430
|
+
# @api private
|
431
|
+
def convert_numeral(num, **options)
|
432
|
+
delimiter = options.fetch(:delimiter, @configuration.delimiter)
|
433
|
+
decimal = options.fetch(:decimal, @configuration.decimal)
|
434
|
+
separator = options.fetch(:separator, @configuration.separator)
|
435
|
+
|
436
|
+
negative = num.to_i < 0
|
437
|
+
n = num.to_i.abs
|
438
|
+
decimals = (n != num.to_f.abs)
|
439
|
+
|
440
|
+
sentence = convert_to_words(n).join(delimiter)
|
441
|
+
|
442
|
+
if sentence.empty?
|
443
|
+
sentence = ZERO
|
444
|
+
end
|
445
|
+
|
446
|
+
if negative
|
447
|
+
sentence = NEGATIVE + SPACE + sentence
|
448
|
+
end
|
449
|
+
|
450
|
+
if decimals
|
451
|
+
sentence = sentence + SPACE +
|
452
|
+
(separator.nil? ? (decimal == :fraction ? AND : POINT) : separator) +
|
453
|
+
SPACE + convert_decimals(num, **options)
|
454
|
+
end
|
455
|
+
|
456
|
+
sentence
|
457
|
+
end
|
458
|
+
|
459
|
+
# Convert decimal part to words
|
460
|
+
#
|
461
|
+
# @param [String] trailing_zeros
|
462
|
+
# whether or not to keep trailing zeros, defaults to `false`
|
463
|
+
#
|
464
|
+
# @return [String]
|
465
|
+
#
|
466
|
+
# @api private
|
467
|
+
def convert_decimals(num, **options)
|
468
|
+
delimiter = options.fetch(:delimiter, @configuration.delimiter)
|
469
|
+
decimal = options.fetch(:decimal, @configuration.decimal)
|
470
|
+
trailing_zeros = options.fetch(:trailing_zeros, @configuration.trailing_zeros)
|
471
|
+
|
472
|
+
dec_num = num.to_s.split(".")[1]
|
473
|
+
dec_num.gsub!(/0+$/, "") unless trailing_zeros
|
474
|
+
|
475
|
+
case decimal
|
476
|
+
when :fraction
|
477
|
+
unit = DECIMAL_SLOTS[dec_num.to_s.length - 1]
|
478
|
+
unit = unit[0...-1] if dec_num.to_i == 1 # strip off 's'
|
479
|
+
convert_to_words(dec_num.to_i).join(delimiter) + SPACE + unit
|
480
|
+
when :digit
|
481
|
+
dec_num.chars.map do |n|
|
482
|
+
(v = convert_tens(n.to_i)).empty? ? ZERO : v
|
483
|
+
end.join(SPACE)
|
484
|
+
else
|
485
|
+
raise Error, "Unknown decimal option '#{decimal.inspect}'"
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
# Convert an integer to number words
|
490
|
+
#
|
491
|
+
# @param [Integer] n
|
492
|
+
#
|
493
|
+
# @return [Array[String]]
|
494
|
+
#
|
495
|
+
# @api public
|
496
|
+
def convert_to_words(n)
|
497
|
+
words = []
|
498
|
+
|
499
|
+
SCALES.each_with_index do |scale, i|
|
500
|
+
mod = n % 1000
|
501
|
+
|
502
|
+
word = []
|
503
|
+
word << convert_hundreds(mod)
|
504
|
+
word << scale unless i.zero?
|
505
|
+
|
506
|
+
words.insert(0, word.join(SPACE))
|
507
|
+
|
508
|
+
n /= 1000
|
509
|
+
|
510
|
+
break if n.zero?
|
511
|
+
end
|
512
|
+
|
513
|
+
words
|
514
|
+
end
|
515
|
+
|
516
|
+
# Convert 3 digit number to equivalent word
|
517
|
+
#
|
518
|
+
# @return [String]
|
519
|
+
#
|
520
|
+
# @api private
|
521
|
+
def convert_hundreds(num)
|
522
|
+
word = []
|
523
|
+
hundreds = (num % 1000) / 100
|
524
|
+
tens = num % 100
|
525
|
+
|
526
|
+
if !hundreds.zero?
|
527
|
+
word << convert_tens(hundreds)
|
528
|
+
word << HUNDRED
|
529
|
+
end
|
530
|
+
|
531
|
+
if !tens.zero?
|
532
|
+
word << convert_tens(tens)
|
533
|
+
end
|
534
|
+
|
535
|
+
word.join(SPACE)
|
536
|
+
end
|
537
|
+
|
538
|
+
# Convert number in 0..99 range to equivalent word
|
539
|
+
#
|
540
|
+
# @return [String]
|
541
|
+
#
|
542
|
+
# @api private
|
543
|
+
def convert_tens(num)
|
544
|
+
word = []
|
545
|
+
tens = num % 100
|
546
|
+
|
547
|
+
if tens.to_s.size < 2 || tens <= 20
|
548
|
+
word << CARDINALS[tens]
|
549
|
+
else
|
550
|
+
word << CARDINALS[(tens / 10) * 10]
|
551
|
+
word << CARDINALS[tens % 10] unless (tens % 10).zero?
|
552
|
+
end
|
553
|
+
|
554
|
+
word.join(SPACE)
|
555
|
+
end
|
556
|
+
end # Numeral
|
557
|
+
end # Strings
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Strings
|
4
|
+
class Numeral
|
5
|
+
class Configuration
|
6
|
+
# Initialize a configuration
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
def initialize
|
10
|
+
@currency = :usd
|
11
|
+
@delimiter = ", "
|
12
|
+
@decimal = :fraction
|
13
|
+
@separator = nil
|
14
|
+
@trailing_zeros = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def currency(value = (not_set = true))
|
18
|
+
if not_set
|
19
|
+
@currency
|
20
|
+
else
|
21
|
+
@currency = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def delimiter(value = (not_set = true))
|
26
|
+
if not_set
|
27
|
+
@delimiter
|
28
|
+
else
|
29
|
+
@delimiter = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def separator(value = (not_set = true))
|
34
|
+
if not_set
|
35
|
+
@separator
|
36
|
+
else
|
37
|
+
@separator = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def decimal(value = (not_set = true))
|
42
|
+
if not_set
|
43
|
+
@decimal
|
44
|
+
else
|
45
|
+
@decimal = value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def trailing_zeros(value = (not_set = true))
|
50
|
+
if not_set
|
51
|
+
@trailing_zeros
|
52
|
+
else
|
53
|
+
@trailing_zeros = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end # Configuration
|
57
|
+
end # Numeral
|
58
|
+
end # Strings
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Strings
|
4
|
+
class Numeral
|
5
|
+
module Extensions
|
6
|
+
Methods = Module.new do
|
7
|
+
def numeralize(**options)
|
8
|
+
Strings::Numeral.numeralize(self, **options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def cardinalize(**options)
|
12
|
+
Strings::Numeral.cardinalize(self, **options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def ordinalize(**options)
|
16
|
+
Strings::Numeral.ordinalize(self, **options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ordinalize_short
|
20
|
+
Strings::Numeral.ordinalize_short(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def monetize(**options)
|
24
|
+
Strings::Numeral.monetize(self, **options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def romanize
|
28
|
+
Strings::Numeral.romanize(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
refine String do
|
33
|
+
include Methods
|
34
|
+
end
|
35
|
+
|
36
|
+
refine Float do
|
37
|
+
include Methods
|
38
|
+
end
|
39
|
+
|
40
|
+
refine Integer do
|
41
|
+
include Methods
|
42
|
+
end
|
43
|
+
end # Extensions
|
44
|
+
end # Numeral
|
45
|
+
end # Strings
|
@@ -0,0 +1,34 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "strings/numeral/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "strings-numeral"
|
7
|
+
spec.version = Strings::Numeral::VERSION
|
8
|
+
spec.authors = ["Piotr Murach"]
|
9
|
+
spec.email = ["me@piotrmurach.com"]
|
10
|
+
spec.summary = %q{Express numbers as word numerals}
|
11
|
+
spec.description = %q{Express numbers as word numerals like cardinal, ordinal, roman and monetary}
|
12
|
+
spec.homepage = "https://github.com/piotrmurach/strings-numeral"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
if spec.respond_to?(:metadata)
|
16
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/piotrmurach/strings-numeral/blob/master/CHANGELOG.md"
|
18
|
+
spec.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/strings-numeral"
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/piotrmurach/strings-numeral"
|
21
|
+
end
|
22
|
+
|
23
|
+
spec.files = Dir["lib/**/*.rb"]
|
24
|
+
spec.files += Dir["tasks/*", "strings-numeral.gemspec"]
|
25
|
+
spec.files += Dir["README.md", "CHANGELOG.md", "LICENSE.txt", "Rakefile"]
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.required_ruby_version = ">= 2.0.0"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", ">= 1.5"
|
32
|
+
spec.add_development_dependency "rake"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
end
|
data/tasks/console.rake
ADDED
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
6
|
+
desc "Run all specs"
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = "spec/{unit,integration}{,/*/**}/*_spec.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc "Run unit specs"
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = "spec/unit{,/*/**}/*_spec.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run integration specs"
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = "spec/integration{,/*/**}/*_spec.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Run performance specs"
|
23
|
+
RSpec::Core::RakeTask.new(:perf) do |task|
|
24
|
+
task.pattern = "spec/perf{,/*/**}/*_spec.rb"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rescue LoadError
|
29
|
+
%w[spec spec:unit spec:integration].each do |name|
|
30
|
+
task name do
|
31
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: strings-numeral
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Piotr Murach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Express numbers as word numerals like cardinal, ordinal, roman and monetary
|
56
|
+
email:
|
57
|
+
- me@piotrmurach.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- CHANGELOG.md
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/strings-numeral.rb
|
67
|
+
- lib/strings/numeral.rb
|
68
|
+
- lib/strings/numeral/configuration.rb
|
69
|
+
- lib/strings/numeral/extensions.rb
|
70
|
+
- lib/strings/numeral/version.rb
|
71
|
+
- strings-numeral.gemspec
|
72
|
+
- tasks/console.rake
|
73
|
+
- tasks/coverage.rake
|
74
|
+
- tasks/spec.rake
|
75
|
+
homepage: https://github.com/piotrmurach/strings-numeral
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata:
|
79
|
+
allowed_push_host: https://rubygems.org
|
80
|
+
changelog_uri: https://github.com/piotrmurach/strings-numeral/blob/master/CHANGELOG.md
|
81
|
+
documentation_uri: https://www.rubydoc.info/gems/strings-numeral
|
82
|
+
homepage_uri: https://github.com/piotrmurach/strings-numeral
|
83
|
+
source_code_uri: https://github.com/piotrmurach/strings-numeral
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.0.0
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubygems_version: 3.1.0.pre3
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Express numbers as word numerals
|
103
|
+
test_files: []
|