i18n-inflector 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|