farsifu 0.4.1 → 0.5.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/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: