farsifu 0.3.0 → 0.4.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/.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