strings-numeral 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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]
|
8
|
+
[][travis]
|
9
|
+
[][appveyor]
|
10
|
+
[][codeclimate]
|
11
|
+
[][coverage]
|
12
|
+
[][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: []
|