farsifu 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ tmp
data/Gemfile.lock CHANGED
@@ -1,12 +1,29 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- farsifu (0.3.0)
4
+ farsifu (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
+ coderay (1.0.8)
9
10
  diff-lcs (1.1.3)
11
+ guard (1.6.2)
12
+ listen (>= 0.6.0)
13
+ lumberjack (>= 1.0.2)
14
+ pry (>= 0.9.10)
15
+ terminal-table (>= 1.4.3)
16
+ thor (>= 0.14.6)
17
+ guard-rspec (2.4.0)
18
+ guard (>= 1.1)
19
+ rspec (~> 2.11)
20
+ listen (0.7.2)
21
+ lumberjack (1.0.2)
22
+ method_source (0.8.1)
23
+ pry (0.9.11.4)
24
+ coderay (~> 1.0.5)
25
+ method_source (~> 0.8)
26
+ slop (~> 3.4)
10
27
  rspec (2.12.0)
11
28
  rspec-core (~> 2.12.0)
12
29
  rspec-expectations (~> 2.12.0)
@@ -15,6 +32,9 @@ GEM
15
32
  rspec-expectations (2.12.1)
16
33
  diff-lcs (~> 1.1.3)
17
34
  rspec-mocks (2.12.1)
35
+ slop (3.4.3)
36
+ terminal-table (1.4.5)
37
+ thor (0.17.0)
18
38
 
19
39
  PLATFORMS
20
40
  ruby
@@ -22,4 +42,5 @@ PLATFORMS
22
42
  DEPENDENCIES
23
43
  bundler (~> 1.2.0)
24
44
  farsifu!
45
+ guard-rspec
25
46
  rspec (~> 2.12.0)
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/README.md CHANGED
@@ -17,6 +17,7 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
17
17
  -0.999.spell_farsi # => "منفی صفر ممیز نهصد و نود و نه هزارم"
18
18
  12.spell_ordinal_farsi # => "دوازدهم"
19
19
  12.spell_ordinal_farsi(true) # => "دوازدهمین"
20
+ "هزار و چهل و پنج".farsi_to_number # => 1045
20
21
 
21
22
 
22
23
  Iran::Provinces
@@ -33,9 +34,14 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
33
34
  ## Install
34
35
  gem install farsifu
35
36
 
36
- ## History
37
+ ## Changelog
38
+ ### 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)
40
+ * Major refactoring and reorganization of the code, courtesy of [Arash Mousavi](https://github.com/arashm)
41
+
42
+
37
43
  ### 0.3.0 - 28.JAN.2013
38
- * added farsi ordinal spelling, courtesy of Arash Mousavi
44
+ * added farsi ordinal spelling, courtesy of [Arash Mousavi](https://github.com/arashm)
39
45
 
40
46
 
41
47
  ### 0.2.2 - 11.APR.2011
data/farsifu.gemspec CHANGED
@@ -21,4 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.rdoc_options = ["--charset=UTF-8"]
22
22
  s.add_development_dependency(%q<rspec>, ["~> 2.12.0"])
23
23
  s.add_development_dependency(%q<bundler>, ["~> 1.2.0"])
24
+ s.add_development_dependency(%q<guard-rspec>)
24
25
  end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ module FarsiFu
4
+ PERSIAN_CHARS = "۱۲۳۴۵۶۷۸۹۰،؛"
5
+ ENGLISH_CHARS = "1234567890,;"
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, "دهم", "صدم", "هزارم", "ده‌هزارم", "صدهزارم", "میلیونیم", "ده‌میلیونیم","صدمیلیونیم","میلیاردیم"]
17
+ }
18
+
19
+ EXCEPTIONS = {
20
+ "یک" => 1,
21
+ "دو" => 2,
22
+ "سه" => 3,
23
+ "چهار" => 4,
24
+ "پنج" => 5,
25
+ "شش" => 6,
26
+ "هفت" => 7,
27
+ "هشت" => 8,
28
+ "نه" => 9,
29
+
30
+ "یازده" => 11,
31
+ "دوازده" => 12,
32
+ "سیزده" => 13,
33
+ "چهارده" => 14,
34
+ "پانزده" => 15,
35
+ "شانزده" => 16,
36
+ "هفده" => 17,
37
+ "هجده" => 18,
38
+ "نوزده" => 19,
39
+
40
+ "ده" => 10,
41
+ "بیست" => 20,
42
+ "سی" => 30,
43
+ "چهل" => 40,
44
+ "پنجاه" => 50,
45
+ "شصت" => 60,
46
+ "هفتاد" => 70,
47
+ "هشتاد" => 80,
48
+ "نود" => 90,
49
+
50
+ "صد" => 100,
51
+ "دویست" => 200,
52
+ "سیصد" => 300,
53
+ "چهارصد" => 400,
54
+ "پانصد" => 500,
55
+ "ششصد" => 600,
56
+ "هفتصد" => 700,
57
+ "هشتصد" => 800,
58
+ "نهصد" => 900
59
+ }
60
+
61
+ POWER_OF_TEN = {
62
+ # based on:
63
+ # 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
+ "ده" => 1,
66
+ "هزار" => 3,
67
+ "میلیون" => 6,
68
+ "میلیارد" => 9,
69
+ "بیلیون" => 12,
70
+ "بیلیارد" => 15,
71
+ "تریلیون" => 18,
72
+ "تریلیارد" => 21,
73
+ "کادریلیون" => 24,
74
+ "کادریلیارد" => 27,
75
+ "کوانتینیوم" => 30,
76
+ "کوانتینیارد" => 33,
77
+ "سکستیلیون" => 36,
78
+ "سکستیلیارد" => 39,
79
+ "دسیلیون" => 42,
80
+ "سپتیلیارد" => 45,
81
+ "اکتیلیون" => 48,
82
+ "اکتیلیارد" => 51,
83
+ "نانیلیون" => 54,
84
+ "نانیلیارد" => 57,
85
+ "دسیلیون" => 60,
86
+ "دسیلیارد" => 63,
87
+ "گوگول" => 100
88
+ }
89
+ end
@@ -0,0 +1,35 @@
1
+ module FarsiFu
2
+ class Convert
3
+
4
+ def initialize(number)
5
+ @number = number
6
+ end
7
+
8
+ # :startdoc:
9
+
10
+ # Returns a string which is the equivalent English number of a Persian number (in String)
11
+ #
12
+ # Example:
13
+ # "۱۲۳".to_english # => "123"
14
+ def to_english
15
+ self.to_s.tr(PERSIAN_CHARS,ENGLISH_CHARS)
16
+ end
17
+
18
+ # Returns a string which is the equivalent Persian number of an English number (in String)
19
+ # accepts instances of String, Integer and Numeric classes (Fixnum,Bignum and floats are accepted)
20
+ #
21
+ # alias: to_persian
22
+ #
23
+ # Example:
24
+ # "123".to_farsi # => "۱۲۳"
25
+ # "456".to_persian # => "۴۵۶"
26
+ # 789.to_farsi # => "۷۸۹"
27
+ def to_farsi
28
+ self.to_s.tr(ENGLISH_CHARS,PERSIAN_CHARS)
29
+ end
30
+
31
+ def to_s
32
+ @number.to_s
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: utf-8
2
+
3
+ module FarsiFu
4
+ class NumToWord
5
+
6
+ def initialize(number)
7
+ @number = number
8
+ end
9
+
10
+ # Spells a number in Persian
11
+ # accpets english numbers (in float,fixnum or string)
12
+ #
13
+ # Example:
14
+ # 5678.spell_farsi # => "پنج هزار و ششصد و هفتاد و هشت"
15
+ 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
24
+ else
25
+ num_array = @number.to_i.to_s.split(//).reverse
26
+ return spell(num_array)
27
+ end
28
+ end
29
+
30
+ # Spells numbers in sequentional format. If pass `true`, it will use the second format
31
+ #
32
+ # Example:
33
+ # 1.spell_ordinal_farsi # => "اول"
34
+ # 121.spell_ordinal_farsi # => "صد و بیست و یکم"
35
+ # 2.spell_ordinal_farsi(true) # => "دومین"
36
+ # 2054.spell_ordinal_farsi(true) # => "دو هزار و پنجاه چهارمین"
37
+ def spell_ordinal_farsi(*args)
38
+ if args[0]
39
+ exceptions = {0 => "صفر", 1 => "اولین", 3 => "سومین"}
40
+ suffix = "مین"
41
+ else
42
+ exceptions = {0 => "صفر", 1 => "اول", 3 => "سوم"}
43
+ suffix = "م"
44
+ end
45
+
46
+ make_ordinal_spell(exceptions, suffix)
47
+ end
48
+
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
57
+
58
+ zillion = 0
59
+ farsi_number = []
60
+
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 = []
65
+ end
66
+
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
76
+
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
83
+
84
+ zillion += 1
85
+ end # End of While
86
+
87
+ sign + farsi_number.compact.join(PERSIAN_DIGIT_JOINT).strip
88
+ end
89
+
90
+ def make_ordinal_spell(exceptions, suffix)
91
+ if exceptions.include? @number
92
+ exceptions[@number]
93
+ else
94
+ (spell_farsi + suffix).gsub(/سه(م|مین)$/) { "سو#{$1}" }
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,40 @@
1
+ module Convert
2
+ def to_farsi
3
+ FarsiFu::Convert.new(self).to_farsi
4
+ end
5
+ alias_method :to_persian, :to_farsi
6
+
7
+ def to_english
8
+ FarsiFu::Convert.new(self).to_english
9
+ end
10
+ end
11
+
12
+ module NumToWord
13
+ def spell_farsi
14
+ FarsiFu::NumToWord.new(self).spell_farsi
15
+ end
16
+
17
+ def spell_ordinal_farsi(*args)
18
+ FarsiFu::NumToWord.new(self).spell_ordinal_farsi(args[0])
19
+ end
20
+ end
21
+
22
+ module WordToNum
23
+ def farsi_to_number
24
+ FarsiFu::WordToNum.new(self).to_number
25
+ end
26
+ end
27
+
28
+ class String
29
+ include Convert
30
+ include WordToNum
31
+ end
32
+
33
+ class Numeric
34
+ include NumToWord
35
+ end
36
+
37
+ # Seems that Numeric works for both Float and Integers
38
+ # class Float
39
+ # include NumToWord
40
+ # end
@@ -1,3 +1,3 @@
1
1
  module FarsiFu
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module FarsiFu
4
+ class WordToNum
5
+
6
+ def initialize(number_in_words)
7
+ @number_in_words = number_in_words
8
+ end
9
+
10
+ # It converts number represented in words to numeral.
11
+ # Example:
12
+ # "صد و بیست و یک".to_number #=> 121
13
+ def to_number
14
+ return @number_in_words if !(@number_in_words.is_a? String)
15
+
16
+ numbers_array = make_integer_array(@number_in_words)
17
+
18
+ memory = 0
19
+ answer = 0
20
+ reset = true
21
+ numbers_array.each do |number|
22
+ if reset || !(divisible_by_thousand? number)
23
+ reset = false
24
+ memory += number
25
+ else
26
+ memory *= number
27
+ answer += memory
28
+ memory = 0
29
+ reset = true
30
+ end
31
+ end
32
+ answer += memory
33
+ end
34
+
35
+ private
36
+ # returns an array of corresponding numbers from string
37
+ # [1, 1000000, 200, 30, 5, 1000, 400, 30, 3]
38
+ def make_integer_array(number_in_words)
39
+ number_in_words = eliminate_and(number_in_words.strip.squeeze(" ")).split(" ")
40
+ numbers_array = []
41
+ number_in_words.each do |number|
42
+ if power_of_ten? number
43
+ numbers_array << 10 ** POWER_OF_TEN[number]
44
+ else
45
+ numbers_array << EXCEPTIONS[number]
46
+ end
47
+ end
48
+ numbers_array
49
+ end
50
+
51
+ # Removes "و" from the string
52
+ def eliminate_and(number_in_words)
53
+ number_in_words.gsub(/ و /, " ")
54
+ end
55
+
56
+ # Checkes if the number is power of divisible by thousand(bigger than 1000)
57
+ def divisible_by_thousand?(number)
58
+ number % 1000 == 0
59
+ end
60
+
61
+ # Checks if the number is power of ten
62
+ def power_of_ten? number
63
+ POWER_OF_TEN.keys.include? number
64
+ end
65
+ end
66
+ end