i18n-inflector 1.0.11 → 2.0.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/docs/TODO CHANGED
@@ -1,9 +1,9 @@
1
+ == Near future
1
2
 
3
+ * add some negative tests (e.g. empty kind, kinds as nils or empty striongs, tokens as empty strings...)
2
4
 
3
- * named patterns: @gender{m:xx|f:xxx|n:xzc} - such pattern may allow multiple tokens but it breaks the logic unless some marker will be given in configuration like !gender: that would inform engine that exact kind must be present in a pattern
4
-
5
- * use commas in patterns to separate tokens that should have to the same value
5
+ == Distant future
6
6
 
7
- * use negation symbols (!) in patterns to mark tokens that should generate value if are not matched (processing ends on first negative match)
7
+ * named patterns: @gender{m:xx|f:xxx|n:xzc} - such pattern may allow multiple tokens but it breaks the logic unless some marker will be given in configuration like !gender: that would inform engine that exact kind must be present in a pattern
8
8
 
9
- * use tilde symbols (~) to allow multiple negative matches. the values will be joined as they are interpolated (with other negative matches or a positive, it just means that the processing won't stop on some particular token)
9
+ * use tilde symbols (~) to allow multiple negative matches. the values will be joined as they are interpolated (with other negative matches or a positive; it just means that the processing won't stop on some particular token) – is this good idea anyway?
@@ -0,0 +1,268 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: (c) 2011 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {file:LGPL GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
+ #
7
+ # This file contains I18n::Backend::Inflector module,
8
+ # which extends I18n::Backend::Simple by adding the ability
9
+ # to interpolate patterns containing inflection tokens
10
+ # defined in translation data.
11
+
12
+ module I18n
13
+
14
+ # @abstract This namespace is shared with I18n subsystem.
15
+ module Backend
16
+
17
+ # This module contains methods that are adding
18
+ # tokenized inflection support to internal I18n classes.
19
+ # It is intened to be included in the Simple backend
20
+ # module so that it will patch translate method in order
21
+ # to interpolate additional inflection tokens present in translations.
22
+ # Usually you don't have to know what's here to use it.
23
+ module Inflector
24
+
25
+ # This accessor allows to reach API methods of the
26
+ # inflector object associated with this class.
27
+ def inflector
28
+ inflector_try_init
29
+ @inflector
30
+ end
31
+
32
+ # Cleans up internal hashes containg kinds, inflections and aliases.
33
+ #
34
+ # @api public
35
+ # @note It calls {I18n::Backend::Simple#reload! I18n::Backend::Simple#reload!}
36
+ # @return [Boolean] the result of calling ancestor's method
37
+ def reload!
38
+ @inflector = nil
39
+ super
40
+ end
41
+
42
+ # Translates given key taking care of inflections.
43
+ #
44
+ # @api public
45
+ # @see I18n::Inflector::Core#interpolate
46
+ # @see I18n::Inflector::InflectionOptions
47
+ # @param [Symbol] locale locale
48
+ # @param [Symbol,String] key translation key
49
+ # @param [Hash] options a set of options to pass to the translation routines.
50
+ # @note Inflector requires at least one of the +options+ to have a value that
51
+ # corresponds with token present in a pattern (or its alias). The name of that
52
+ # particular option should be the same as the name of a kind of tokens from a pattern.
53
+ # All +options+ along with a +string+ and +locale+ are passed to
54
+ # {I18n::Backend::Simple#translate I18n::Backend::Simple#translate}
55
+ # and the result is processed by {I18n::Inflector::Core#interpolate}
56
+ # @return [String] the translated string with interpolated patterns
57
+ def translate(locale, key, options = {})
58
+ translated_string = super
59
+
60
+ return translated_string if locale.to_s.empty?
61
+
62
+ unless @inflector.inflected_locale?(locale)
63
+ return translated_string.gsub(I18n::Inflector::PATTERN,'')
64
+ end
65
+
66
+ unless translated_string.include?(I18n::Inflector::FAST_MATCHER)
67
+ return translated_string
68
+ end
69
+
70
+ @inflector.interpolate(translated_string, locale, options.dup)
71
+ end
72
+
73
+ # Stores translations in memory.
74
+ #
75
+ # @api public
76
+ # @raise [I18n::InvalidLocale] if the given +locale+ is invalid
77
+ # @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
78
+ # @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
79
+ # @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
80
+ # @note If inflections are changed it will regenerate proper internal
81
+ # structures.
82
+ # @return [Hash] the stored translations
83
+ def store_translations(locale, data, options = {})
84
+ r = super
85
+ inflector_try_init
86
+ if data.respond_to?(:has_key?)
87
+ subdata = (data[:i18n] || data['i18n'])
88
+ unless subdata.nil?
89
+ subdata = (subdata[:inflections] || subdata['inflections'])
90
+ unless subdata.nil?
91
+ inflection_data = load_inflection_tokens(locale, r[:i18n][:inflections])
92
+ @inflector.add_database(inflection_data)
93
+ end
94
+ end
95
+ end
96
+ r
97
+ end
98
+
99
+ protected
100
+
101
+ # Initializes internal hashes used for keeping inflections configuration.
102
+ #
103
+ # @return [void]
104
+ def inflector_try_init
105
+ return nil if (defined?(@inflector) && !@inflector.nil?)
106
+ @inflector = I18n::Inflector::Core.new
107
+ nil
108
+ end
109
+
110
+ # Takes care of loading inflection tokens
111
+ # for all languages (locales) that have them
112
+ # defined.
113
+ #
114
+ # @note It calls {I18n::Backend::Simple#init_translations I18n::Backend::Simple#init_translations}
115
+ # @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
116
+ # @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
117
+ # @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
118
+ # @return [Boolean] +true+ if everything went fine
119
+ def init_translations
120
+ inflector_try_init
121
+ super
122
+ end
123
+
124
+ # Gives an access to the internal structure containing configuration data
125
+ # for a given locale.
126
+ #
127
+ # @note Under some very rare conditions this method may be called while
128
+ # translation data is loading. It must always return when translations
129
+ # are not initialized. Otherwise it will cause loops and someone in Poland
130
+ # will eat a kittien!
131
+ # @param [Symbol] locale the locale to use
132
+ # @return [Hash,nil] part of the translation data that
133
+ # reflects inflections for a given locale or +nil+
134
+ # if translations are not initialized
135
+ def inflection_subtree(locale)
136
+ return nil unless initialized?
137
+ lookup(locale, :"i18n.inflections", [], :fallback => true, :raise => :false)
138
+ end
139
+
140
+ # Resolves an alias for a token if the given +token+ is an alias.
141
+ #
142
+ # @note It does take care of aliasing loops (max traverses is set to 64).
143
+ # @raise [I18n::BadInflectionToken] if a name of the token that alias points to is corrupted
144
+ # @raise [I18n::BadInflectionAlias] if an alias points to token that does not exists
145
+ # @return [Symbol] the true token that alias points to if the given +token+
146
+ # is an alias or the given +token+ if it is a true token
147
+ # @overload shorten_inflection_alias(token, kind, locale)
148
+ # Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
149
+ # @note This version uses internal subtree and needs the translation data to be initialized.
150
+ # @param [Symbol] token the token name
151
+ # @param [Symbol] kind the kind of the given token
152
+ # @param [Symbol] locale the locale to use
153
+ # @return [Symbol] the true token that alias points to if the given +token+
154
+ # is an alias or the given +token+ if it is a true token
155
+ # @overload shorten_inflection_alias(token, kind, locale, subtree)
156
+ # Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
157
+ # @param [Symbol] token the token name
158
+ # @param [Symbol] kind the kind of the given token
159
+ # @param [Symbol] locale the locale to use
160
+ # @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
161
+ # @return [Symbol] the true token that alias points to if the given +token+
162
+ # is an alias or the given +token+ if it is a true token
163
+ def shorten_inflection_alias(token, kind, locale, subtree=nil, count=0)
164
+ count += 1
165
+ return nil if count > 64
166
+
167
+ inflections_tree = subtree || inflection_subtree(locale)
168
+ return nil if (inflections_tree.nil? || inflections_tree.empty?)
169
+
170
+ kind_subtree = inflections_tree[kind]
171
+ value = kind_subtree[token].to_s
172
+
173
+ if value[0..0] != I18n::Inflector::ALIAS_MARKER
174
+ if kind_subtree.has_key?(token)
175
+ return token
176
+ else
177
+ # that should never happend but who knows
178
+ raise I18n::BadInflectionToken.new(locale, token, kind)
179
+ end
180
+ else
181
+ orig_token = token
182
+ token = value[1..-1]
183
+ if token.to_s.empty?
184
+ raise I18n::BadInflectionToken.new(locale, token, kind)
185
+ end
186
+ token = token.to_sym
187
+ if kind_subtree[token].nil?
188
+ raise BadInflectionAlias.new(locale, orig_token, kind, token)
189
+ else
190
+ shorten_inflection_alias(token, kind, locale, inflections_tree, count)
191
+ end
192
+ end
193
+
194
+ end
195
+
196
+ # Uses the inflections subtree and creates internal mappings
197
+ # to resolve kinds assigned to inflection tokens and aliases, including defaults.
198
+ # @return [Hash,nil] the internal Hash containing inflections tokens or +nil+ if something went wrong
199
+ # @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
200
+ # @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
201
+ # @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
202
+ # @overload load_inflection_tokens(locale)
203
+ # @note That version calls the {inflection_subtree} method to obtain internal translations data.
204
+ # Loads inflection tokens for the given locale using internal hash of stored translations. Requires
205
+ # translations to be initialized.
206
+ # @param [Symbol] locale the locale to use and work for
207
+ # @return [Hash,nil] the internal Hash containing inflections or +nil+ if translations were not initialized
208
+ # @overload load_inflection_tokens(locale, subtree)
209
+ # Loads inflection tokens for the given locale using data given in an argument
210
+ # @param [Symbol] locale the locale to use and work for
211
+ # @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
212
+ # @return [Hash,nil] the internal Hash containing inflections or +nil+ if the given subtree was wrong or empty
213
+ def load_inflection_tokens(locale, subtree=nil)
214
+ inflections_tree = subtree || inflection_subtree(locale)
215
+ return nil if (inflections_tree.nil? || inflections_tree.empty?)
216
+
217
+ idb = I18n::Inflector::InflectionData.new(locale)
218
+
219
+ inflections_tree.each_pair do |kind, tokens|
220
+ tokens.each_pair do |token, description|
221
+
222
+ # test for duplicate
223
+ if idb.has_token?(token)
224
+ raise I18n::DuplicatedInflectionToken.new(idb.get_kind(token), kind, token)
225
+ end
226
+
227
+ # validate token's name
228
+ raise I18n::BadInflectionToken.new(locale, token, kind) if token.to_s.empty?
229
+
230
+ # validate token's description
231
+ if description.nil?
232
+ raise I18n::BadInflectionToken.new(locale, token, kind, description)
233
+ elsif description[0..0] == I18n::Inflector::ALIAS_MARKER
234
+ next
235
+ end
236
+
237
+ # handle default token for a kind
238
+ if token == :default
239
+ if idb.has_default_token?(kind) # should never happend unless someone is messing with @translations
240
+ raise I18n::DuplicatedInflectionToken.new(kind, nil, token)
241
+ end
242
+ idb.set_default_token(kind, description)
243
+ next
244
+ end
245
+
246
+ idb.add_token(token, kind, description)
247
+ end
248
+ end
249
+
250
+ # handle aliases
251
+ inflections_tree.each_pair do |kind, tokens|
252
+ tokens.each_pair do |token, description|
253
+ next if description[0..0] != I18n::Inflector::ALIAS_MARKER
254
+ real_token = shorten_inflection_alias(token, kind, locale, inflections_tree)
255
+ idb.add_alias(token, real_token) unless real_token.nil?
256
+ end
257
+ end
258
+
259
+ # process and validate defaults
260
+ valid = idb.validate_default_tokens
261
+ raise I18n::BadInflectionAlias.new(locale, :default, valid[0], valid[1]) unless valid.nil?
262
+
263
+ idb
264
+ end
265
+
266
+ end
267
+ end
268
+ end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
4
  # Copyright:: (c) 2011 by Paweł Wilk
5
- # License:: This program is licensed under the terms of {file:LGPL-LICENSE GNU Lesser General Public License} or {file:COPYING Ruby License}.
5
+ # License:: This program is licensed under the terms of {file:LGPL GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
6
  #
7
7
  # This file contains error reporting classes for I18n::Backend::Inflector module.
8
8
 
@@ -37,7 +37,7 @@ module I18n
37
37
  "pattern #{pattern.inspect} is invalid"
38
38
  end
39
39
  end
40
-
40
+
41
41
  # This is raised when an inflection token used in a pattern does not match
42
42
  # an assumed kind determined by reading previous tokens from that pattern.
43
43
  class MisplacedInflectionToken < ArgumentError
@@ -45,7 +45,7 @@ module I18n
45
45
  def initialize(pattern, token, kind)
46
46
  @pattern, @token, @kind = pattern, token, kind
47
47
  super "inflection token #{token.inspect} from pattern #{pattern.inspect} " +
48
- "is not of expected kind #{kind.inspect}"
48
+ "is not of the expected kind #{kind.inspect}"
49
49
  end
50
50
  end
51
51
 
@@ -69,22 +69,25 @@ module I18n
69
69
  def initialize(locale, token, kind, pointer)
70
70
  @locale, @token, @kind, @pointer = locale, token, kind, pointer
71
71
  what = token == :default ? "default token" : "alias"
72
- super "the #{what} #{token.inspect} of kind #{kind.inspect} " +
73
- "for language #{locale.inspect} points to an unknown token #{pointer.inspect}"
72
+ lang = locale.nil? ? "" : "for language #{locale.inspect} "
73
+ kinn = kind.nil? ? "" : "of kind #{kind.inspect} "
74
+ super "the #{what} #{token.inspect}" + kinn + lang +
75
+ "points to an unknown token #{pointer.inspect}"
74
76
  end
75
77
  end
76
-
78
+
77
79
  # This is raised when an inflection token or its description has a bad name. This
78
80
  # includes an empty name or a name containing prohibited characters.
79
81
  class BadInflectionToken < ArgumentError
80
82
  attr_reader :locale, :token, :kind, :description
81
- def initialize(locale, token, kind, description=nil)
83
+ def initialize(locale, token, kind=nil, description=nil)
82
84
  @locale, @token, @kind, @description = locale, token, kind, description
85
+ kinn = kind.nil? ? "" : "of kind #{kind.inspect} "
83
86
  if description.nil?
84
- super "Inflection token #{token.inspect} of kind #{kind.inspect} "+
87
+ super "Inflection token #{token.inspect} " + kinn +
85
88
  "for language #{locale.inspect} has a bad name"
86
89
  else
87
- super "Inflection token #{token.inspect} of kind #{kind.inspect} "+
90
+ super "Inflection token #{token.inspect} " + kinn +
88
91
  "for language #{locale.inspect} has a bad description #{description.inspect}"
89
92
  end
90
93
  end
@@ -0,0 +1,329 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: (c) 2011 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {file:LGPL GNU Lesser General Public License} or {file:COPYING Ruby License}.
6
+ #
7
+ # This file contains utility methods,
8
+ # that are used by I18n::Inflector and I18n::Backend::Inflector.
9
+
10
+ # @abstract This namespace is shared with I18n subsystem.
11
+ module I18n
12
+ module Inflector
13
+
14
+ # This class contains structures for keeping parsed translation data
15
+ # and basic operations for performing on them.
16
+ class InflectionData
17
+
18
+ # Initializes internal structures.
19
+ def initialize(locale=nil)
20
+ dummy_token = {:kind=>nil,:target=>nil,:description=>nil}
21
+ @kinds = Hash.new(false)
22
+ @tokens = Hash.new(dummy_token)
23
+ @defaults = {}
24
+ @locale = locale
25
+ end
26
+
27
+ # Locale that this database works on.
28
+ attr_reader :locale
29
+
30
+ # Adds an alias (overwriting existing alias).
31
+ #
32
+ # @param [Symbol] name the name of an alias
33
+ # @param [Symbol] target the target token for the given +alias+
34
+ # @return [Boolean] +true+ if everything went ok, +false+ otherwise
35
+ # (in case of bad or +nil+ names or non-existent targets)
36
+ def add_alias(name, target)
37
+ target = target.to_s
38
+ name = name.to_s
39
+ return false if (name.empty? || target.empty?)
40
+ name = name.to_sym
41
+ target = target.to_sym
42
+ kind = get_kind(target)
43
+ return false if kind.nil?
44
+ @tokens[name] = {}
45
+ @tokens[name][:kind] = kind
46
+ @tokens[name][:target] = target
47
+ @tokens[name][:description] = @tokens[target][:description]
48
+ true
49
+ end
50
+
51
+ # Adds a token (overwriting existing token).
52
+ #
53
+ # @param [Symbol] token the name of a token to add
54
+ # @param [Symbol] kind the kind of a token
55
+ # @param [String] description the description of a token
56
+ # @return [void]
57
+ def add_token(token, kind, description)
58
+ token = token.to_sym
59
+ @tokens[token] = {}
60
+ @tokens[token][:kind] = kind.to_sym
61
+ @tokens[token][:description] = description.to_s
62
+ @kinds[kind] = true
63
+ end
64
+
65
+ # Sets the default token for a kind.
66
+ #
67
+ # @param [Symbol] kind the kind to which the default
68
+ # token should be assigned
69
+ # @param [Symbol] target the token to set
70
+ # @return [void]
71
+ def set_default_token(kind, target)
72
+ @defaults[kind.to_sym] = target.to_sym
73
+ end
74
+
75
+ # Tests if the token is a true token.
76
+ #
77
+ # @overload has_true_token?(token)
78
+ # Tests if the token is a true token.
79
+ # @param [Symbol] token the identifier of a token
80
+ # @return [Boolean] +true+ if the given +token+ is
81
+ # a token and not an alias, +false+ otherwise
82
+ # @overload has_true_token?(token, kind)
83
+ # Tests if the token is a true token.
84
+ # @param [Symbol] token the identifier of a token
85
+ # @param [Symbol] kind the identifier of a kind
86
+ # @return [Boolean] +true+ if the given +token+ is
87
+ # a token and not an alias, and is a kind of
88
+ # the given kind, +false+ otherwise
89
+ def has_true_token?(token, kind=nil)
90
+ o = @tokens[token]
91
+ k = o[:kind]
92
+ return false if (k.nil? || !o[:target].nil?)
93
+ kind.nil? ? true : k == kind
94
+ end
95
+
96
+ # Tests if a token (or alias) is present.
97
+ #
98
+ # @overload has_token(token)
99
+ # Tests if a token (or alias) is present.
100
+ # @param [Symbol] token the identifier of a token
101
+ # @return [Boolean] +true+ if the given +token+
102
+ # (which may be an alias) exists
103
+ # @overload has_token(token, kind)
104
+ # Tests if a token (or alias) is present.
105
+ # @param [Symbol] token the identifier of a token
106
+ # @param [Symbol] kind the identifier of a kind
107
+ # @return [Boolean] +true+ if the given +token+
108
+ # (which may be an alias) exists and if kind of
109
+ # the given kind
110
+ def has_token?(token, kind=nil)
111
+ k = @tokens[token][:kind]
112
+ kind.nil? ? !k.nil? : k == kind
113
+ end
114
+
115
+ # Tests if a kind exists.
116
+ #
117
+ # @param [Symbol] kind the identifier of a kind
118
+ # @return [Boolean] +true+ if the given +kind+ exists
119
+ def has_kind?(kind)
120
+ @kinds.has_key?(kind)
121
+ end
122
+
123
+ # Tests if a kind has a default token assigned.
124
+ #
125
+ # @param [Symbol] kind the identifier of a kind
126
+ # @return [Boolean] +true+ if there is a default
127
+ # token of the given kind
128
+ def has_default_token?(kind)
129
+ @defaults.has_key?(kind)
130
+ end
131
+
132
+ # Tests if a given alias is really an alias.
133
+ #
134
+ # @overload has_alias?(alias_name)
135
+ # Tests if a given alias is really an alias.
136
+ # @param [Symbol] alias_name the identifier of an alias
137
+ # @return [Boolean] +true+ if the given alias is really an alias,
138
+ # +false+ otherwise
139
+ # @overload has_alias?(alias_name, kind)
140
+ # Tests if a given alias is really an alias.
141
+ # @param [Symbol] alias_name the identifier of an alias
142
+ # @param [Symbol] kind the identifier of a kind
143
+ # @return [Boolean] +true+ if the given alias is really an alias
144
+ # being a kind of the given kind, +false+ otherwise
145
+ def has_alias?(alias_name, kind=nil)
146
+ o = @tokens[alias_name]
147
+ return false if o[:target].nil?
148
+ kind.nil? ? true : o[:kind] == kind
149
+ end
150
+
151
+ # Reads the all the true tokens (not aliases).
152
+ #
153
+ # @return [Hash] the true tokens in a
154
+ # form of Hash (<tt>token => description</tt>)
155
+ # @overload get_true_tokens(kind)
156
+ # Reads the all the true tokens (not aliases).
157
+ # @return [Hash] the true tokens in a
158
+ # form of Hash (<tt>token => description</tt>)
159
+ # @overload get_true_tokens(kind)
160
+ # Reads the all the true tokens (not aliases).
161
+ # @param [Symbol] kind the identifier of a kind
162
+ # @return [Hash] the true tokens of the given kind in a
163
+ # form of Hash (<tt>token => description</tt>)
164
+ def get_true_tokens(kind=nil)
165
+ tokens = @tokens.reject{|k,v| !v[:target].nil?}
166
+ tokens = tokens.reject{|k,v| v[:kind]!=kind} unless kind.nil?
167
+ tokens.merge(tokens){|k,v| v[:description]}
168
+ end
169
+
170
+ # Reads the all the aliases.
171
+ #
172
+ # @return [Hash] the aliases in a
173
+ # form of Hash (<tt>alias => target</tt>)
174
+ # @overload get_aliases(kind)
175
+ # Reads the all the aliases.
176
+ # @return [Hash] the aliases in a
177
+ # form of Hash (<tt>alias => target</tt>)
178
+ # @overload get_aliases(kind)
179
+ # Reads the all the aliases.
180
+ # @param [Symbol] kind the identifier of a kind
181
+ # @return [Hash] the aliases of the given kind in a
182
+ # form of Hash (<tt>alias => target</tt>)
183
+ def get_aliases(kind=nil)
184
+ aliases = @tokens.reject{|k,v| v[:target].nil?}
185
+ aliases = aliases.reject{|k,v| v[:kind]!=kind} unless kind.nil?
186
+ aliases.merge(aliases){|k,v| v[:target]}
187
+ end
188
+
189
+ # Reads the all the tokens in a way that it is possible to
190
+ # distinguish true tokens from aliases.
191
+ #
192
+ # @note True tokens have descriptions (String) and aliases
193
+ # have targets (Symbol) assigned.
194
+ # @return [Hash] the tokens in a
195
+ # form of Hash (<tt>token => description|target</tt>)
196
+ # @overload get_raw_tokens
197
+ # Reads the all the tokens.
198
+ # @return [Hash] the tokens in a
199
+ # form of Hash (<tt>token => description|target</tt>)
200
+ # @overload get_raw_tokens(kind)
201
+ # Reads the all the tokens.
202
+ # @param [Symbol] kind the identifier of a kind
203
+ # @return [Hash] the tokens of the given kind in a
204
+ # form of Hash (<tt>token => description|target</tt>)
205
+ def get_raw_tokens(kind=nil)
206
+ get_true_tokens(kind).merge(get_aliases(kind))
207
+ end
208
+
209
+ # Reads the all the tokens (including aliases).
210
+ #
211
+ # @note Use {get_raw_tokens} if you want to distinguish
212
+ # true tokens from aliases.
213
+ # @return [Hash] the tokens in a
214
+ # form of Hash (<tt>token => description</tt>)
215
+ # @overload get_raw_tokens(kind)
216
+ # Reads the all the tokens (including aliases).
217
+ # @return [Hash] the tokens in a
218
+ # form of Hash (<tt>token => description</tt>)
219
+ # @overload get_raw_tokens(kind)
220
+ # Reads the all the tokens (including aliases).
221
+ # @param [Symbol] kind the identifier of a kind
222
+ # @return [Hash] the tokens of the given kind in a
223
+ # form of Hash (<tt>token => description</tt>)
224
+ def get_tokens(kind=nil)
225
+ tokens = @tokens
226
+ tokens = tokens.reject{|k,v| v[:kind]!=kind} unless kind.nil?
227
+ tokens.merge(tokens){|k,v| v[:description]}
228
+ end
229
+
230
+ # Gets a target token for the alias.
231
+ #
232
+ # @param [Symbol] alias_name the identifier of an alias
233
+ # @return [Symbol,nil] the token that the given alias points to
234
+ # or +nil+ if it isn't really an alias
235
+ def get_target_for_alias(alias_name)
236
+ @tokens[alias_name][:target]
237
+ end
238
+
239
+ # Gets a kind of the given token or alias.
240
+ #
241
+ # @param [Symbol] token identifier of a token
242
+ # @return [Symbol,nil] the kind of the given +token+
243
+ # or +nil+ if the token is unknown
244
+ def get_kind(token)
245
+ @tokens[token][:kind]
246
+ end
247
+
248
+ # Gets a true token for the given identifier.
249
+ #
250
+ # @note If the given +token+ is really an alias it will
251
+ # be resolved and the real token pointed by that alias
252
+ # will be returned.
253
+ # @overload get_true_token(token)
254
+ # Gets a true token for the given token identifier.
255
+ # @param [Symbol] token the identifier of a token
256
+ # @return [Symbol,nil] the true token for the given +token+
257
+ # or +nil+ if the token is unknown
258
+ # @overload get_true_token(token, kind)
259
+ # Gets a true token for the given token identifier and the
260
+ # given kind.
261
+ # @param [Symbol] token the identifier of a token
262
+ # @param [Symbol] kind the identifier of a kind
263
+ # @return [Symbol,nil] the true token for the given +token+
264
+ # or +nil+ if the token is unknown or is not kind of the
265
+ # given kind
266
+ def get_true_token(token, kind=nil)
267
+ o = @tokens[token]
268
+ k = o[:kind]
269
+ return nil if k.nil?
270
+ r = (o[:target] || token)
271
+ return r if kind.nil?
272
+ k == kind ? r : nil
273
+ end
274
+
275
+ # Gets all known kinds.
276
+ #
277
+ # @return [Array<Symbol>] an array containing all the known kinds
278
+ def get_kinds
279
+ @kinds.keys
280
+ end
281
+
282
+ # Reads the default token of a kind.
283
+ #
284
+ # @note It will always return true token (not an alias).
285
+ # @param [Symbol] kind the identifier of a kind
286
+ # @return [Symbol,nil] the default token of the given +kind+
287
+ # or +nil+ if there is no default token set
288
+ def get_default_token(kind)
289
+ @defaults[kind]
290
+ end
291
+
292
+ # Gets a description of a token or alias.
293
+ #
294
+ # @note If the token is really an alias it will resolve the alias first.
295
+ # @param [Symbol] token the identifier of a token
296
+ # @return [String,nil] the string containing description of the given
297
+ # token (which may be an alias) or +nil+ if the token is unknown
298
+ def get_description(token)
299
+ @tokens[token][:description]
300
+ end
301
+
302
+ # This method validates default tokens assigned
303
+ # for kinds and replaces targets with true tokens
304
+ # if they are aliases.
305
+ #
306
+ # @return [nil,Array<Symbol>] +nil+ if everything went fine,
307
+ # two dimensional array containing kind and target
308
+ # in case of error while geting a token
309
+ def validate_default_tokens
310
+ @defaults.each_pair do |kind, pointer|
311
+ ttok = get_true_token(pointer)
312
+ return [kind, pointer] if ttok.nil?
313
+ set_default_token(kind, ttok)
314
+ end
315
+ return nil
316
+ end
317
+
318
+ # Test if the inflection data have no elements.
319
+ #
320
+ # @return [Boolean] +true+ if the inflection data
321
+ # have no elements
322
+ def empty?
323
+ @tokens.empty?
324
+ end
325
+
326
+ end # InflectionData
327
+
328
+ end
329
+ end