i18n-inflector-3 3.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.
- checksums.yaml +7 -0
- data/ChangeLog +1674 -0
- data/LGPL-LICENSE +169 -0
- data/README.md +259 -0
- data/docs/COPYING +57 -0
- data/docs/EXAMPLES +357 -0
- data/docs/HISTORY +280 -0
- data/docs/LEGAL +10 -0
- data/docs/LGPL +166 -0
- data/docs/TODO +8 -0
- data/docs/USAGE +967 -0
- data/docs/rdoc.css +20 -0
- data/lib/i18n-inflector/api.rb +753 -0
- data/lib/i18n-inflector/api_strict.rb +671 -0
- data/lib/i18n-inflector/backend.rb +352 -0
- data/lib/i18n-inflector/config.rb +289 -0
- data/lib/i18n-inflector/errors.rb +226 -0
- data/lib/i18n-inflector/hset.rb +24 -0
- data/lib/i18n-inflector/inflection_data.rb +357 -0
- data/lib/i18n-inflector/inflection_data_strict.rb +300 -0
- data/lib/i18n-inflector/inflector.rb +38 -0
- data/lib/i18n-inflector/interpolate.rb +546 -0
- data/lib/i18n-inflector/lazy_enum.rb +267 -0
- data/lib/i18n-inflector/long_comments.rb +57 -0
- data/lib/i18n-inflector/options.rb +329 -0
- data/lib/i18n-inflector/version.rb +27 -0
- data/lib/i18n-inflector.rb +19 -0
- metadata +87 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
|
5
|
+
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
|
|
6
|
+
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
|
|
7
|
+
#
|
|
8
|
+
# This file contains I18n::Backend::Inflector module,
|
|
9
|
+
# which extends I18n::Backend::Simple by adding the ability
|
|
10
|
+
# to interpolate patterns containing inflection tokens
|
|
11
|
+
# defined in translation data.
|
|
12
|
+
|
|
13
|
+
module I18n
|
|
14
|
+
# @abstract This namespace is shared with I18n subsystem.
|
|
15
|
+
module Backend
|
|
16
|
+
# This module contains methods that add
|
|
17
|
+
# tokenized inflection support to internal I18n classes.
|
|
18
|
+
# It is intened to be included in the Simple backend
|
|
19
|
+
# module so that it will patch translate method in order
|
|
20
|
+
# to interpolate additional inflection tokens present in translations.
|
|
21
|
+
# Usually you don't have to know what's here to use it.
|
|
22
|
+
module Inflector
|
|
23
|
+
# Shortcut to configuration module.
|
|
24
|
+
InflectorCfg = I18n::Inflector::Config
|
|
25
|
+
|
|
26
|
+
# This accessor allows to reach API methods of the
|
|
27
|
+
# inflector object associated with this class.
|
|
28
|
+
def inflector
|
|
29
|
+
inflector_try_init
|
|
30
|
+
@inflector
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Cleans up internal hashes containg kinds, inflections and aliases.
|
|
34
|
+
#
|
|
35
|
+
# @api public
|
|
36
|
+
# @note It calls {I18n::Backend::Simple#reload! I18n::Backend::Simple#reload!}
|
|
37
|
+
# @return [Boolean] the result of calling ancestor's method
|
|
38
|
+
def reload!
|
|
39
|
+
@inflector = nil
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Translates given key taking care of inflections.
|
|
44
|
+
#
|
|
45
|
+
# @api public
|
|
46
|
+
# @see I18n::Inflector::API#interpolate
|
|
47
|
+
# @see I18n::Inflector::InflectionOptions
|
|
48
|
+
# @param [Symbol] locale locale
|
|
49
|
+
# @param [Symbol,String] key translation key
|
|
50
|
+
# @param [Hash] options a set of options to pass to the translation routines.
|
|
51
|
+
# @note The given +options+ along with a translated string and the given
|
|
52
|
+
# +locale+ are passed to
|
|
53
|
+
# {I18n::Backend::Simple#translate I18n::Backend::Simple#translate}
|
|
54
|
+
# and then the result is processed by {I18n::Inflector::API#interpolate}
|
|
55
|
+
# @return [String] the translated string with interpolated patterns
|
|
56
|
+
def translate(locale, key, options = {})
|
|
57
|
+
inflector_try_init
|
|
58
|
+
|
|
59
|
+
# take care about cache-awareness
|
|
60
|
+
cached = if options.key?(:inflector_cache_aware)
|
|
61
|
+
options[:inflector_cache_aware]
|
|
62
|
+
else
|
|
63
|
+
@inflector.options.cache_aware
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if cached
|
|
67
|
+
interpolate_options = options
|
|
68
|
+
@inflector.options.prepare_options!(options)
|
|
69
|
+
else
|
|
70
|
+
interpolate_options = options.dup
|
|
71
|
+
@inflector.options.clean_for_translate!(options)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# translate string using original translate
|
|
75
|
+
translated_string = super
|
|
76
|
+
|
|
77
|
+
# generate a pattern from key-based inflection object
|
|
78
|
+
if translated_string.is_a?(Hash) && key.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND
|
|
79
|
+
translated_string = @inflector.key_to_pattern(translated_string)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# interpolate string
|
|
83
|
+
begin
|
|
84
|
+
@inflector.options.prepare_options!(interpolate_options) unless cached
|
|
85
|
+
@inflector.interpolate(translated_string, locale, interpolate_options)
|
|
86
|
+
|
|
87
|
+
# complete the exception by adding translation key
|
|
88
|
+
rescue I18n::InflectionException => e
|
|
89
|
+
e.key = key
|
|
90
|
+
raise
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Stores translations in memory.
|
|
95
|
+
#
|
|
96
|
+
# @api public
|
|
97
|
+
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
|
|
98
|
+
# @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
|
|
99
|
+
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
|
|
100
|
+
# @raise [I18n::BadInflectionKind] if a loaded kind identifier is invalid
|
|
101
|
+
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
|
|
102
|
+
# @note If inflections are changed it will regenerate proper internal
|
|
103
|
+
# structures.
|
|
104
|
+
# @return [Hash] the stored translations
|
|
105
|
+
def store_translations(locale, data, options = {})
|
|
106
|
+
r = super
|
|
107
|
+
inflector_try_init
|
|
108
|
+
if data.respond_to?(:has_key?)
|
|
109
|
+
subdata = data[:i18n] || data['i18n']
|
|
110
|
+
unless subdata.nil?
|
|
111
|
+
subdata = subdata[:inflections] || subdata['inflections']
|
|
112
|
+
unless subdata.nil?
|
|
113
|
+
db, db_strict = load_inflection_tokens(locale, r[:i18n][:inflections])
|
|
114
|
+
@inflector.add_database(db, db_strict)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
r
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
protected
|
|
122
|
+
|
|
123
|
+
# Initializes internal hashes used for keeping inflections configuration.
|
|
124
|
+
#
|
|
125
|
+
# @return [void]
|
|
126
|
+
def inflector_try_init
|
|
127
|
+
return if defined?(@inflector) && !@inflector.nil?
|
|
128
|
+
|
|
129
|
+
@inflector = I18n::Inflector::API.new
|
|
130
|
+
init_translations unless initialized?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Takes care of loading inflection tokens
|
|
134
|
+
# for all languages (locales) that have them
|
|
135
|
+
# defined.
|
|
136
|
+
#
|
|
137
|
+
# @note It calls {I18n::Backend::Simple#init_translations I18n::Backend::Simple#init_translations}
|
|
138
|
+
# @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
|
|
139
|
+
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
|
|
140
|
+
# @raise [I18n::BadInflectionKind] if a loaded kind identifier is invalid
|
|
141
|
+
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
|
|
142
|
+
# @return [Boolean] +true+ if everything went fine
|
|
143
|
+
def init_translations
|
|
144
|
+
@inflector = I18n::Inflector::API.new unless defined?(@inflector) && !@inflector.nil?
|
|
145
|
+
super
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Gives an access to the internal structure containing configuration data
|
|
149
|
+
# for the given locale.
|
|
150
|
+
#
|
|
151
|
+
# @note Under some very rare conditions this method may be called while
|
|
152
|
+
# translation data is loading. It must always return when translations
|
|
153
|
+
# are not initialized. Otherwise it will cause loops and someone in Poland
|
|
154
|
+
# will eat a kittien!
|
|
155
|
+
# @param [Symbol] locale the locale to use
|
|
156
|
+
# @return [Hash,nil] part of the translation data that
|
|
157
|
+
# reflects inflections for the given locale or +nil+
|
|
158
|
+
# if translations are not initialized
|
|
159
|
+
def inflection_subtree(locale)
|
|
160
|
+
return nil unless initialized?
|
|
161
|
+
|
|
162
|
+
lookup(locale, :'i18n.inflections', [], fallback: true, raise: false)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Resolves an alias for a token if the given +token+ is an alias.
|
|
166
|
+
#
|
|
167
|
+
# @note It does take care of aliasing loops (max traverses is set to 64).
|
|
168
|
+
# @raise [I18n::BadInflectionToken] if a name of the token that alias points to is corrupted
|
|
169
|
+
# @raise [I18n::BadInflectionAlias] if an alias points to token that does not exists
|
|
170
|
+
# @return [Symbol] the true token that alias points to if the given +token+
|
|
171
|
+
# is an alias or the given +token+ if it is a true token
|
|
172
|
+
# @overload shorten_inflection_alias(token, kind, locale)
|
|
173
|
+
# Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
|
|
174
|
+
# @note This version uses internal subtree and needs the translation data to be initialized.
|
|
175
|
+
# @param [Symbol] token the token name
|
|
176
|
+
# @param [Symbol] kind the kind of the given token
|
|
177
|
+
# @param [Symbol] locale the locale to use
|
|
178
|
+
# @return [Symbol] the true token that alias points to if the given +token+
|
|
179
|
+
# is an alias or the given +token+ if it is a true token
|
|
180
|
+
# @overload shorten_inflection_alias(token, kind, locale, subtree)
|
|
181
|
+
# Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
|
|
182
|
+
# @param [Symbol] token the token name
|
|
183
|
+
# @param [Symbol] kind the kind of the given token
|
|
184
|
+
# @param [Symbol] locale the locale to use
|
|
185
|
+
# @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
|
|
186
|
+
# @return [Symbol] the true token that alias points to if the given +token+
|
|
187
|
+
# is an alias or the given +token+ if it is a true token
|
|
188
|
+
def shorten_inflection_alias(token, kind, locale, subtree = nil, count = 0)
|
|
189
|
+
count += 1
|
|
190
|
+
return nil if count > 64
|
|
191
|
+
|
|
192
|
+
inflections_tree = subtree || inflection_subtree(locale)
|
|
193
|
+
return nil if inflections_tree.nil? || inflections_tree.empty?
|
|
194
|
+
|
|
195
|
+
kind_subtree = inflections_tree[kind]
|
|
196
|
+
value = kind_subtree[token].to_s
|
|
197
|
+
|
|
198
|
+
if value[0..0] == InflectorCfg::Markers::ALIAS
|
|
199
|
+
orig_token = token
|
|
200
|
+
token = value[1..]
|
|
201
|
+
|
|
202
|
+
raise I18n::BadInflectionToken.new(locale, token, kind) if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
|
|
203
|
+
|
|
204
|
+
token = token.to_sym
|
|
205
|
+
raise BadInflectionAlias.new(locale, orig_token, kind, token) if kind_subtree[token].nil?
|
|
206
|
+
|
|
207
|
+
shorten_inflection_alias(token, kind, locale, inflections_tree, count)
|
|
208
|
+
|
|
209
|
+
else
|
|
210
|
+
return token if kind_subtree.key?(token)
|
|
211
|
+
|
|
212
|
+
raise I18n::BadInflectionToken.new(locale, token, kind)
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Uses the inflections subtree and creates internal mappings
|
|
218
|
+
# to resolve kinds assigned to inflection tokens and aliases, including defaults.
|
|
219
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
|
220
|
+
# or +nil+ if something went wrong
|
|
221
|
+
# @raise [I18n::BadInflectionToken] if a token identifier is invalid
|
|
222
|
+
# @raise [I18n::BadInflectionKind] if a kind identifier is invalid
|
|
223
|
+
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
|
|
224
|
+
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
|
|
225
|
+
# @overload load_inflection_tokens(locale)
|
|
226
|
+
# @note That version calls the {inflection_subtree} method to obtain internal translations data.
|
|
227
|
+
# Loads inflection tokens for the given locale using internal hash of stored translations. Requires
|
|
228
|
+
# translations to be initialized.
|
|
229
|
+
# @param [Symbol] locale the locale to use and work for
|
|
230
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
|
231
|
+
# or +nil+ if something went wrong
|
|
232
|
+
# @overload load_inflection_tokens(locale, subtree)
|
|
233
|
+
# Loads inflection tokens for the given locale using datthe given in an argument
|
|
234
|
+
# @param [Symbol] locale the locale to use and work for
|
|
235
|
+
# @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
|
|
236
|
+
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
|
|
237
|
+
# or +nil+ if something went wrong
|
|
238
|
+
def load_inflection_tokens(locale, subtree = nil)
|
|
239
|
+
inflections_tree = subtree || inflection_subtree(locale)
|
|
240
|
+
return nil if inflections_tree.nil? || inflections_tree.empty?
|
|
241
|
+
|
|
242
|
+
inflections_tree = deep_symbolize(inflections_tree)
|
|
243
|
+
|
|
244
|
+
idb = I18n::Inflector::InflectionData.new(locale)
|
|
245
|
+
idb_strict = I18n::Inflector::InflectionData_Strict.new(locale)
|
|
246
|
+
|
|
247
|
+
return nil if idb.nil? || idb_strict.nil?
|
|
248
|
+
|
|
249
|
+
inflections = prepare_inflections(locale, inflections_tree, idb, idb_strict)
|
|
250
|
+
|
|
251
|
+
# add inflection tokens and kinds to internal database
|
|
252
|
+
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
|
|
253
|
+
# validate token's kind
|
|
254
|
+
if kind.to_s.empty? || InflectorCfg::Reserved::Kinds.invalid?(orig_kind, :DB)
|
|
255
|
+
raise I18n::BadInflectionKind.new(locale, orig_kind)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
tokens.each_pair do |token, description|
|
|
259
|
+
# test for duplicate
|
|
260
|
+
if subdb.has_token?(token, strict_kind)
|
|
261
|
+
raise I18n::DuplicatedInflectionToken.new(locale, token, orig_kind,
|
|
262
|
+
subdb.get_kind(token, strict_kind))
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# validate token's name
|
|
266
|
+
if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
|
|
267
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# validate token's description
|
|
271
|
+
if description.nil?
|
|
272
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind, description)
|
|
273
|
+
elsif description.to_s[0..0] == InflectorCfg::Markers::ALIAS
|
|
274
|
+
next
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# skip default token for later processing
|
|
278
|
+
next if token == :default
|
|
279
|
+
|
|
280
|
+
subdb.add_token(token, kind, description)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# handle aliases
|
|
285
|
+
inflections.each do |orig_kind, kind, _strict_kind, subdb, tokens|
|
|
286
|
+
tokens.each_pair do |token, description|
|
|
287
|
+
next if token == :default
|
|
288
|
+
next if description.to_s[0..0] != InflectorCfg::Markers::ALIAS
|
|
289
|
+
|
|
290
|
+
real_token = shorten_inflection_alias(token, orig_kind, locale, inflections_tree)
|
|
291
|
+
subdb.add_alias(token, real_token, kind) unless real_token.nil?
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# handle default tokens
|
|
295
|
+
next unless tokens.key?(:default)
|
|
296
|
+
|
|
297
|
+
if subdb.has_default_token?(kind)
|
|
298
|
+
raise I18n::DuplicatedInflectionToken.new(locale, :default, kind,
|
|
299
|
+
orig_kind)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
orig_target = tokens[:default]
|
|
303
|
+
target = orig_target.to_s
|
|
304
|
+
target = target[1..] if target[0..0] == InflectorCfg::Markers::ALIAS
|
|
305
|
+
raise I18n::BadInflectionToken.new(locale, token, orig_kind, orig_target) if target.empty?
|
|
306
|
+
|
|
307
|
+
target = subdb.get_true_token(target.to_sym, kind)
|
|
308
|
+
raise I18n::BadInflectionAlias.new(locale, :default, orig_kind, orig_target) if target.nil?
|
|
309
|
+
|
|
310
|
+
subdb.set_default_token(kind, target)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
[idb, idb_strict]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# @private
|
|
317
|
+
def prepare_inflections(locale, inflections, idb, idb_strict)
|
|
318
|
+
raise I18n::BadInflectionKind.new(locale, :INFLECTIONS_ROOT) unless inflections.respond_to?(:has_key?)
|
|
319
|
+
|
|
320
|
+
I18n::Inflector::LazyHashEnumerator.for(inflections).ary_map do |kind, tokens|
|
|
321
|
+
next if tokens.nil? || tokens.empty?
|
|
322
|
+
raise I18n::BadInflectionKind.new(locale, kind) unless tokens.respond_to?(:has_key?)
|
|
323
|
+
|
|
324
|
+
subdb = idb
|
|
325
|
+
strict_kind = nil
|
|
326
|
+
orig_kind = kind
|
|
327
|
+
if kind.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND
|
|
328
|
+
kind = kind.to_s[1..]
|
|
329
|
+
next if kind.empty?
|
|
330
|
+
|
|
331
|
+
kind = kind.to_sym
|
|
332
|
+
subdb = idb_strict
|
|
333
|
+
strict_kind = kind
|
|
334
|
+
end
|
|
335
|
+
[orig_kind, kind, strict_kind, subdb, tokens]
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# @private
|
|
340
|
+
def deep_symbolize(obj)
|
|
341
|
+
obj.each_with_object({}) do |(key, value), result|
|
|
342
|
+
value = deep_symbolize(value) if value.is_a?(Hash)
|
|
343
|
+
result[begin
|
|
344
|
+
key.to_s.to_sym
|
|
345
|
+
rescue StandardError
|
|
346
|
+
key
|
|
347
|
+
end || key] = value
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
|
5
|
+
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
|
|
6
|
+
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
|
|
7
|
+
#
|
|
8
|
+
# This file contains configuration of I18n::Inflector module.
|
|
9
|
+
|
|
10
|
+
module I18n
|
|
11
|
+
module Inflector
|
|
12
|
+
# This module contains submodules and module
|
|
13
|
+
# methods for handling global configuration
|
|
14
|
+
# of the engine.
|
|
15
|
+
module Config
|
|
16
|
+
# @private
|
|
17
|
+
def get_i18n_reserved_keys
|
|
18
|
+
return I18n::RESERVED_KEYS if defined?(I18n::RESERVED_KEYS)
|
|
19
|
+
return I18n::Backend::Base::RESERVED_KEYS if defined?(I18n::Backend::Base::RESERVED_KEYS)
|
|
20
|
+
return I18n::Backend::Simple::RESERVED_KEYS if defined?(I18n::Backend::Simple::RESERVED_KEYS)
|
|
21
|
+
return RESERVED_KEYS if defined?(RESERVED_KEYS)
|
|
22
|
+
|
|
23
|
+
[]
|
|
24
|
+
end
|
|
25
|
+
module_function :get_i18n_reserved_keys
|
|
26
|
+
|
|
27
|
+
# @private
|
|
28
|
+
def all_consts(obj, f = String)
|
|
29
|
+
obj.constants.filter_map do |c|
|
|
30
|
+
v = obj.const_get(c)
|
|
31
|
+
(v.is_a?(f) && c != 'ALL') ? v : nil
|
|
32
|
+
end.uniq
|
|
33
|
+
end
|
|
34
|
+
module_function :all_consts
|
|
35
|
+
|
|
36
|
+
# @private
|
|
37
|
+
def gen_regexp(ary)
|
|
38
|
+
::Regexp.new "[#{ary.join}]"
|
|
39
|
+
end
|
|
40
|
+
module_function :gen_regexp
|
|
41
|
+
|
|
42
|
+
# Prefix that makes option a controlling option.
|
|
43
|
+
OPTION_PREFIX = InflectionOptions::OPTION_PREFIX
|
|
44
|
+
|
|
45
|
+
# Regexp matching a prefix that makes option
|
|
46
|
+
# a controlling option.
|
|
47
|
+
OPTION_PREFIX_REGEXP = Regexp.new("^#{OPTION_PREFIX}")
|
|
48
|
+
|
|
49
|
+
# This module contains keys that have special
|
|
50
|
+
# meaning.
|
|
51
|
+
module Keys
|
|
52
|
+
# A Symbol that is used to mark default token
|
|
53
|
+
# in configuration and in options.
|
|
54
|
+
DEFAULT_TOKEN = :default
|
|
55
|
+
|
|
56
|
+
# All keys
|
|
57
|
+
ALL = HSet.new Config.all_consts(self, Symbol)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# This module contains characters that are markers
|
|
61
|
+
# giving the shape for a pattern and its elements.
|
|
62
|
+
module Markers
|
|
63
|
+
# A character that is used to mark pattern.
|
|
64
|
+
PATTERN = '@'
|
|
65
|
+
|
|
66
|
+
# A character that is used to mark a strict kind.
|
|
67
|
+
STRICT_KIND = '@'
|
|
68
|
+
|
|
69
|
+
# A character that is used to open a pattern.
|
|
70
|
+
PATTERN_BEGIN = '{'
|
|
71
|
+
|
|
72
|
+
# A character that ends a pattern.
|
|
73
|
+
PATTERN_END = '}'
|
|
74
|
+
|
|
75
|
+
# A character that indicates an alias.
|
|
76
|
+
ALIAS = '@'
|
|
77
|
+
|
|
78
|
+
# A character used to mark token value as loud.
|
|
79
|
+
LOUD_VALUE = '~'
|
|
80
|
+
|
|
81
|
+
# All markers.
|
|
82
|
+
ALL = Config.all_consts(self)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
module Escapes
|
|
86
|
+
# A general esape symbol.
|
|
87
|
+
ESCAPE = '\\'
|
|
88
|
+
|
|
89
|
+
# A regular expression that catches escape symbols.
|
|
90
|
+
ESCAPE_R = /\\([^\\])/
|
|
91
|
+
|
|
92
|
+
# A list of escape symbols that cause a pattern to be escaped.
|
|
93
|
+
PATTERN = HSet[Markers::PATTERN, Escapes::ESCAPE]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# This module contains constants that define
|
|
97
|
+
# operators in patterns.
|
|
98
|
+
module Operators
|
|
99
|
+
# This module contains constants that define
|
|
100
|
+
# operators in patterns that handle token
|
|
101
|
+
# groups or tokens.
|
|
102
|
+
module Tokens
|
|
103
|
+
# A character used to mark patterns as complex
|
|
104
|
+
# and to separate token groups assigned to different
|
|
105
|
+
# strict kinds.
|
|
106
|
+
AND = '+'
|
|
107
|
+
|
|
108
|
+
# A character that is used to separate tokens
|
|
109
|
+
# or token groups within a pattern.
|
|
110
|
+
OR = '|'
|
|
111
|
+
|
|
112
|
+
# A character used to assign value to a token
|
|
113
|
+
# or a group of tokens.
|
|
114
|
+
ASSIGN = ':'
|
|
115
|
+
|
|
116
|
+
# A character used to create a virtual token
|
|
117
|
+
# that always matches.
|
|
118
|
+
WILDCARD = '*'
|
|
119
|
+
|
|
120
|
+
# All token groups operators.
|
|
121
|
+
ALL = Config.all_consts(self)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# This module contains constants that are operators
|
|
125
|
+
# in patterns that handle token groups or tokens.
|
|
126
|
+
module Token
|
|
127
|
+
# A character used to separate multiple tokens.
|
|
128
|
+
OR = ','
|
|
129
|
+
|
|
130
|
+
# A character used to mark tokens as negative.
|
|
131
|
+
NOT = '!'
|
|
132
|
+
|
|
133
|
+
# All token operators.
|
|
134
|
+
ALL = Config.all_consts(self)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# All operators.
|
|
138
|
+
ALL = Tokens::ALL | Token::ALL
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# This module contains constants defining
|
|
142
|
+
# reserved characters in tokens and kinds.
|
|
143
|
+
module Reserved
|
|
144
|
+
# Reserved keys.
|
|
145
|
+
KEYS = HSet.new(
|
|
146
|
+
Config.get_i18n_reserved_keys +
|
|
147
|
+
Config::Keys::ALL.to_a +
|
|
148
|
+
InflectionOptions.known.values
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# This module contains constants defining
|
|
152
|
+
# reserved characters in token identifiers.
|
|
153
|
+
module Tokens
|
|
154
|
+
# Reserved characters in token identifiers placed in configuration.
|
|
155
|
+
DB = (Operators::ALL | Markers::ALL) - [Markers::LOUD_VALUE]
|
|
156
|
+
|
|
157
|
+
# Reserved characters in token identifiers passed as options.
|
|
158
|
+
OPTION = DB
|
|
159
|
+
|
|
160
|
+
# Reserved characters in token identifiers placed in patterns.
|
|
161
|
+
PATTERN = OPTION - [Operators::Tokens::WILDCARD]
|
|
162
|
+
|
|
163
|
+
# This module contains constants defining
|
|
164
|
+
# regular expressions for reserved characters
|
|
165
|
+
# in token identifiers.
|
|
166
|
+
module Regexp
|
|
167
|
+
# Reserved characters in token identifiers placed in configuration.
|
|
168
|
+
DB = Config.gen_regexp Tokens::DB
|
|
169
|
+
|
|
170
|
+
# Reserved characters in token identifiers passed as options.
|
|
171
|
+
OPTION = Config.gen_regexp Tokens::OPTION
|
|
172
|
+
|
|
173
|
+
# Reserved characters in token identifiers placed in patterns.
|
|
174
|
+
PATTERN = Config.gen_regexp Tokens::PATTERN
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# This method checks if the given +token+ is invalid,
|
|
178
|
+
# that means it's either +nil+ or empty or it matches
|
|
179
|
+
# the refular expression given as +root+.
|
|
180
|
+
#
|
|
181
|
+
# @api public
|
|
182
|
+
# @param [Symbol,String] token the identifier of a token
|
|
183
|
+
# @param [Regexp] root the regular expression used to test
|
|
184
|
+
# @return [Boolean] +true+ if the given +token+ is
|
|
185
|
+
# invalid, +false+ otherwise
|
|
186
|
+
def invalid?(token, root)
|
|
187
|
+
token = token.to_s
|
|
188
|
+
token.empty? ||
|
|
189
|
+
(root == Regexp::PATTERN && Keys::ALL[token.to_sym]) ||
|
|
190
|
+
Regexp.const_get(root) =~ token
|
|
191
|
+
end
|
|
192
|
+
module_function :invalid?
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# This module contains constants defining
|
|
196
|
+
# reserved characters in kind identifiers.
|
|
197
|
+
module Kinds
|
|
198
|
+
# Reserved characters in kind identifiers placed in configuration.
|
|
199
|
+
DB = (Operators::ALL | Markers::ALL) - [Markers::ALIAS, Markers::LOUD_VALUE]
|
|
200
|
+
|
|
201
|
+
# Reserved characters in kind identifiers passed as option values.
|
|
202
|
+
OPTION = DB
|
|
203
|
+
|
|
204
|
+
# Reserved characters in kind identifiers placed in patterns.
|
|
205
|
+
PATTERN = (Operators::ALL | Markers::ALL) - [Markers::LOUD_VALUE]
|
|
206
|
+
|
|
207
|
+
# This module contains constants defining
|
|
208
|
+
# regular expressions for reserved characters
|
|
209
|
+
# in kind identifiers.
|
|
210
|
+
module Regexp
|
|
211
|
+
# Reserved characters in kind identifiers placed in configuration.
|
|
212
|
+
DB = Config.gen_regexp Kinds::DB
|
|
213
|
+
|
|
214
|
+
# Reserved characters in kind identifiers passed as option values.
|
|
215
|
+
OPTION = Config.gen_regexp Kinds::OPTION
|
|
216
|
+
|
|
217
|
+
# Reserved characters in kind identifiers placed in patterns.
|
|
218
|
+
PATTERN = Config.gen_regexp Kinds::PATTERN
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# This method checks if the given +kind+ is invalid,
|
|
222
|
+
# that means it's either +nil+ or empty or it matches
|
|
223
|
+
# the refular expression given as +root+.
|
|
224
|
+
#
|
|
225
|
+
# @api public
|
|
226
|
+
# @param [Symbol,String] kind the identifier of a kind
|
|
227
|
+
# @param [Regexp] root the regular expression used to test
|
|
228
|
+
# @return [Boolean] +true+ if the given +kind+ is
|
|
229
|
+
# invalid, +false+ otherwise
|
|
230
|
+
def invalid?(kind, root)
|
|
231
|
+
kind = kind.to_s
|
|
232
|
+
kind.empty? ||
|
|
233
|
+
(root != Regexp::OPTION &&
|
|
234
|
+
(KEYS[kind.to_sym] || OPTION_PREFIX_REGEXP =~ kind)) ||
|
|
235
|
+
Regexp.const_get(root) =~ kind
|
|
236
|
+
end
|
|
237
|
+
module_function :invalid?
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# A string for regular expression that catches patterns.
|
|
242
|
+
PATTERN_RESTR = "(.?)#{Markers::PATTERN}" \
|
|
243
|
+
"([^\\#{Markers::PATTERN_BEGIN}]*)\\#{Markers::PATTERN_BEGIN}" \
|
|
244
|
+
"([^\\#{Markers::PATTERN_END}]+)\\#{Markers::PATTERN_END}" \
|
|
245
|
+
"((?:\\#{Markers::PATTERN_BEGIN}([^\\#{Markers::PATTERN_BEGIN}" \
|
|
246
|
+
"]+)\\#{Markers::PATTERN_END})*)".freeze
|
|
247
|
+
|
|
248
|
+
# A string for regular expression that extracts additional patterns attached.
|
|
249
|
+
MULTI_RESTR = "\\#{Markers::PATTERN_BEGIN}" \
|
|
250
|
+
"([^\\#{Markers::PATTERN_END}]+)\\" \
|
|
251
|
+
"#{Markers::PATTERN_END}".freeze
|
|
252
|
+
|
|
253
|
+
# A regular expression that catches token groups or single tokens.
|
|
254
|
+
TOKENS_RESTR = '(?:' \
|
|
255
|
+
"([^#{Operators::Tokens::ASSIGN}\\#{Operators::Tokens::OR}]+)" \
|
|
256
|
+
"#{Operators::Tokens::ASSIGN}+" \
|
|
257
|
+
"([^\\#{Operators::Tokens::OR}]+)\\1?)" \
|
|
258
|
+
"|([^#{Operators::Tokens::ASSIGN}\\#{Operators::Tokens::OR}]+)".freeze
|
|
259
|
+
|
|
260
|
+
# A regular expression that catches patterns.
|
|
261
|
+
PATTERN_REGEXP = Regexp.new PATTERN_RESTR
|
|
262
|
+
|
|
263
|
+
# A regular expression that extracts additional patterns attached.
|
|
264
|
+
MULTI_REGEXP = Regexp.new MULTI_RESTR
|
|
265
|
+
|
|
266
|
+
# A regular expression that catches token groups or single tokens.
|
|
267
|
+
TOKENS_REGEXP = Regexp.new TOKENS_RESTR
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# @private
|
|
271
|
+
PATTERN_MARKER = Config::Markers::PATTERN
|
|
272
|
+
# @private
|
|
273
|
+
NAMED_MARKER = Config::Markers::STRICT_KIND
|
|
274
|
+
# @private
|
|
275
|
+
ALIAS_MARKER = Config::Markers::ALIAS
|
|
276
|
+
# @private
|
|
277
|
+
ESCAPE = Config::Escapes::ESCAPE
|
|
278
|
+
# @private
|
|
279
|
+
ESCAPE_R = Config::Escapes::ESCAPE_R
|
|
280
|
+
# @private
|
|
281
|
+
ESCAPES = Config::Escapes::PATTERN
|
|
282
|
+
# @private
|
|
283
|
+
PATTERN = Config::PATTERN_REGEXP
|
|
284
|
+
# @private
|
|
285
|
+
TOKENS = Config::TOKENS_REGEXP
|
|
286
|
+
# @private
|
|
287
|
+
INFLECTOR_RESERVED_KEYS = Config::Reserved::KEYS
|
|
288
|
+
end
|
|
289
|
+
end
|