trange_frange 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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