i18n-inflector 1.0.11 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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