petrovich 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
  [![Build Status](https://secure.travis-ci.org/rocsci/petrovich.png)](http://travis-ci.org/rocsci/petrovich)
7
7
 
8
+ #### Посмотреть в действии: http://petrovich.rocketscience.it
9
+
8
10
  ## Установка
9
11
 
10
12
  Добавьте в Gemfile:
@@ -47,7 +49,7 @@ p.middlename('Сергеевич', :dative) # => Сергеевичу
47
49
  такие как Нельсон.
48
50
 
49
51
  Важно понимать, что явное указание пола повышает точность обработки слов.
50
- Если пол не известен, однако известно отчество, то гем постарается
52
+ Если пол неизвестен, однако известно отчество, то гем постарается
51
53
  определить по пол отчеству на основе простой эвристики.
52
54
 
53
55
  ### Продвинутое использование
@@ -166,22 +168,22 @@ person.my_lastname_dative # => Сафронову
166
168
 
167
169
  ```
168
170
  Pr(nominative|male) = 100.0000%
169
- Pr(genitive|male) = 99.6763%
170
- Pr(dative|male) = 99.7012%
171
- Pr(accusative|male) = 99.7261%
172
- Pr(instrumental|male) = 97.9485%
173
- Pr(prepositional|male) = 99.6888%
171
+ Pr(genitive|male) = 99.7137%
172
+ Pr(dative|male) = 99.7386%
173
+ Pr(accusative|male) = 99.7635%
174
+ Pr(instrumental|male) = 97.9858%
175
+ Pr(prepositional|male) = 99.7261%
174
176
  ```
175
177
  ```
176
178
  Pr(nominative|female) = 100.0000%
177
- Pr(genitive|female) = 99.8652%
178
- Pr(dative|female) = 99.8952%
179
- Pr(accusative|female) = 99.9251%
180
- Pr(instrumental|female) = 99.4189%
181
- Pr(prepositional|female) = 99.8952%
179
+ Pr(genitive|female) = 99.9102%
180
+ Pr(dative|female) = 99.9401%
181
+ Pr(accusative|female) = 99.9701%
182
+ Pr(instrumental|female) = 99.4636%
183
+ Pr(prepositional|female) = 99.9401%
182
184
  ```
183
185
 
184
- В настоящий момент наблюдается точность в 99.6275% на основе обработки
186
+ В настоящий момент наблюдается точность в 99.6614% на основе обработки
185
187
  88314 примеров.
186
188
 
187
189
  [АОТ]: http://seman.svn.sourceforge.net/viewvc/seman/trunk/Docs/Morph_UNIX.txt?revision=HEAD&view=markup
@@ -203,7 +205,6 @@ Pr(prepositional|female) = 99.8952%
203
205
  * добавить отладочный режим, чтобы видеть, какое именно правило было
204
206
  использовано при словообразовании;
205
207
  * интерфейс командной строки, чтобы работать с гемом из командной строки;
206
- * Web-интерфейс для обработки ФИО;
207
208
  * проверка совместимости с различными ORM и сторонними библиотеками.
208
209
 
209
210
  Если вы хотите помочь этому проекту, вы можете реализовать любую
@@ -3,7 +3,7 @@
3
3
  class Petrovich
4
4
  # Этот модуль разработан для возможности его подмешивания в класс Ruby.
5
5
  # Его можно подмешать в любой класс, например, в модель ActiveRecord.
6
- #
6
+ #
7
7
  # При помощи вызова метода +petrovich+ вы указываете, какие аттрибуты или методы класса
8
8
  # будут возвращать фамилию, имя и отчество.
9
9
  #
@@ -24,23 +24,23 @@ class Petrovich
24
24
  # на основе файла правил.
25
25
  #
26
26
  # Пример использования
27
- #
27
+ #
28
28
  # class User
29
29
  # include Petrovich::Extension
30
- #
30
+ #
31
31
  # petrovich :firstname => :my_firstname,
32
32
  # :middlename => :my_middlename,
33
33
  # :lastname => :my_lastname,
34
34
  # :gender => :my_gender
35
- #
35
+ #
36
36
  # def my_firstname
37
37
  # 'Пётр'
38
38
  # end
39
- #
39
+ #
40
40
  # def my_middlename
41
41
  # 'Александрович'
42
42
  # end
43
- #
43
+ #
44
44
  # def my_lastname
45
45
  # 'Ларин'
46
46
  # end
@@ -74,7 +74,7 @@ class Petrovich
74
74
  end
75
75
 
76
76
  self.petrovich_configuration = {
77
- :fullname => nil,
77
+ :lastname => nil,
78
78
  :firstname => nil,
79
79
  :middlename => nil,
80
80
  :gender => nil
@@ -84,11 +84,20 @@ class Petrovich
84
84
 
85
85
  def petrovich_create_getter(method_name, attribute, gcase)
86
86
  options = self.class.petrovich_configuration
87
- reflection = options.key(attribute.to_sym) or raise "No reflection for attribute '#{attribute}'!"
87
+ reflection = options.key(attribute.to_sym) or
88
+ raise "No reflection for attribute '#{attribute}'!"
88
89
 
89
90
  self.class.send(:define_method, method_name) do
90
- rn = Petrovich.new(options[:gender])
91
- rn.send(reflection, send(attribute), gcase)
91
+ # detect by gender attr if defined
92
+ gender = options[:gender] && send(options[:gender])
93
+ # detect by middlename attr if defined
94
+ gender ||= begin
95
+ middlename = options[:middlename] && send(options[:middlename])
96
+ middlename && Petrovich.detect_gender(middlename)
97
+ end
98
+
99
+ rn = Petrovich.new gender
100
+ rn.send reflection, send(attribute), gcase
92
101
  end
93
102
  end
94
103
 
@@ -26,13 +26,18 @@ class Petrovich
26
26
  #
27
27
  [:lastname, :firstname, :middlename].each do |method_name|
28
28
  define_method(method_name) do |name, gcase|
29
- find_and_apply(name, gcase, Petrovich::RULES[method_name.to_s])
29
+ inflect(name, gcase, Petrovich::RULES[method_name.to_s])
30
30
  end
31
31
  end
32
32
 
33
33
  protected
34
-
35
- def match?(name, rule, match_whole_word)
34
+ # Известно несколько типов признаков, которые влияют на процесс поиска.
35
+ #
36
+ # Признак +first_word+ указывает, что данное слово является первым словом
37
+ # в составном слове. Например, в двойной русской фамилии Иванов-Сидоров.
38
+ #
39
+ def match?(name, rule, match_whole_word, tags)
40
+ return false unless tags_allow? tags, rule['tags']
36
41
  return false if rule['gender'] == 'male' && female? || rule['gender'] == 'female' && !female?
37
42
 
38
43
  name = UnicodeUtils.downcase(name)
@@ -52,6 +57,19 @@ class Petrovich
52
57
  @gender == 'female'
53
58
  end
54
59
 
60
+ def inflect(name, gcase, rules)
61
+ i = 0
62
+
63
+ parts = name.split('-')
64
+
65
+ parts.map! do |part|
66
+ first_word = (i += 1) == 1 && parts.size > 1
67
+ find_and_apply(part, gcase, rules, first_word: first_word)
68
+ end
69
+
70
+ parts.join('-')
71
+ end
72
+
55
73
  # Применить правило
56
74
  def apply(name, gcase, rule)
57
75
  modificator_for(gcase, rule).each_char do |char|
@@ -68,8 +86,8 @@ class Petrovich
68
86
  end
69
87
 
70
88
  # Найти правило и применить к имени с учетом склонения
71
- def find_and_apply(name, gcase, rules)
72
- rule = find_for(name, rules)
89
+ def find_and_apply(name, gcase, rules, features = {})
90
+ rule = find_for(name, rules, features)
73
91
  apply(name, gcase, rule)
74
92
  rescue UnknownRuleException
75
93
  # Если не найдено правило для имени, возвращаем неизмененное имя.
@@ -77,21 +95,23 @@ class Petrovich
77
95
  end
78
96
 
79
97
  # Найти подходящее правило в исключениях или суффиксах
80
- def find_for(name, rules)
98
+ def find_for(name, rules, features = {})
99
+ tags = extract_tags(features)
100
+
81
101
  # Сначала пытаемся найти исключения
82
102
  if rules.has_key?('exceptions')
83
- p = find(name, rules['exceptions'], true)
103
+ p = find(name, rules['exceptions'], true, tags)
84
104
  return p if p
85
105
  end
86
106
 
87
107
  # Не получилось, ищем в суффиксах. Если не получилось найти и в них,
88
108
  # возвращаем неизмененное имя.
89
- find(name, rules['suffixes'], false) or raise UnknownRuleException, "Cannot find rule for #{name}"
109
+ find(name, rules['suffixes'], false, tags) or raise UnknownRuleException, "Cannot find rule for #{name}"
90
110
  end
91
111
 
92
112
  # Найти подходящее правило в конкретном списке правил
93
- def find(name, rules, match_whole_word)
94
- rules.find { |rule| match?(name, rule, match_whole_word) }
113
+ def find(name, rules, match_whole_word, tags)
114
+ rules.find { |rule| match?(name, rule, match_whole_word, tags) }
95
115
  end
96
116
 
97
117
  # Получить модификатор из указанного правиля для указанного склонения
@@ -114,5 +134,17 @@ class Petrovich
114
134
  end
115
135
  end
116
136
 
137
+ # Преобразование +{a: true, b: false, c: true}+ в +%w(a c)+.
138
+ def extract_tags(features = {})
139
+ features.keys.select { |k| features[k] == true }.map(&:to_s)
140
+ end
141
+
142
+ # Правило не подходит только в том случае, если оно содержит больше
143
+ # тегов, чем требуется для данного слова.
144
+ #
145
+ def tags_allow?(tags, rule_tags)
146
+ rule_tags ||= []
147
+ (rule_tags - tags).empty?
148
+ end
117
149
  end
118
150
  end
@@ -29,8 +29,29 @@
29
29
  #
30
30
  lastname:
31
31
  exceptions:
32
+ # Неизменяемые первые части двойных русских фамилий.
33
+ #
34
+ - gender: androgynous
35
+ test:
36
+ - бонч
37
+ - абдул
38
+ - белиц
39
+ - гасан
40
+ - дюссар
41
+ - дюмон
42
+ - книппер
43
+ - корвин
44
+ - ван
45
+ - шолом
46
+ - тер
47
+ - призван
48
+ - мелик
49
+ - вар
50
+ mods: [., ., ., ., .]
51
+ tags: [first_word]
52
+
32
53
  - gender: androgynous
33
- test: [дюма, тома, дега, люка, ферма, гамарра, петипа, шандра]
54
+ test: [дюма, тома, дега, люка, ферма, гамарра, петипа, шандра, скаля]
34
55
  mods: [., ., ., ., .]
35
56
 
36
57
  - gender: androgynous
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: petrovich
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-07-08 00:00:00.000000000 Z
13
+ date: 2013-09-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: unicode_utils