farsifu 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,8 +2,9 @@
2
2
  farsifu is a toolbox for developing ruby applications in Persian (Farsi) language.
3
3
 
4
4
  ## Features
5
- * Converting numbers to Persian numbers
6
- * Spelling numbers in Persian (also support ordinal spelling)
5
+ * Converting numbers to and from Persian numbers
6
+ * Spelling numbers in Persian (supports ordinal spelling of numbers in Persian)
7
+ * Converting Persian spelling of numbers back to normal numbers (see examples below)
7
8
  * List of Iran's provinces, cities, counties
8
9
  * List of countries in Persian
9
10
 
@@ -15,7 +16,10 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
15
16
  -2567023.spell_farsi # => "منفی دو میلیون و پانصد و شصت و هفت هزار و بیست و سه"
16
17
  7.53.spell_farsi # => "هفت ممیز پنجاه و سه صدم"
17
18
  -0.999.spell_farsi # => "منفی صفر ممیز نهصد و نود و نه هزارم"
19
+ # Passing false to spell_farsi method will turn off the verbose mode.
20
+ -0.999.spell_farsi(false) # => "منفی نهصد و نود و نه هزارم"
18
21
  12.spell_ordinal_farsi # => "دوازدهم"
22
+ # Note the different when you pass true to spell_ordinal_farsi method.
19
23
  12.spell_ordinal_farsi(true) # => "دوازدهمین"
20
24
  "هزار و چهل و پنج".farsi_to_number # => 1045
21
25
 
@@ -35,46 +39,39 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
35
39
  gem install farsifu
36
40
 
37
41
  ## Changelog
42
+ ### 0.5.0 - 15.FEB.2013
43
+ * [Arash Mousavi](https://github.com/arashm) is now a collaborator.
44
+ * Passing false to spell_farsi method will turn off the verbose mode.
45
+ * Major internal refactoring. Should not change the external API.
46
+
38
47
  ### 0.4.0 - 4.FEB.2013
39
- * added `farsi_to_number` to convert farsi spelling of numbers to real numbers , courtesy of [Arash Mousavi](https://github.com/arashm)
48
+ * Added `farsi_to_number` to convert farsi spelling of numbers to real numbers , courtesy of [Arash Mousavi](https://github.com/arashm)
40
49
  * Major refactoring and reorganization of the code, courtesy of [Arash Mousavi](https://github.com/arashm)
41
50
 
42
-
43
51
  ### 0.3.0 - 28.JAN.2013
44
- * added farsi ordinal spelling, courtesy of [Arash Mousavi](https://github.com/arashm)
45
-
52
+ * Added Farsi ordinal spelling, courtesy of [Arash Mousavi](https://github.com/arashm)
46
53
 
47
54
  ### 0.2.2 - 11.APR.2011
48
- * added ruby 1.9 compatibility, courtesy of Brian Kaney
55
+ * Added ruby 1.9 compatibility, courtesy of Brian Kaney
49
56
 
50
57
  ### 0.2.1 - 11.JAN.2011
51
- * updated readme
52
- * now using rspec 2.4
53
- * no longer replacing * with ×
58
+ * Updated Readme
59
+ * Updated rspec to 2.4
60
+ * No longer replacing * with ×
54
61
 
55
62
  ### 0.2 - 2.MAR.2010
56
- * renamed gem from FarsiFu to farsifu
63
+ * Renamed gem from FarsiFu to farsifu
57
64
  * Added a spec suite
58
65
  * Migrated the gem to rubygems.org
59
66
  * Added Iran Module
60
67
 
61
68
  ### 0.02 - 10.AUG.2008
62
- * converted into a gem
63
- * rdocs added
69
+ * Converted into a gem
70
+ * Added rdocs documentation
64
71
 
65
72
  ### 0.01 - 07.AUG.2008
66
- * initial release
67
-
68
-
69
- ## Note on Patches/Pull Requests
73
+ * Initial release
70
74
 
71
- * Fork the project.
72
- * Make your feature addition or bug fix.
73
- * Add tests for it. This is important so I don't break it in a
74
- future version unintentionally.
75
- * Commit, do not mess with rakefile, version, or history.
76
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
77
- * Send me a pull request. Bonus points for topic branches.
78
75
 
79
76
  ## Copyright
80
77
 
data/farsifu.gemspec CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
6
6
  s.name = "farsifu"
7
7
  s.version = FarsiFu::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Allen A. Bargi"]
10
- s.email = %q{allen.bargi@gmail.com}
9
+ s.authors = ["Allen A. Bargi", "Arash Mousavi"]
10
+ s.email = %q{allen.bargi@gmail.com mousavi.arash@gmail.com}
11
11
  s.homepage = %q{http://github.com/aziz/farsifu}
12
12
  s.summary = %q{a toolbox for developing ruby applications in Persian (Farsi) language, see readme file for features}
13
13
  s.description = %q{a toolbox for developing ruby applications in Persian (Farsi) language, see readme file for features}
@@ -4,16 +4,9 @@ module FarsiFu
4
4
  PERSIAN_CHARS = "۱۲۳۴۵۶۷۸۹۰،؛"
5
5
  ENGLISH_CHARS = "1234567890,;"
6
6
 
7
- PERSIAN_DIGIT_JOINT = " و "
8
- PERSIAN_DIGIT_SIGN = ["منفی ", "مثبت ", " ممیز "]
9
-
10
- PERSIAN_DIGIT_SPELL = {
11
- 0 => [ nil ,"یک","دو","سه","چهار","پنج","شش","هفت","هشت","نه", "صفر"] ,
12
- 1 => [ nil ,"ده","بیست","سی","چهل","پنجاه","شصت","هفتاد","هشتاد","نود"],
13
- 2 => [ nil ,"صد","دویست","سیصد","چهارصد","پانصد","ششصد","هفتصد","هشتصد","نهصد"],
14
- "10..19" => [ "ده" ,"یازده","دوازده","سیزده","چهارده","پانزده","شانزده","هفده","هجده","نوزده"],
15
- "zillion" => [ nil ,"هزار","میلیون","میلیارد","بیلیون","تریلیون","کوادریلیون","کوینتیلیون","سیکستیلیون","سپتیلیون","اکتیلیون","نونیلیون","دسیلیون"],
16
- "decimals" => [ nil, "دهم", "صدم", "هزارم", "ده‌هزارم", "صدهزارم", "میلیونیم", "ده‌میلیونیم","صدمیلیونیم","میلیاردیم"]
7
+ SIGNS ={
8
+ "-" => "منفی ",
9
+ "+" => "مثبت "
17
10
  }
18
11
 
19
12
  EXCEPTIONS = {
@@ -58,10 +51,11 @@ module FarsiFu
58
51
  "نهصد" => 900
59
52
  }
60
53
 
54
+ EXCEPTIONS_INVERT = EXCEPTIONS.invert
55
+
61
56
  POWER_OF_TEN = {
62
- # based on:
57
+ # based on:
63
58
  # https://fa.wikipedia.org/wiki/%D9%86%D8%A7%D9%85_%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8%A8%D8%B2%D8%B1%DA%AF
64
- "صفر" => 0,
65
59
  "ده" => 1,
66
60
  "هزار" => 3,
67
61
  "میلیون" => 6,
@@ -86,4 +80,6 @@ module FarsiFu
86
80
  "دسیلیارد" => 63,
87
81
  "گوگول" => 100
88
82
  }
83
+
84
+ POWER_OF_TEN_INVERT = POWER_OF_TEN.invert
89
85
  end
@@ -3,8 +3,11 @@
3
3
  module FarsiFu
4
4
  class NumToWord
5
5
 
6
- def initialize(number)
7
- @number = number
6
+ def initialize(number, verbose = true)
7
+ @number = number.to_s
8
+ @sign = check_for_sign
9
+ @float = true if number.is_a? Float
10
+ @verbose = verbose
8
11
  end
9
12
 
10
13
  # Spells a number in Persian
@@ -12,18 +15,12 @@ module FarsiFu
12
15
  #
13
16
  # Example:
14
17
  # 5678.spell_farsi # => "پنج هزار و ششصد و هفتاد و هشت"
18
+ # 3.22.spell_farsi # => "سه ممیز بیست و دو صدم"
15
19
  def spell_farsi
16
- # Distigushing the number (float and )
17
- if @number.class == Float
18
- num_array = @number.to_f.to_s.split(".").first.split(//).reverse
19
- dec_array = @number.to_f.to_s.split(".").last.split(//).slice(0..9).compact.reverse
20
- dec_copy_b = dec_array.clone ; dec_copy_a = dec_array.clone
21
- result = spell(num_array)
22
- ( result += PERSIAN_DIGIT_SIGN[2] + spell(dec_array) + " " + PERSIAN_DIGIT_SPELL["decimals"][dec_copy_a.size].to_s ) unless [PERSIAN_DIGIT_SPELL[0][10],""].include? spell(dec_copy_b)
23
- return result
20
+ if @float
21
+ parse_and_spell_float
24
22
  else
25
- num_array = @number.to_i.to_s.split(//).reverse
26
- return spell(num_array)
23
+ parse_and_spell_real_number
27
24
  end
28
25
  end
29
26
 
@@ -34,57 +31,96 @@ module FarsiFu
34
31
  # 121.spell_ordinal_farsi # => "صد و بیست و یکم"
35
32
  # 2.spell_ordinal_farsi(true) # => "دومین"
36
33
  # 2054.spell_ordinal_farsi(true) # => "دو هزار و پنجاه چهارمین"
37
- def spell_ordinal_farsi(*args)
38
- if args[0]
39
- exceptions = {0 => "صفر", 1 => "اولین", 3 => "سومین"}
40
- suffix = "مین"
34
+ def spell_ordinal_farsi(second_type = false)
35
+ if second_type
36
+ exceptions = {'0' => "صفر", '1' => "اولین", '3' => "سومین"}
37
+ suffix = "مین"
41
38
  else
42
- exceptions = {0 => "صفر", 1 => "اول", 3 => "سوم"}
43
- suffix = "م"
39
+ exceptions = {'0' => "صفر", '1' => "اول", '3' => "سوم"}
40
+ suffix = "م"
44
41
  end
45
42
 
46
43
  make_ordinal_spell(exceptions, suffix)
47
44
  end
48
45
 
49
- private #---------------------------------------------------------
50
- def spell(num_array)
51
- # Dealing with signs
52
- sign_m = num_array.include?("-") ? PERSIAN_DIGIT_SIGN[0] : ""
53
- sign_p = num_array.include?("+") ? PERSIAN_DIGIT_SIGN[1] : ""
54
- num_array.delete_at(num_array.index("-")) if sign_m.size > 0
55
- num_array.delete_at(num_array.index("+")) if sign_p.size > 0
56
- sign = sign_m + sign_p
46
+ private
47
+ def parse_and_spell_real_number
48
+ answer = []
49
+ group_by_power do |power, num|
50
+ three_digit_spell = spell_three_digits(num, power)
51
+ answer.concat three_digit_spell
52
+ end
53
+ spell = answer.compact.reverse.join(' و ').prepend("#{SIGNS[@sign]}")
54
+ # verbose false?
55
+ spell.gsub!(/^(منفی\s|مثبت\s)*یک\sهزار/) {"#{$1}هزار"} unless @verbose
56
+ spell
57
+ end
57
58
 
58
- zillion = 0
59
- farsi_number = []
59
+ def parse_and_spell_float
60
+ # Seperate floating point
61
+ float_num = @number.match(/\./)
62
+ pre_num, post_num = float_num.pre_match.prepend("#{@sign}"), float_num.post_match
63
+ # To convert it to دهم, صدم...
64
+ floating_point_power = 10 ** post_num.size
60
65
 
61
- # Dealing with Zero
62
- if (num_array.length == 1 && num_array[0] == "0" )
63
- farsi_number = [PERSIAN_DIGIT_SPELL[0][10]]
64
- num_array = []
66
+ pre_num_spell = NumToWord.new(pre_num).spell_farsi
67
+ pre_num_spell << 'صفر' if pre_num == '0' and @verbose
68
+ post_num_spell = NumToWord.new(post_num).spell_farsi
69
+ floating_point_power_spell = NumToWord.new(floating_point_power, false).spell_ordinal_farsi.gsub(/یک\s*/, '')
70
+
71
+ if pre_num != '0' or @verbose
72
+ "#{pre_num_spell} ممیز #{post_num_spell} #{floating_point_power_spell}"
73
+ else
74
+ "#{pre_num_spell if pre_num_spell.size > 0}#{post_num_spell} #{floating_point_power_spell}"
65
75
  end
76
+ end
66
77
 
67
- while num_array.length > 0 do
68
- spelling = []
69
- num_array[0..2].each_with_index do |digit,index|
70
- spelling[index] = PERSIAN_DIGIT_SPELL[index][digit.to_i]
71
- if index == 1 && digit == "1" # Dealing with 10..19
72
- spelling[1] = PERSIAN_DIGIT_SPELL["10..19"][num_array[0].to_i]
73
- spelling[0] = nil
74
- end
75
- end
78
+ # checks if the first char is `+` or `-` and returns the sign
79
+ def check_for_sign
80
+ sign = @number.slice(0).match(/(-|\+)/)
81
+ if sign
82
+ # remove the sign from number
83
+ @number.slice!(0)
84
+ sign[1]
85
+ end
86
+ end
76
87
 
77
- 3.times { num_array.shift if num_array.length > 0 } # Eliminating the first 3 number of the array
78
- dig = spelling.reverse.compact.join(PERSIAN_DIGIT_JOINT)
79
- if dig.size > 0
80
- dig << (" " + PERSIAN_DIGIT_SPELL["zillion"][zillion].to_s)
81
- farsi_number.unshift(dig)
82
- end
88
+ # '1234567' #=> {0=>["7", "6", "5"], 3=>["4", "3", "2"], 6=>["1"]}
89
+ def group_by_power &block
90
+ power = 0
91
+ @number.split('').reverse.each_slice(3) do |digit|
92
+ yield power, digit
93
+ power += 3
94
+ end
95
+ end
83
96
 
84
- zillion += 1
85
- end # End of While
97
+ # ["7", "6", "5"], 3 #=> ['هفت هزار', 'شصت', 'پانصد']
98
+ def spell_three_digits(num, power)
99
+ answer = []
100
+ yekan = nil
101
+ num.each_with_index do |n, i|
102
+ # The 'n' is zero? no need to evaluate
103
+ next if n == '0'
104
+ exception_index = n.to_i * (10 ** i)
86
105
 
87
- sign + farsi_number.compact.join(PERSIAN_DIGIT_JOINT).strip
106
+ case i
107
+ when 0
108
+ # save Yekan to use for 10..19 exceptions
109
+ yekan = n
110
+ when 1
111
+ # If we're in Sadgan and the digit is 1 so it's a number
112
+ # between 10..19 and it's an exception
113
+ if n == '1'
114
+ exception_index = 10 + yekan.to_i
115
+ answer.clear
116
+ end
117
+ end
118
+ answer << EXCEPTIONS_INVERT[exception_index]
119
+ end
120
+ # append power of ten to first number based on `power` passed to function
121
+ # ["7", "6", "5"], 3 #=> ['هفت هزار', 'شصت', 'پانصد']
122
+ answer[0] = "#{answer[0]} #{(POWER_OF_TEN_INVERT[power])}".strip if answer.size > 0
123
+ answer
88
124
  end
89
125
 
90
126
  def make_ordinal_spell(exceptions, suffix)
data/lib/farsifu/punch.rb CHANGED
@@ -10,12 +10,12 @@ module Convert
10
10
  end
11
11
 
12
12
  module NumToWord
13
- def spell_farsi
14
- FarsiFu::NumToWord.new(self).spell_farsi
13
+ def spell_farsi(verbose = true)
14
+ FarsiFu::NumToWord.new(self, verbose).spell_farsi
15
15
  end
16
16
 
17
- def spell_ordinal_farsi(*args)
18
- FarsiFu::NumToWord.new(self).spell_ordinal_farsi(args[0])
17
+ def spell_ordinal_farsi(second_type = false, verbose = true)
18
+ FarsiFu::NumToWord.new(self, verbose).spell_ordinal_farsi(second_type)
19
19
  end
20
20
  end
21
21
 
@@ -27,6 +27,7 @@ end
27
27
 
28
28
  class String
29
29
  include Convert
30
+ include NumToWord
30
31
  include WordToNum
31
32
  end
32
33
 
@@ -34,8 +35,3 @@ class Numeric
34
35
  include Convert
35
36
  include NumToWord
36
37
  end
37
-
38
- # Seems that Numeric works for both Float and Integers
39
- # class Float
40
- # include NumToWord
41
- # end
@@ -1,3 +1,3 @@
1
1
  module FarsiFu
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
data/spec/farsifu_spec.rb CHANGED
@@ -22,6 +22,7 @@ describe "Farsifu" do
22
22
  it "should be able to spell positive and negetive integers in Persian" do
23
23
  1024.spell_farsi.should == "یک هزار و بیست و چهار"
24
24
  -2567023.spell_farsi.should == "منفی دو میلیون و پانصد و شصت و هفت هزار و بیست و سه"
25
+ '+2567023'.spell_farsi.should == "مثبت دو میلیون و پانصد و شصت و هفت هزار و بیست و سه"
25
26
  end
26
27
 
27
28
  it "should be able to spell positive and negetive floats in Persian" do
@@ -32,6 +33,13 @@ describe "Farsifu" do
32
33
  -0.999.spell_farsi.should == "منفی صفر ممیز نهصد و نود و نه هزارم"
33
34
  end
34
35
 
36
+ it "should spell in non-verbose mode" do
37
+ 1204.spell_farsi(false).should eq('هزار و دویست و چهار')
38
+ -0.2.spell_farsi(false).should eq('منفی دو دهم')
39
+ # shouldn't affect floats without zero at the beginning
40
+ 1.2.spell_farsi(false).should eq('یک ممیز دو دهم')
41
+ end
42
+
35
43
  it "should be able to show first type of sequentional numbers to persian" do
36
44
  nums = {0 => "صفر",1 => "اول", 3 => "سوم", 12 => "دوازدهم", 33 => "سی و سوم", 121=> "صد و بیست و یکم"}
37
45
  nums.each do |k, v|
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: farsifu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Allen A. Bargi
9
+ - Arash Mousavi
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-02-05 00:00:00.000000000 Z
13
+ date: 2013-02-15 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: rspec
@@ -61,7 +62,7 @@ dependencies:
61
62
  version: '0'
62
63
  description: a toolbox for developing ruby applications in Persian (Farsi) language,
63
64
  see readme file for features
64
- email: allen.bargi@gmail.com
65
+ email: allen.bargi@gmail.com mousavi.arash@gmail.com
65
66
  executables: []
66
67
  extensions: []
67
68
  extra_rdoc_files: