trange_frange 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.
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ README.rdoc
3
+ ChangeLog.rdoc
4
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/ChangeLog.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.1.0 / 2013-02-03 ###
2
+
3
+ * Initial release:
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Ninoslav Milenovic
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # trange_frange #
2
+ The tool spells out numbers (amounts) in words. It supports serbian language.
3
+ > 12345.67 => 'dvanaest hiljada tri stotine četrdeset pet i 67/100'
4
+
5
+ ## Install ##
6
+ ```bash
7
+ $ gem install trange_frange
8
+ ```
9
+
10
+ ## Examples ##
11
+ ```ruby
12
+ require 'trange_frange'
13
+ amount = TrangeFrange::Amount.new(16345.67)
14
+ amount.spell!
15
+ => "šesnaest hiljada tri stotine četrdeset pet"
16
+ ```
17
+ to include a fraction
18
+ ```ruby
19
+ require 'trange_frange'
20
+ amount = TrangeFrange::Amount.new(16345.67)
21
+ amount.spell! show_fraction: true
22
+ => 'šesnaest hiljada tri stotine četrdeset pet i 67/100'
23
+ ```
24
+ to disable spacing between words
25
+ ```ruby
26
+ require 'trange_frange'
27
+ amount = TrangeFrange::Amount.new(16345.67)
28
+ amount.spell! squeeze: true
29
+ => 'šesnaesthiljadatristotinečetrdesetpet'
30
+ ```
31
+ to avoid using accented lating characters
32
+ ```ruby
33
+ require 'trange_frange'
34
+ amount = TrangeFrange::Amount.new(16345.67)
35
+ amount.spell! bald: true
36
+ => 'sesnaest hiljada tri stotine cetrdeset pet'
37
+ ```
38
+ or combine the options
39
+ ```ruby
40
+ require 'trange_frange'
41
+ amount = TrangeFrange::Amount.new(16345.67)
42
+ amount.spell! show_fraction: true, squeeze: true, bald: true
43
+ => 'sesnaesthiljadatristotinecetrdesetpet i 67/100'
44
+ ```
45
+
46
+ ### Copyright ###
47
+ Copyright (c) 2013 Ninoslav Milenovic
48
+
49
+ See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn 'Run `gem install rubygems-tasks` to install Gem::Tasks.'
14
+ end
15
+
16
+ begin
17
+ gem 'rdoc', '~> 3.0'
18
+ require 'rdoc/task'
19
+
20
+ RDoc::Task.new do |rdoc|
21
+ rdoc.title = 'trange_frange'
22
+ end
23
+ rescue LoadError => e
24
+ warn e.message
25
+ warn "Run `gem install rdoc` to install 'rdoc/task'."
26
+ end
27
+ task :doc => :rdoc
28
+
29
+ begin
30
+ gem 'rspec', '~> 2.4'
31
+ require 'rspec/core/rake_task'
32
+
33
+ RSpec::Core::RakeTask.new
34
+ rescue LoadError => e
35
+ task :spec do
36
+ abort 'Please run `gem install rspec` to install RSpec.'
37
+ end
38
+ end
39
+
40
+ task :test => :spec
41
+ task :default => :spec
@@ -0,0 +1,333 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'trange_frange/version'
4
+
5
+ module TrangeFrange
6
+ class Member < Struct.new :base
7
+ def one
8
+ base[-1]
9
+ end
10
+
11
+ def ten
12
+ base.size >= 2 ? base[-2] : '0'
13
+ end
14
+
15
+ def hundred
16
+ base.size == 3 ? base[-3] : '0'
17
+ end
18
+ end
19
+
20
+ class OrderCondition
21
+ def initialize
22
+ @conditions = []
23
+ end
24
+
25
+ def add
26
+ @conditions << Proc.new
27
+ end
28
+
29
+ def match!
30
+ @conditions.map(&:call).map do |condition|
31
+ return condition if condition
32
+ end
33
+ end
34
+
35
+ private
36
+ attr_reader :conditions
37
+ end
38
+
39
+ class Base < Struct.new :base
40
+ # range [10-19]
41
+ def teen?
42
+ member.ten == '1'
43
+ end
44
+
45
+ def gender?
46
+ %w[1 2].include? member.one
47
+ end
48
+
49
+ def member
50
+ @member ||= TrangeFrange::Member.new base
51
+ end
52
+ end
53
+
54
+ class Suffix < Struct.new :base
55
+ def gender?
56
+ ('2'..'4').include? suffix_base.member.one
57
+ end
58
+
59
+ def one?
60
+ suffix_base.member.one == '1'
61
+ end
62
+
63
+ def suffix_base
64
+ @suffix_base ||= TrangeFrange::Base.new base
65
+ end
66
+ end
67
+
68
+ class One < Struct.new :base, :magnitude
69
+ ONES = {
70
+ '0' => '', # not printed
71
+ '1' => {
72
+ :m => 'jedan', # male gender
73
+ :f => 'jedna' # female gender
74
+ },
75
+ '2' => {
76
+ :m => 'dva',
77
+ :f => 'dve'
78
+ },
79
+ '3' => 'tri',
80
+ '4' => 'četiri',
81
+ '5' => 'pet',
82
+ '6' => 'šest',
83
+ '7' => 'sedam',
84
+ '8' => 'osam',
85
+ '9' => 'devet'
86
+ }
87
+
88
+ def word
89
+ order_condition.add { String.new if one_base.teen? }
90
+ order_condition.add { ONES[one_base.member.one][gender] if one_base.gender? }
91
+ order_condition.add { ONES[one_base.member.one] }
92
+ order_condition.match!
93
+ end
94
+
95
+ private
96
+
97
+ def one_base
98
+ @one_base ||= TrangeFrange::Base.new base
99
+ end
100
+
101
+ def order_condition
102
+ @order_condition ||= TrangeFrange::OrderCondition.new
103
+ end
104
+
105
+ def gender
106
+ magnitude.odd? ? :f : :m
107
+ end
108
+ end
109
+
110
+ class Ten < Struct.new :base
111
+ TENS = {
112
+ '0' => '',
113
+ '10' => 'deset',
114
+ '11' => 'jedanaest',
115
+ '12' => 'dvanaest',
116
+ '13' => 'trinaest',
117
+ '14' => 'četrnaest',
118
+ '15' => 'petnaest',
119
+ '16' => 'šesnaest',
120
+ '17' => 'sedamnaest',
121
+ '18' => 'osamnaest',
122
+ '19' => 'devetnaest',
123
+ '2' => 'dvadeset',
124
+ '3' => 'trideset',
125
+ '4' => 'četrdeset',
126
+ '5' => 'pedeset',
127
+ '6' => 'šezdeset',
128
+ '7' => 'sedamdeset',
129
+ '8' => 'osamdeset',
130
+ '9' => 'devedeset'
131
+ }
132
+
133
+ def word
134
+ order_condition.add { TENS[teen_base_member] if ten_base.teen? }
135
+ order_condition.add { TENS[ten_base.member.ten] }
136
+ order_condition.match!
137
+ end
138
+
139
+ private
140
+
141
+ def ten_base
142
+ @ten_base ||= TrangeFrange::Base.new base
143
+ end
144
+
145
+ def order_condition
146
+ @order_condition ||= TrangeFrange::OrderCondition.new
147
+ end
148
+
149
+ def teen_base_member
150
+ ten_base.member.ten + ten_base.member.one
151
+ end
152
+ end
153
+
154
+ class Hundred < Struct.new :base
155
+ HUNDREDS = {
156
+ '0' => '',
157
+ '1' => 'jedna stotina',
158
+ '2' => 'dve stotine',
159
+ '3' => 'tri stotine',
160
+ '4' => 'četiri stotine',
161
+ '5' => 'pet stotina',
162
+ '6' => 'šest stotina',
163
+ '7' => 'sedam stotina',
164
+ '8' => 'osam stotina',
165
+ '9' => 'devet stotina'
166
+ }
167
+
168
+ def word
169
+ order_condition.add { HUNDREDS[hundred_base.member.hundred] }
170
+ order_condition.match!
171
+ end
172
+
173
+ private
174
+
175
+ def hundred_base
176
+ @hundred_base ||= TrangeFrange::Base.new base
177
+ end
178
+
179
+ def order_condition
180
+ @order_condition ||= TrangeFrange::OrderCondition.new
181
+ end
182
+ end
183
+
184
+ class Thousand < Struct.new :base
185
+ THOUSANDS = %w[hiljada hiljade]
186
+
187
+ def word
188
+ order_condition.add { THOUSANDS[1] if suffix.gender? and !suffix.suffix_base.teen? }
189
+ order_condition.add { THOUSANDS[0] }
190
+ order_condition.match!
191
+ end
192
+
193
+ private
194
+
195
+ def suffix
196
+ @suffix ||= TrangeFrange::Suffix.new base
197
+ end
198
+
199
+ def order_condition
200
+ @order_condition ||= TrangeFrange::OrderCondition.new
201
+ end
202
+ end
203
+
204
+ class Milion < Struct.new :base
205
+ MILIONS = %w[milion miliona]
206
+
207
+ def word
208
+ order_condition.add { MILIONS[0] if suffix.one? and !suffix.suffix_base.teen? }
209
+ order_condition.add { MILIONS[1] }
210
+ order_condition.match!
211
+ end
212
+
213
+ private
214
+
215
+ def suffix
216
+ @suffix ||= TrangeFrange::Suffix.new base
217
+ end
218
+
219
+ def order_condition
220
+ @order_condition ||= TrangeFrange::OrderCondition.new
221
+ end
222
+ end
223
+
224
+ class Bilion < Struct.new :base
225
+ BILIONS = %w[milijarda milijarde milijardi]
226
+
227
+ def word
228
+ order_condition.add { BILIONS[0] if suffix.one? and !suffix.suffix_base.teen? }
229
+ order_condition.add { BILIONS[1] if suffix.gender? and !suffix.suffix_base.teen? }
230
+ order_condition.add { BILIONS[2] }
231
+ order_condition.match!
232
+ end
233
+
234
+ private
235
+
236
+ def suffix
237
+ @suffix ||= TrangeFrange::Suffix.new base
238
+ end
239
+
240
+ def order_condition
241
+ @order_condition ||= TrangeFrange::OrderCondition.new
242
+ end
243
+ end
244
+
245
+ class Shaper < Struct.new :words, :fraction, :options
246
+ OPTIONS = [:bald, :squeeze, :show_fraction]
247
+
248
+ def shape!
249
+ OPTIONS.each { |option| send(option) if options[option] } and return words
250
+ end
251
+
252
+ private
253
+
254
+ def show_fraction
255
+ words << " i #{fraction}/100"
256
+ end
257
+
258
+ def squeeze
259
+ words.delete!(' ')
260
+ end
261
+
262
+ def bald
263
+ words.tr!('čćšđž', 'ccsdz')
264
+ end
265
+ end
266
+
267
+ class Amount
268
+ attr_reader :amount
269
+
270
+ MAX_AMOUNT_SIZE = 12
271
+ BASES = [Hundred, Ten, One]
272
+ SUFFIXES = [Thousand, Milion, Bilion]
273
+
274
+ def initialize(amount)
275
+ unless amount.is_a?(Fixnum) || amount.is_a?(Float)
276
+ raise TypeError, 'Amount must be of type Fixnum or Float.'
277
+ end
278
+
279
+ if max_amount_size?(amount)
280
+ raise NotImplementedError, 'I can only work with amounts up to 999 bilions.'
281
+ end
282
+
283
+ @amount = amount
284
+ end
285
+
286
+ def spell!(options={})
287
+ TrangeFrange::Shaper.new(generate_words!, fraction, options).shape!
288
+ end
289
+
290
+ private
291
+
292
+ def max_amount_size?(amount)
293
+ amount.to_s.split('.')[0].size > MAX_AMOUNT_SIZE
294
+ end
295
+
296
+ def split!
297
+ @splitted ||= ('%.2f' % amount).split('.')
298
+ end
299
+
300
+ def whole_number
301
+ @whole_number ||= split![0]
302
+ end
303
+
304
+ def fraction
305
+ @fraction ||= split![1]
306
+ end
307
+
308
+ def members
309
+ @members ||= whole_number.reverse.scan(/.{1,3}/).reverse.map(&:reverse)
310
+ end
311
+
312
+ def generate_base!(member, magnitude)
313
+ BASES.map do |base|
314
+ base == One ? base.new(member, magnitude).word : base.new(member).word
315
+ end.join(' ').strip.squeeze
316
+ end
317
+
318
+ def generate_suffix!(member, magnitude)
319
+ magnitude > 0 ? SUFFIXES[magnitude.pred].new(member).word : String.new
320
+ end
321
+
322
+ def generate_words!
323
+ magnitude = members.size.pred
324
+ Array.new.tap do |words|
325
+ members.map do |member|
326
+ words << generate_base!(member, magnitude)
327
+ words << generate_suffix!(member, magnitude) unless words.last.empty?
328
+ magnitude -= 1
329
+ end
330
+ end.join(' ').strip.squeeze
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,3 @@
1
+ module TrangeFrange
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,5 @@
1
+ gem 'rspec', '~> 2.4'
2
+ require 'rspec'
3
+ require 'trange_frange/version'
4
+
5
+ include TrangeFrange
@@ -0,0 +1,541 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+ require 'trange_frange'
5
+
6
+ describe TrangeFrange do
7
+ it 'should have a VERSION constant' do
8
+ subject.const_get('VERSION').should_not be_empty
9
+ end
10
+
11
+ describe TrangeFrange::Member do
12
+ let(:base) { TrangeFrange::Member.new '123' }
13
+
14
+ describe '#one' do
15
+ context 'when 123' do
16
+ specify { base.one.should eq('3') }
17
+ end
18
+ end
19
+
20
+ describe '#ten' do
21
+ context 'when 123' do
22
+ specify { base.ten.should eq('2') }
23
+ end
24
+ end
25
+
26
+ describe '#hundred' do
27
+ context 'when 123' do
28
+ specify { base.hundred.should eq('1') }
29
+ end
30
+ end
31
+ end
32
+
33
+ describe TrangeFrange::OrderCondition do
34
+ let(:order_condition) { OrderCondition.new }
35
+ before do
36
+ order_condition.add { nil }
37
+ order_condition.add { 'content' }
38
+ order_condition.add { nil }
39
+ end
40
+
41
+ describe '#add' do
42
+ specify { order_condition.send(:conditions).class.should eq(Array) }
43
+ specify do
44
+ order_condition.send(:conditions).map do |condition|
45
+ condition.instance_of?(Proc)
46
+ end.uniq.should eq([true])
47
+ end
48
+ specify do
49
+ order_condition.send(:conditions).map(&:call).should match_array([nil, 'content', nil])
50
+ end
51
+ end
52
+
53
+ describe '#match!' do
54
+ specify { order_condition.match!.should eq('content') }
55
+ end
56
+ end
57
+
58
+ describe TrangeFrange::Base do
59
+ describe '#teen?' do
60
+ context 'when 123' do
61
+ let(:base) { TrangeFrange::Base.new '123' }
62
+ specify { base.teen?.should be_false }
63
+ end
64
+
65
+ context 'when 113' do
66
+ let(:base) { TrangeFrange::Base.new '113' }
67
+ specify { base.teen?.should be_true }
68
+ end
69
+ end
70
+
71
+ describe '#gender?' do
72
+ context 'when not gender' do
73
+ let(:non_gender) { Array 3..9 }
74
+ let(:bases) do
75
+ non_gender.map { |non_gender| TrangeFrange::Base.new "12#{non_gender}" }
76
+ end
77
+ specify do
78
+ bases.each { |base| base.gender?.should be_false }
79
+ end
80
+ end
81
+
82
+ context 'when gender' do
83
+ let(:gender) { Array 1..2 }
84
+ let(:bases) do
85
+ gender.map { |gender| TrangeFrange::Base.new "12#{gender}" }
86
+ end
87
+ specify do
88
+ bases.each { |base| base.gender?.should be_true }
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ describe TrangeFrange::Suffix do
95
+ describe '#gender?' do
96
+ context 'when gender' do
97
+ let(:gender) { Array(2..4) }
98
+ let(:suffixes) do
99
+ gender.map { |gender| TrangeFrange::Suffix.new "12#{gender}" }
100
+ end
101
+ specify do
102
+ suffixes.each { |suffix| suffix.gender?.should be_true }
103
+ end
104
+ end
105
+
106
+ context 'when not gender' do
107
+ let(:non_gender) { Array(5..9) << 1 }
108
+ let(:suffixes) do
109
+ non_gender.map { |non_gender| TrangeFrange::Suffix.new "12#{non_gender}" }
110
+ end
111
+ specify do
112
+ suffixes.each { |suffix| suffix.gender?.should be_false }
113
+ end
114
+ end
115
+ end
116
+
117
+ describe '#one?' do
118
+ context 'when one' do
119
+ let(:suffix) { TrangeFrange::Suffix.new '121' }
120
+ specify { suffix.one?.should be_true }
121
+ end
122
+
123
+ context 'when not one' do
124
+ let(:suffixes) { TrangeFrange::Suffix.new '123' }
125
+ specify { suffixes.one?.should be_false }
126
+ end
127
+ end
128
+ end
129
+
130
+ describe TrangeFrange::One do
131
+ describe '#gender' do
132
+ context 'when magnitude is odd' do
133
+ let(:one) { TrangeFrange::One.new '123', 0 }
134
+ specify { one.send(:gender).should eq(:m) }
135
+ end
136
+
137
+ context 'when magnitude is even' do
138
+ let(:one) { TrangeFrange::One.new '123', 1 }
139
+ specify { one.send(:gender).should eq(:f) }
140
+ end
141
+ end
142
+
143
+ describe '#word' do
144
+ context 'when simple' do
145
+ specify { TrangeFrange::One.new('120', 0).word.should eq(String.new) }
146
+ specify { TrangeFrange::One.new('123', 1).word.should eq('tri') }
147
+ specify { TrangeFrange::One.new('124', 2).word.should eq('četiri') }
148
+ specify { TrangeFrange::One.new('125', 3).word.should eq('pet') }
149
+ specify { TrangeFrange::One.new('126', 4).word.should eq('šest') }
150
+ specify { TrangeFrange::One.new('127', 5).word.should eq('sedam') }
151
+ specify { TrangeFrange::One.new('128', 6).word.should eq('osam') }
152
+ specify { TrangeFrange::One.new('129', 7).word.should eq('devet') }
153
+ end
154
+
155
+ context 'when gender' do
156
+ context 'when magnitude is odd' do
157
+ Array(0..9).select(&:odd?).each do |odd_number|
158
+ specify { TrangeFrange::One.new('121', odd_number).word.should eq('jedna') }
159
+ specify { TrangeFrange::One.new('122', odd_number).word.should eq('dve') }
160
+ end
161
+ end
162
+
163
+ context 'when magnitude is even' do
164
+ Array(0..9).select(&:even?).each do |even_number|
165
+ specify { TrangeFrange::One.new('121', even_number).word.should eq('jedan') }
166
+ specify { TrangeFrange::One.new('122', even_number).word.should eq('dva') }
167
+ end
168
+ end
169
+ end
170
+
171
+ context 'when teen' do
172
+ specify { TrangeFrange::One.new('110', 0).word.should be_empty }
173
+ specify { TrangeFrange::One.new('111', 0).word.should be_empty }
174
+ specify { TrangeFrange::One.new('112', 1).word.should be_empty }
175
+ specify { TrangeFrange::One.new('113', 2).word.should be_empty }
176
+ specify { TrangeFrange::One.new('114', 3).word.should be_empty }
177
+ specify { TrangeFrange::One.new('115', 4).word.should be_empty }
178
+ specify { TrangeFrange::One.new('116', 5).word.should be_empty }
179
+ specify { TrangeFrange::One.new('117', 6).word.should be_empty }
180
+ specify { TrangeFrange::One.new('118', 7).word.should be_empty }
181
+ specify { TrangeFrange::One.new('119', 2).word.should be_empty }
182
+ end
183
+ end
184
+ end
185
+
186
+ describe TrangeFrange::Ten do
187
+ describe 'private #teen_base_member' do
188
+ specify do
189
+ TrangeFrange::Ten.new('103').send(:teen_base_member).should eq('03')
190
+ end
191
+ specify do
192
+ TrangeFrange::Ten.new('113').send(:teen_base_member).should eq('13')
193
+ end
194
+ specify do
195
+ TrangeFrange::Ten.new('123').send(:teen_base_member).should eq('23')
196
+ end
197
+ end
198
+
199
+ describe '#word' do
200
+ context 'when simple' do
201
+ specify { TrangeFrange::Ten.new('103').word.should eq(String.new) }
202
+ specify { TrangeFrange::Ten.new('123').word.should eq('dvadeset') }
203
+ specify { TrangeFrange::Ten.new('134').word.should eq('trideset') }
204
+ specify { TrangeFrange::Ten.new('145').word.should eq('četrdeset') }
205
+ specify { TrangeFrange::Ten.new('156').word.should eq('pedeset') }
206
+ specify { TrangeFrange::Ten.new('167').word.should eq('šezdeset') }
207
+ specify { TrangeFrange::Ten.new('178').word.should eq('sedamdeset') }
208
+ specify { TrangeFrange::Ten.new('189').word.should eq('osamdeset') }
209
+ specify { TrangeFrange::Ten.new('199').word.should eq('devedeset') }
210
+ end
211
+
212
+ context 'when teen' do
213
+ specify { TrangeFrange::Ten.new('111').word.should eq('jedanaest') }
214
+ specify { TrangeFrange::Ten.new('112').word.should eq('dvanaest') }
215
+ specify { TrangeFrange::Ten.new('113').word.should eq('trinaest') }
216
+ specify { TrangeFrange::Ten.new('114').word.should eq('četrnaest') }
217
+ specify { TrangeFrange::Ten.new('115').word.should eq('petnaest') }
218
+ specify { TrangeFrange::Ten.new('116').word.should eq('šesnaest') }
219
+ specify { TrangeFrange::Ten.new('117').word.should eq('sedamnaest') }
220
+ specify { TrangeFrange::Ten.new('118').word.should eq('osamnaest') }
221
+ specify { TrangeFrange::Ten.new('119').word.should eq('devetnaest') }
222
+ end
223
+ end
224
+ end
225
+
226
+ describe TrangeFrange::Hundred do
227
+ describe '#word' do
228
+ specify { TrangeFrange::Hundred.new('013').word.should eq(String.new) }
229
+ specify { TrangeFrange::Hundred.new('113').word.should eq('jedna stotina') }
230
+ specify { TrangeFrange::Hundred.new('223').word.should eq('dve stotine') }
231
+ specify { TrangeFrange::Hundred.new('334').word.should eq('tri stotine') }
232
+ specify { TrangeFrange::Hundred.new('445').word.should eq('četiri stotine') }
233
+ specify { TrangeFrange::Hundred.new('556').word.should eq('pet stotina') }
234
+ specify { TrangeFrange::Hundred.new('667').word.should eq('šest stotina') }
235
+ specify { TrangeFrange::Hundred.new('778').word.should eq('sedam stotina') }
236
+ specify { TrangeFrange::Hundred.new('889').word.should eq('osam stotina') }
237
+ specify { TrangeFrange::Hundred.new('999').word.should eq('devet stotina') }
238
+ end
239
+ end
240
+
241
+ describe TrangeFrange::Thousand do
242
+ describe '#word' do
243
+ context 'when gender' do
244
+ context 'when teen' do
245
+ specify { TrangeFrange::Thousand.new('112').word.should eq('hiljada') }
246
+ specify { TrangeFrange::Thousand.new('113').word.should eq('hiljada') }
247
+ specify { TrangeFrange::Thousand.new('114').word.should eq('hiljada') }
248
+ end
249
+
250
+ context 'when not teen' do
251
+ specify { TrangeFrange::Thousand.new('122').word.should eq('hiljade') }
252
+ specify { TrangeFrange::Thousand.new('123').word.should eq('hiljade') }
253
+ specify { TrangeFrange::Thousand.new('124').word.should eq('hiljade') }
254
+ end
255
+ end
256
+
257
+ context 'when simple non gender teen' do
258
+ specify { TrangeFrange::Thousand.new('110').word.should eq('hiljada') }
259
+ specify { TrangeFrange::Thousand.new('111').word.should eq('hiljada') }
260
+ specify { TrangeFrange::Thousand.new('115').word.should eq('hiljada') }
261
+ specify { TrangeFrange::Thousand.new('116').word.should eq('hiljada') }
262
+ specify { TrangeFrange::Thousand.new('117').word.should eq('hiljada') }
263
+ specify { TrangeFrange::Thousand.new('118').word.should eq('hiljada') }
264
+ specify { TrangeFrange::Thousand.new('119').word.should eq('hiljada') }
265
+ end
266
+
267
+ context 'when simple non gender not teen' do
268
+ specify { TrangeFrange::Thousand.new('120').word.should eq('hiljada') }
269
+ specify { TrangeFrange::Thousand.new('231').word.should eq('hiljada') }
270
+ specify { TrangeFrange::Thousand.new('345').word.should eq('hiljada') }
271
+ specify { TrangeFrange::Thousand.new('456').word.should eq('hiljada') }
272
+ specify { TrangeFrange::Thousand.new('567').word.should eq('hiljada') }
273
+ specify { TrangeFrange::Thousand.new('678').word.should eq('hiljada') }
274
+ specify { TrangeFrange::Thousand.new('789').word.should eq('hiljada') }
275
+ end
276
+ end
277
+ end
278
+
279
+ describe TrangeFrange::Milion do
280
+ describe '#word' do
281
+ context 'when one' do
282
+ context 'when not teen' do
283
+ specify { TrangeFrange::Milion.new('101').word.should eq('milion') }
284
+ specify { TrangeFrange::Milion.new('121').word.should eq('milion') }
285
+ end
286
+ end
287
+
288
+ context 'when other' do
289
+ specify { TrangeFrange::Milion.new('110').word.should eq('miliona') }
290
+ specify { TrangeFrange::Milion.new('111').word.should eq('miliona') }
291
+ specify { TrangeFrange::Milion.new('112').word.should eq('miliona') }
292
+ specify { TrangeFrange::Milion.new('123').word.should eq('miliona') }
293
+ specify { TrangeFrange::Milion.new('134').word.should eq('miliona') }
294
+ specify { TrangeFrange::Milion.new('145').word.should eq('miliona') }
295
+ specify { TrangeFrange::Milion.new('156').word.should eq('miliona') }
296
+ specify { TrangeFrange::Milion.new('167').word.should eq('miliona') }
297
+ specify { TrangeFrange::Milion.new('178').word.should eq('miliona') }
298
+ specify { TrangeFrange::Milion.new('189').word.should eq('miliona') }
299
+ end
300
+ end
301
+ end
302
+
303
+ describe TrangeFrange::Bilion do
304
+ describe '#word' do
305
+ context 'when one' do
306
+ context 'when not teen' do
307
+ specify { TrangeFrange::Bilion.new('101').word.should eq('milijarda') }
308
+ specify { TrangeFrange::Bilion.new('121').word.should eq('milijarda') }
309
+ end
310
+ end
311
+
312
+ context 'when gender' do
313
+ context 'when not teen' do
314
+ specify { TrangeFrange::Bilion.new('102').word.should eq('milijarde') }
315
+ specify { TrangeFrange::Bilion.new('123').word.should eq('milijarde') }
316
+ specify { TrangeFrange::Bilion.new('134').word.should eq('milijarde') }
317
+ end
318
+ end
319
+
320
+ context 'when other' do
321
+ specify { TrangeFrange::Bilion.new('110').word.should eq('milijardi') }
322
+ specify { TrangeFrange::Bilion.new('111').word.should eq('milijardi') }
323
+ specify { TrangeFrange::Bilion.new('112').word.should eq('milijardi') }
324
+ specify { TrangeFrange::Bilion.new('145').word.should eq('milijardi') }
325
+ specify { TrangeFrange::Bilion.new('156').word.should eq('milijardi') }
326
+ specify { TrangeFrange::Bilion.new('167').word.should eq('milijardi') }
327
+ specify { TrangeFrange::Bilion.new('178').word.should eq('milijardi') }
328
+ specify { TrangeFrange::Bilion.new('189').word.should eq('milijardi') }
329
+ end
330
+ end
331
+ end
332
+
333
+ describe TrangeFrange::Shaper do
334
+ let!(:words) { 'jedna stotina dvadeset tri hiljade četiri stotine pedeset šest' }
335
+
336
+ specify do
337
+ TrangeFrange::Shaper.new(words, 75, {}).shape!.should \
338
+ eq('jedna stotina dvadeset tri hiljade četiri stotine pedeset šest')
339
+ end
340
+ specify do
341
+ TrangeFrange::Shaper.new(words, 75, show_fraction: true).shape!.should \
342
+ eq("jedna stotina dvadeset tri hiljade četiri stotine pedeset šest i 75/100")
343
+ end
344
+ specify do
345
+ TrangeFrange::Shaper.new(words, 75, show_fraction: true, squeeze: true).shape!.should \
346
+ eq("jednastotinadvadesettrihiljadečetiristotinepedesetšest i 75/100")
347
+ end
348
+ specify do
349
+ TrangeFrange::Shaper.new(words, 75, show_fraction: true, squeeze: true, bald: true).shape!.should \
350
+ eq("jednastotinadvadesettrihiljadecetiristotinepedesetsest i 75/100")
351
+ end
352
+ end
353
+
354
+ describe TrangeFrange::Amount do
355
+ describe '#amount' do
356
+ context 'when valid amount' do
357
+ specify do
358
+ amount = TrangeFrange::Amount.new 123
359
+ amount.amount.should eq(123)
360
+ end
361
+
362
+ specify do
363
+ amount = TrangeFrange::Amount.new 123.45
364
+ amount.amount.should eq(123.45)
365
+ end
366
+ end
367
+
368
+ context 'when invalid amount' do
369
+ specify 'raise an exception' do
370
+ expect { TrangeFrange::Amount.new('123') }.to \
371
+ raise_error(TypeError, 'Amount must be of type Fixnum or Float.')
372
+ end
373
+ specify 'raise an exception' do
374
+ expect { TrangeFrange::Amount.new(1234657981234) }.to \
375
+ raise_error(NotImplementedError, 'I can only work with amounts up to 999 bilions.')
376
+ end
377
+ end
378
+ end
379
+
380
+ describe '#spell!' do
381
+ context 'when valid amount' do
382
+ context 'when options are ommited' do
383
+ specify do
384
+ amount = TrangeFrange::Amount.new 123456.78
385
+ amount.spell!.should eq('jedna stotina dvadeset tri hiljade četiri stotine pedeset šest')
386
+ end
387
+ end
388
+
389
+ context 'when `show_fraction` option is true' do
390
+ specify do
391
+ amount = TrangeFrange::Amount.new 123456.78
392
+ amount.spell!(show_fraction: true).should eq('jedna stotina dvadeset tri hiljade četiri stotine pedeset šest i 78/100')
393
+ end
394
+ end
395
+
396
+ context 'when `show_fraction` option is false' do
397
+ specify do
398
+ amount = TrangeFrange::Amount.new 123456.78
399
+ amount.spell!(show_fraction: false).should eq('jedna stotina dvadeset tri hiljade četiri stotine pedeset šest')
400
+ end
401
+ end
402
+
403
+ context 'when `squeeze` option is true' do
404
+ specify do
405
+ amount = TrangeFrange::Amount.new 123456.78
406
+ amount.spell!(squeeze: true).should eq('jednastotinadvadesettrihiljadečetiristotinepedesetšest')
407
+ end
408
+ end
409
+
410
+ context 'when `bald` option is true' do
411
+ specify do
412
+ amount = TrangeFrange::Amount.new 123456.78
413
+ amount.spell!(bald: true).should eq('jedna stotina dvadeset tri hiljade cetiri stotine pedeset sest')
414
+ end
415
+ end
416
+
417
+ context 'when options are combined' do
418
+ specify do
419
+ amount = TrangeFrange::Amount.new 123456.78
420
+ amount.spell!(show_fraction: true, squeeze: true, bald: true).should \
421
+ eq('jednastotinadvadesettrihiljadecetiristotinepedesetsest i 78/100')
422
+ end
423
+ end
424
+
425
+ specify do
426
+ amount = TrangeFrange::Amount.new 1
427
+ amount.spell!(show_fraction: true).should eq('jedan i 00/100')
428
+ end
429
+ specify do
430
+ amount = TrangeFrange::Amount.new 12.34
431
+ amount.spell!(show_fraction: true).should eq('dvanaest i 34/100')
432
+ end
433
+ specify do
434
+ amount = TrangeFrange::Amount.new 123.45
435
+ amount.spell!(show_fraction: true).should eq('jedna stotina dvadeset tri i 45/100')
436
+ end
437
+ specify do
438
+ amount = TrangeFrange::Amount.new 1234.56
439
+ amount.spell!(show_fraction: true).should eq('jedna hiljada dve stotine trideset četiri i 56/100')
440
+ end
441
+ specify do
442
+ amount = TrangeFrange::Amount.new 12345.67
443
+ amount.spell!(show_fraction: true).should eq('dvanaest hiljada tri stotine četrdeset pet i 67/100')
444
+ end
445
+ specify do
446
+ amount = TrangeFrange::Amount.new 123456.78
447
+ amount.spell!(show_fraction: true).should eq('jedna stotina dvadeset tri hiljade četiri stotine pedeset šest i 78/100')
448
+ end
449
+ specify do
450
+ amount = TrangeFrange::Amount.new 1234567.89
451
+ amount.spell!(show_fraction: true).should eq('jedan milion dve stotine trideset četiri hiljade pet stotina šezdeset sedam i 89/100')
452
+ end
453
+ specify do
454
+ amount = TrangeFrange::Amount.new 12345678
455
+ amount.spell!(show_fraction: true).should eq('dvanaest miliona tri stotine četrdeset pet hiljada šest stotina sedamdeset osam i 00/100')
456
+ end
457
+ specify do
458
+ amount = TrangeFrange::Amount.new 123456789
459
+ amount.spell!(show_fraction: true).should eq('jedna stotina dvadeset tri miliona četiri stotine pedeset šest hiljada sedam stotina osamdeset devet i 00/100')
460
+ end
461
+ specify do
462
+ amount = TrangeFrange::Amount.new 1234567890
463
+ amount.spell!(show_fraction: true).should eq('jedna milijarda dve stotine trideset četiri miliona pet stotina šezdeset sedam hiljada osam stotina devedeset i 00/100')
464
+ end
465
+ specify do
466
+ amount = TrangeFrange::Amount.new 12345678901
467
+ amount.spell!(show_fraction: true).should eq('dvanaest milijardi tri stotine četrdeset pet miliona šest stotina sedamdeset osam hiljada devet stotina jedan i 00/100')
468
+ end
469
+ specify do
470
+ amount = TrangeFrange::Amount.new 123456789012
471
+ amount.spell!(show_fraction: true).should eq('jedna stotina dvadeset tri milijarde četiri stotine pedeset šest miliona sedam stotina osamdeset devet hiljada dvanaest i 00/100')
472
+ end
473
+ end
474
+ end
475
+
476
+ describe 'PRIVATE' do
477
+ describe '#split!' do
478
+ specify do
479
+ amount = TrangeFrange::Amount.new 12345
480
+ amount.send(:split!).should eq(['12345', '00'])
481
+ end
482
+
483
+ specify do
484
+ amount = TrangeFrange::Amount.new 12345.67
485
+ amount.send(:split!).should eq(['12345', '67'])
486
+ end
487
+
488
+ specify do
489
+ amount = TrangeFrange::Amount.new 12345.678
490
+ amount.send(:split!).should eq(['12345', '68'])
491
+ end
492
+ end
493
+
494
+ describe '#whole_number' do
495
+ specify { TrangeFrange::Amount.new(12345.67).send(:whole_number).should eq('12345') }
496
+ end
497
+
498
+ describe '#fraction' do
499
+ specify { TrangeFrange::Amount.new(12345.678).send(:fraction).should eq('68') }
500
+ end
501
+
502
+ describe '#generate_base!' do
503
+ specify do
504
+ amount = TrangeFrange::Amount.new 123
505
+ amount.send(:generate_base!, '123', 0).should \
506
+ eq('jedna stotina dvadeset tri')
507
+ end
508
+ end
509
+
510
+ describe '#generate_suffix!' do
511
+ context 'when magnitude is greater than zero' do
512
+ specify do
513
+ amount = TrangeFrange::Amount.new 123000
514
+ amount.send(:generate_suffix!, '123', 1).should eq('hiljade')
515
+ end
516
+ end
517
+
518
+ context 'when magnitude is zero' do
519
+ specify do
520
+ amount = TrangeFrange::Amount.new 123
521
+ amount.send(:generate_suffix!, '123', 0).should eq(String.new)
522
+ end
523
+ end
524
+ end
525
+
526
+ describe '#members' do
527
+ specify do
528
+ amount = TrangeFrange::Amount.new 1234567.89
529
+ amount.send(:members).should match_array(['1', '234', '567'])
530
+ end
531
+ end
532
+
533
+ describe '#generate_words' do
534
+ specify do
535
+ amount = TrangeFrange::Amount.new 12345.67
536
+ amount.send(:generate_words!).should eq('dvanaest hiljada tri stotine četrdeset pet')
537
+ end
538
+ end
539
+ end
540
+ end
541
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/trange_frange/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'trange_frange'
7
+ gem.version = TrangeFrange::VERSION
8
+ gem.summary = %q{Tool for spelling amounts}
9
+ gem.description = %q{The tool spells out numbers (amounts) in words. It supports serbian language.}
10
+ gem.license = 'MIT'
11
+ gem.authors = ['Ninoslav Milenovic']
12
+ gem.email = 'nino.mil@gmail.com'
13
+ gem.homepage = 'https://github.com/pythogorian/trange_frange#readme'
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_development_dependency 'rdoc', '~> 3.0'
21
+ gem.add_development_dependency 'rspec', '~> 2.4'
22
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
23
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trange_frange
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ninoslav Milenovic
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.4'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.4'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rubygems-tasks
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.2'
62
+ description: The tool spells out numbers (amounts) in words. It supports serbian language.
63
+ email: nino.mil@gmail.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - .document
69
+ - .gitignore
70
+ - .rspec
71
+ - ChangeLog.md
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/trange_frange.rb
76
+ - lib/trange_frange/version.rb
77
+ - spec/spec_helper.rb
78
+ - spec/trange_frange_spec.rb
79
+ - trange_frange.gemspec
80
+ homepage: https://github.com/pythogorian/trange_frange#readme
81
+ licenses:
82
+ - MIT
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.24
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Tool for spelling amounts
105
+ test_files:
106
+ - spec/spec_helper.rb
107
+ - spec/trange_frange_spec.rb