i18n-inflector 2.1.0 → 2.2.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/ChangeLog +412 -0
- data/Manifest.txt +3 -0
- data/README.rdoc +38 -17
- data/docs/EXAMPLES +111 -22
- data/docs/HISTORY +37 -0
- data/docs/TODO +3 -27
- data/lib/i18n-inflector/api.rb +22 -234
- data/lib/i18n-inflector/api_strict.rb +1 -1
- data/lib/i18n-inflector/backend.rb +78 -23
- data/lib/i18n-inflector/config.rb +297 -0
- data/lib/i18n-inflector/errors.rb +184 -58
- data/lib/i18n-inflector/hset.rb +28 -0
- data/lib/i18n-inflector/inflection_data.rb +3 -1
- data/lib/i18n-inflector/inflection_data_strict.rb +3 -1
- data/lib/i18n-inflector/inflector.rb +1 -39
- data/lib/i18n-inflector/interpolate.rb +404 -0
- data/lib/i18n-inflector/lazy_enum.rb +52 -6
- data/lib/i18n-inflector/long_comments.rb +463 -157
- data/lib/i18n-inflector/options.rb +116 -20
- data/lib/i18n-inflector/version.rb +1 -1
- data/lib/i18n-inflector.rb +4 -1
- data/test/inflector_test.rb +179 -22
- data.tar.gz.sig +0 -0
- metadata +7 -4
- metadata.gz.sig +0 -0
@@ -0,0 +1,404 @@
|
|
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::Inflector::Interpolate module,
|
8
|
+
# which is included in the API.
|
9
|
+
|
10
|
+
module I18n
|
11
|
+
module Inflector
|
12
|
+
|
13
|
+
# This module contains methods for interpolating
|
14
|
+
# inflection patterns.
|
15
|
+
module Interpolate
|
16
|
+
|
17
|
+
include I18n::Inflector::Config
|
18
|
+
|
19
|
+
# Interpolates inflection values in the given +string+
|
20
|
+
# using kinds given in +options+ and a matching tokens.
|
21
|
+
#
|
22
|
+
# @param [String] string the translation string
|
23
|
+
# containing patterns to interpolate
|
24
|
+
# @param [String,Symbol] locale the locale identifier
|
25
|
+
# @param [Hash] options the options
|
26
|
+
# ComplexPatternMalformed.new
|
27
|
+
# @raise {I18n::InvalidInflectionKind}
|
28
|
+
# @raise {I18n::InvalidInflectionOption}
|
29
|
+
# @raise {I18n::InvalidInflectionToken}
|
30
|
+
# @raise {I18n::MisplacedInflectionToken}
|
31
|
+
# @option options [Boolean] :inflector_excluded_defaults (false) local switch
|
32
|
+
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#excluded_defaults})
|
33
|
+
# @option options [Boolean] :inflector_unknown_defaults (true) local switch
|
34
|
+
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#unknown_defaults})
|
35
|
+
# @option options [Boolean] :inflector_raises (false) local switch
|
36
|
+
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#raises})
|
37
|
+
# @option options [Boolean] :inflector_aliased_patterns (false) local switch
|
38
|
+
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#aliased_patterns})
|
39
|
+
# @option options [Boolean] :inflector_cache_aware (false) local switch
|
40
|
+
# that overrides global setting (see: {I18n::Inflector::InflectionOptions#cache_aware})
|
41
|
+
# @return [String] the string with interpolated patterns
|
42
|
+
def interpolate(string, locale, options = {})
|
43
|
+
interpolate_core(string, locale, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
# This method creates an inflection pattern
|
47
|
+
# by collecting information contained in a key-based
|
48
|
+
# inflection data.
|
49
|
+
#
|
50
|
+
# @param [Hash] key the given key
|
51
|
+
# @return [String] the inflection pattern
|
52
|
+
def key_to_pattern(key)
|
53
|
+
key = key.dup
|
54
|
+
pref = key.delete(:@prefix).to_s
|
55
|
+
suff = key.delete(:@suffix).to_s
|
56
|
+
kind = key.delete(:@kind).to_s
|
57
|
+
free = key.delete(:@free)
|
58
|
+
free = free.nil? ? "" : (Operators::Tokens::OR + free.to_s)
|
59
|
+
|
60
|
+
pref + Markers::PATTERN + kind + Markers::PATTERN_BEGIN +
|
61
|
+
key.map { |k,v| k.to_s + Operators::Tokens::ASSIGN + v.to_s }.
|
62
|
+
join(Operators::Tokens::OR) + free + Markers::PATTERN_END + suff
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# @private
|
68
|
+
def interpolate_core(string, locale, options)
|
69
|
+
passed_kinds = options.except(*Reserved::KEYS)
|
70
|
+
raises = options[:inflector_raises]
|
71
|
+
aliased_patterns = options[:inflector_aliased_patterns]
|
72
|
+
unknown_defaults = options[:inflector_unknown_defaults]
|
73
|
+
excluded_defaults = options[:inflector_excluded_defaults]
|
74
|
+
|
75
|
+
idb = @idb[locale]
|
76
|
+
idb_strict = @idb_strict[locale]
|
77
|
+
|
78
|
+
string.gsub(PATTERN_REGEXP) do
|
79
|
+
pattern_fix = $1
|
80
|
+
strict_kind = $2
|
81
|
+
pattern_content = $3
|
82
|
+
multipattern = $4
|
83
|
+
ext_pattern = $&
|
84
|
+
|
85
|
+
# initialize some defaults
|
86
|
+
ext_freetext = ''
|
87
|
+
found = nil
|
88
|
+
default_value = nil
|
89
|
+
tb_raised = nil
|
90
|
+
|
91
|
+
# leave escaped pattern as-is
|
92
|
+
unless pattern_fix.empty?
|
93
|
+
ext_pattern = ext_pattern[1..-1]
|
94
|
+
next ext_pattern if Escapes::PATTERN[pattern_fix]
|
95
|
+
end
|
96
|
+
|
97
|
+
# handle multiple patterns
|
98
|
+
unless multipattern.empty?
|
99
|
+
patterns = []
|
100
|
+
patterns << pattern_content
|
101
|
+
patterns += multipattern.scan(MULTI_REGEXP).flatten
|
102
|
+
next pattern_fix + patterns.map do |content|
|
103
|
+
interpolate_core(Markers::PATTERN + strict_kind +
|
104
|
+
Markers::PATTERN_BEGIN + content +
|
105
|
+
Markers::PATTERN_END, locale, options)
|
106
|
+
end.join
|
107
|
+
end
|
108
|
+
|
109
|
+
# set parsed kind if strict kind is given (named pattern is parsed)
|
110
|
+
if strict_kind.empty?
|
111
|
+
sym_parsed_kind = nil
|
112
|
+
strict_kind = nil
|
113
|
+
parsed_kind = nil
|
114
|
+
default_token = nil
|
115
|
+
subdb = idb
|
116
|
+
else
|
117
|
+
sym_parsed_kind = (Markers::PATTERN + strict_kind).to_sym
|
118
|
+
|
119
|
+
if strict_kind.include?(Operators::Tokens::AND)
|
120
|
+
|
121
|
+
# Complex markers processing
|
122
|
+
begin
|
123
|
+
result = interpolate_complex(strict_kind,
|
124
|
+
pattern_content,
|
125
|
+
locale, options)
|
126
|
+
rescue I18n::InflectionPatternException => e
|
127
|
+
e.pattern = ext_pattern
|
128
|
+
raise
|
129
|
+
end
|
130
|
+
found = pattern_content = "" # disable further processing
|
131
|
+
|
132
|
+
else
|
133
|
+
|
134
|
+
# Strict kinds preparing
|
135
|
+
subdb = idb_strict
|
136
|
+
|
137
|
+
# validate strict kind and set needed variables
|
138
|
+
if (Reserved::Kinds.invalid?(strict_kind, :PATTERN) ||
|
139
|
+
!idb_strict.has_kind?(strict_kind.to_sym))
|
140
|
+
raise I18n::InvalidInflectionKind.new(locale, ext_pattern, sym_parsed_kind) if raises
|
141
|
+
# Take a free text for invalid kind and return it
|
142
|
+
next pattern_fix + pattern_content.scan(TOKENS_REGEXP).reverse.
|
143
|
+
select { |t,v,f| t.nil? && !f.nil? }.
|
144
|
+
map { |t,v,f| f.to_s }.
|
145
|
+
first.to_s
|
146
|
+
else
|
147
|
+
strict_kind = strict_kind.to_sym
|
148
|
+
parsed_kind = strict_kind
|
149
|
+
# inject default token
|
150
|
+
default_token = subdb.get_default_token(parsed_kind)
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# process pattern content's
|
157
|
+
pattern_content.scan(TOKENS_REGEXP) do
|
158
|
+
ext_token = $1.to_s
|
159
|
+
ext_value = $2.to_s
|
160
|
+
ext_freetext = $3.to_s
|
161
|
+
tokens = Hash.new(false)
|
162
|
+
negatives = Hash.new(false)
|
163
|
+
kind = nil
|
164
|
+
passed_token = nil
|
165
|
+
result = nil
|
166
|
+
|
167
|
+
# TOKEN GROUP PROCESSING
|
168
|
+
|
169
|
+
# token not found?
|
170
|
+
if ext_token.empty?
|
171
|
+
# free text not found too? that should never happend.
|
172
|
+
if ext_freetext.empty?
|
173
|
+
raise I18n::InvalidInflectionToken.new(locale, ext_pattern, ext_token) if raises
|
174
|
+
end
|
175
|
+
next
|
176
|
+
end
|
177
|
+
|
178
|
+
# split tokens from group if comma is present and put into fast list
|
179
|
+
ext_token.split(Operators::Token::OR).each do |t|
|
180
|
+
# token name corrupted
|
181
|
+
if t.to_s.empty?
|
182
|
+
raise I18n::InvalidInflectionToken.new(locale, ext_pattern, t) if raises
|
183
|
+
next
|
184
|
+
end
|
185
|
+
|
186
|
+
# mark negative-matching token and put it on the negatives fast list
|
187
|
+
if t[0..0] == Operators::Token::NOT
|
188
|
+
t = t[1..-1]
|
189
|
+
negative = true
|
190
|
+
else
|
191
|
+
negative = false
|
192
|
+
end
|
193
|
+
|
194
|
+
# is token name corrupted?
|
195
|
+
if Reserved::Tokens.invalid?(t, :PATTERN)
|
196
|
+
raise I18n::InvalidInflectionToken.new(locale, ext_pattern, t) if raises
|
197
|
+
next
|
198
|
+
end
|
199
|
+
|
200
|
+
t = t.to_sym
|
201
|
+
t = subdb.get_true_token(t, strict_kind) if aliased_patterns
|
202
|
+
negatives[t] = true if negative
|
203
|
+
|
204
|
+
# get a kind for that token
|
205
|
+
kind = subdb.get_kind(t, strict_kind)
|
206
|
+
|
207
|
+
if kind.nil?
|
208
|
+
if raises
|
209
|
+
# regular pattern and token that has a bad kind
|
210
|
+
if strict_kind.nil?
|
211
|
+
raise I18n::InvalidInflectionToken.new(locale, ext_pattern, t, sym_parsed_kind)
|
212
|
+
else
|
213
|
+
# named pattern (kind validated before, so the only error is misplaced token)
|
214
|
+
raise I18n::MisplacedInflectionToken.new(locale, ext_pattern, t, sym_parsed_kind)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
next
|
218
|
+
end
|
219
|
+
|
220
|
+
# set processed kind after matching first token in a pattern
|
221
|
+
if parsed_kind.nil?
|
222
|
+
parsed_kind = kind
|
223
|
+
sym_parsed_kind = kind.to_sym
|
224
|
+
default_token = subdb.get_default_token(parsed_kind)
|
225
|
+
elsif parsed_kind != kind
|
226
|
+
# tokens of different kinds in one regular (not named) pattern are prohibited
|
227
|
+
raise I18n::MisplacedInflectionToken.new(locale, ext_pattern, t, sym_parsed_kind) if raises
|
228
|
+
next
|
229
|
+
end
|
230
|
+
|
231
|
+
# use that token
|
232
|
+
unless negatives[t]
|
233
|
+
tokens[t] = true
|
234
|
+
default_value = ext_value if t == default_token
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# self-explanatory
|
239
|
+
if (tokens.empty? && negatives.empty?)
|
240
|
+
raise I18n::InvalidInflectionToken.new(locale, ext_pattern, ext_token) if raises
|
241
|
+
end
|
242
|
+
|
243
|
+
# INFLECTION OPTION PROCESSING
|
244
|
+
|
245
|
+
# set up expected_kind depending on type of a kind
|
246
|
+
if strict_kind.nil?
|
247
|
+
expected_kind = parsed_kind
|
248
|
+
else
|
249
|
+
expected_kind = sym_parsed_kind
|
250
|
+
expected_kind = parsed_kind unless passed_kinds.has_key?(expected_kind)
|
251
|
+
end
|
252
|
+
|
253
|
+
# get passed token from options or from a default token
|
254
|
+
if passed_kinds.has_key?(expected_kind)
|
255
|
+
passed_token = passed_kinds[expected_kind]
|
256
|
+
orig_passed_token = passed_token
|
257
|
+
# validate passed token's name
|
258
|
+
if Reserved::Tokens.invalid?(passed_token, :OPTION)
|
259
|
+
raise I18n::InvalidInflectionOption.new(locale, ext_pattern, orig_passed_token) if raises
|
260
|
+
passed_token = default_token if unknown_defaults
|
261
|
+
end
|
262
|
+
else
|
263
|
+
# current inflection option wasn't found
|
264
|
+
# but delay this exception because we might use
|
265
|
+
# the default token if found somewhere in a pattern
|
266
|
+
tb_raised = InflectionOptionNotFound.new(locale, ext_pattern, ext_token,
|
267
|
+
expected_kind, orig_passed_token) if raises
|
268
|
+
passed_token = default_token
|
269
|
+
orig_passed_token = nil
|
270
|
+
end
|
271
|
+
|
272
|
+
# explicit default
|
273
|
+
passed_token = default_token if passed_token == Keys::DEFAULT_TOKEN
|
274
|
+
|
275
|
+
# resolve token from options and check if it's known
|
276
|
+
unless passed_token.nil?
|
277
|
+
passed_token = subdb.get_true_token(passed_token.to_sym, parsed_kind)
|
278
|
+
passed_token = default_token if passed_token.nil? && unknown_defaults
|
279
|
+
end
|
280
|
+
|
281
|
+
# throw the value if the given option matches one of the tokens from group
|
282
|
+
# or negatively matches one of the negated tokens
|
283
|
+
case negatives.count
|
284
|
+
when 0 then next unless tokens[passed_token]
|
285
|
+
when 1 then next if negatives[passed_token]
|
286
|
+
end
|
287
|
+
|
288
|
+
# skip further evaluation of the pattern
|
289
|
+
# since the right token has been found
|
290
|
+
found = passed_token
|
291
|
+
result = ext_value
|
292
|
+
break
|
293
|
+
|
294
|
+
end # single token (or a group) processing
|
295
|
+
|
296
|
+
# RESULTS PROCESSING
|
297
|
+
|
298
|
+
# if there was no hit for that option
|
299
|
+
if result.nil?
|
300
|
+
raise tb_raised unless tb_raised.nil?
|
301
|
+
|
302
|
+
# try to extract default token's value
|
303
|
+
|
304
|
+
# if there is excluded_defaults switch turned on
|
305
|
+
# and a correct token was found in an inflection option but
|
306
|
+
# has not been found in a pattern then interpolate
|
307
|
+
# the pattern with a value picked for the default
|
308
|
+
# token for that kind if a default token was present
|
309
|
+
# in a pattern
|
310
|
+
result = (excluded_defaults &&
|
311
|
+
!parsed_kind.nil? &&
|
312
|
+
subdb.has_token?(passed_kinds[parsed_kind], parsed_kind)) ?
|
313
|
+
default_value : nil
|
314
|
+
|
315
|
+
# interpolate loud tokens
|
316
|
+
elsif result == Markers::LOUD_VALUE
|
317
|
+
|
318
|
+
result = subdb.get_description(found, parsed_kind)
|
319
|
+
|
320
|
+
# interpolate escaped loud tokens or other escaped strings
|
321
|
+
elsif result[0..0] == Escapes::ESCAPE
|
322
|
+
|
323
|
+
result.sub!(Escapes::ESCAPE_R, '\1')
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
pattern_fix + (result || ext_freetext)
|
328
|
+
|
329
|
+
end # single pattern processing
|
330
|
+
|
331
|
+
end # def interpolate
|
332
|
+
|
333
|
+
# This is a helper that reduces a complex inflection pattern
|
334
|
+
# by producing equivalent of regular patterns of it and
|
335
|
+
# by interpolating them using {#interpolate} method.
|
336
|
+
#
|
337
|
+
# @param [String] complex_kind the complex kind (many kinds separated
|
338
|
+
# by the {Operators::Tokens::AND})
|
339
|
+
# @param [String] content the content of the processed pattern
|
340
|
+
# @param [Symbol] locale the locale to use
|
341
|
+
# @param [Hash] options the options
|
342
|
+
# @return [String] the interpolated pattern
|
343
|
+
def interpolate_complex(complex_kind, content, locale, options)
|
344
|
+
result = nil
|
345
|
+
free_text = ""
|
346
|
+
kinds = complex_kind.split(Operators::Tokens::AND).
|
347
|
+
reject{ |k| k.nil? || k.empty? }.each
|
348
|
+
|
349
|
+
begin
|
350
|
+
|
351
|
+
content.scan(TOKENS_REGEXP) do |tokens, value, free|
|
352
|
+
if tokens.nil?
|
353
|
+
raise IndexError.new if free.empty?
|
354
|
+
free_text = free
|
355
|
+
next
|
356
|
+
end
|
357
|
+
|
358
|
+
kinds.rewind
|
359
|
+
|
360
|
+
# process each token from set
|
361
|
+
results = tokens.split(Operators::Tokens::AND).map do |token|
|
362
|
+
raise IndexError.new if token.empty?
|
363
|
+
if value == Markers::LOUD_VALUE
|
364
|
+
r = interpolate_core(Markers::PATTERN + kinds.next.to_s + Markers::PATTERN_BEGIN + token.to_s +
|
365
|
+
Operators::Tokens::ASSIGN + value.to_s + Operators::Tokens::OR +
|
366
|
+
Markers::PATTERN + Markers::PATTERN_END, locale, options)
|
367
|
+
break if r == Markers::PATTERN
|
368
|
+
else
|
369
|
+
r = interpolate_core(Markers::PATTERN + kinds.next.to_s + Markers::PATTERN_BEGIN + token.to_s +
|
370
|
+
Operators::Tokens::ASSIGN + value.to_s + Markers::PATTERN_END, locale, options)
|
371
|
+
break if r != value # stop with this set, because something is not matching
|
372
|
+
end
|
373
|
+
r
|
374
|
+
end
|
375
|
+
|
376
|
+
# some token didn't matched, try another set
|
377
|
+
next if results.nil?
|
378
|
+
|
379
|
+
# generate result for set or raise error
|
380
|
+
if results.size == kinds.count
|
381
|
+
result = value == Markers::LOUD_VALUE ? results.join(' ') : value
|
382
|
+
break
|
383
|
+
else
|
384
|
+
raise IndexError.new
|
385
|
+
end
|
386
|
+
|
387
|
+
end # scan tokens
|
388
|
+
|
389
|
+
rescue IndexError, StopIteration
|
390
|
+
|
391
|
+
if options[:inflector_raises]
|
392
|
+
raise I18n::ComplexPatternMalformed.new(locale, content, nil, complex_kind)
|
393
|
+
end
|
394
|
+
result = nil
|
395
|
+
|
396
|
+
end
|
397
|
+
|
398
|
+
result || free_text
|
399
|
+
|
400
|
+
end # def interpolate_complex
|
401
|
+
|
402
|
+
end # module Interpolate
|
403
|
+
end # module Inflector
|
404
|
+
end # module I18n
|
@@ -12,7 +12,7 @@ module I18n
|
|
12
12
|
if RUBY_VERSION.gsub(/\D/,'')[0..1].to_i < 19
|
13
13
|
require 'enumerator' rescue nil
|
14
14
|
|
15
|
-
class
|
15
|
+
class LazyEnumerator < Object.const_defined?(:Enumerator) ? Enumerator : Enumerable::Enumerator
|
16
16
|
|
17
17
|
# This class allows to initialize the Enumerator with a block
|
18
18
|
class Yielder
|
@@ -46,24 +46,62 @@ module I18n
|
|
46
46
|
alias_method :with_object, :each_with_object
|
47
47
|
end
|
48
48
|
|
49
|
-
end # class
|
49
|
+
end # class LazyEnumerator for ruby18
|
50
50
|
|
51
51
|
else # if RUBY_VERSION >= 1.9.0
|
52
52
|
|
53
|
-
class
|
53
|
+
class LazyEnumerator < Enumerator
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# This class implements simple enumerators for arrays
|
59
|
+
# that allow to do lazy operations on them.
|
60
|
+
class LazyArrayEnumerator < LazyEnumerator
|
61
|
+
|
62
|
+
# Mapping enumerator
|
63
|
+
# @return [I18n::Inflector::LazyEnumerator] the enumerator
|
64
|
+
def map(&block)
|
65
|
+
LazyArrayEnumerator.new do |yielder|
|
66
|
+
self.each do |v|
|
67
|
+
yielder.yield(block.call(v))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Array selecting enumerator
|
73
|
+
# @return [I18n::Inflector::LazyHashEnumerator] the enumerator
|
74
|
+
def select(&block)
|
75
|
+
LazyArrayEnumerator.new do |yielder|
|
76
|
+
self.each do |v|
|
77
|
+
yielder.yield(v) if block.call(v)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Array rejecting enumerator
|
83
|
+
# @return [I18n::Inflector::LazyHashEnumerator] the enumerator
|
84
|
+
def reject(&block)
|
85
|
+
LazyArrayEnumerator.new do |yielder|
|
86
|
+
self.each do |v|
|
87
|
+
yielder.yield(v) unless block.call(v)
|
88
|
+
end
|
89
|
+
end
|
54
90
|
end
|
55
91
|
|
56
92
|
end
|
57
93
|
|
58
94
|
# This class implements simple enumerators for hashes
|
59
95
|
# that allow to do lazy operations on them.
|
60
|
-
class LazyHashEnumerator
|
96
|
+
class LazyHashEnumerator < LazyEnumerator
|
61
97
|
|
62
98
|
# Creates a Hash kind of object by collecting all
|
63
99
|
# data from enumerated collection.
|
64
100
|
# @return [Hash] the resulting hash
|
65
101
|
def to_h
|
66
|
-
Hash
|
102
|
+
h = Hash.new
|
103
|
+
self.each{|k,v| h[k]=v }
|
104
|
+
h
|
67
105
|
end
|
68
106
|
|
69
107
|
# Hash mapping enumerator
|
@@ -87,13 +125,21 @@ module I18n
|
|
87
125
|
end
|
88
126
|
|
89
127
|
# This method converts resulting keys
|
90
|
-
# to array.
|
128
|
+
# to an array.
|
91
129
|
def keys
|
92
130
|
ary = []
|
93
131
|
self.each{ |k,v| ary << k }
|
94
132
|
return ary
|
95
133
|
end
|
96
134
|
|
135
|
+
# This method converts resulting values
|
136
|
+
# to an array.
|
137
|
+
def values
|
138
|
+
ary = []
|
139
|
+
self.each{ |k,v| ary << v }
|
140
|
+
return ary
|
141
|
+
end
|
142
|
+
|
97
143
|
# Hash selecting enumerator
|
98
144
|
# @return [I18n::Inflector::LazyHashEnumerator] the enumerator
|
99
145
|
def select(&block)
|