extlib 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of extlib might be problematic. Click here for more details.

Files changed (54) hide show
  1. data/History.txt +22 -0
  2. data/LICENSE +1 -1
  3. data/README +0 -0
  4. data/Rakefile +17 -12
  5. data/lib/extlib.rb +1 -1
  6. data/lib/extlib/blank.rb +51 -21
  7. data/lib/extlib/boolean.rb +1 -1
  8. data/lib/extlib/class.rb +12 -12
  9. data/lib/extlib/datetime.rb +20 -2
  10. data/lib/extlib/dictionary.rb +2 -2
  11. data/lib/extlib/hash.rb +57 -34
  12. data/lib/extlib/inflection.rb +0 -1
  13. data/lib/extlib/lazy_array.rb +327 -36
  14. data/lib/extlib/logger.rb +8 -8
  15. data/lib/extlib/mash.rb +45 -45
  16. data/lib/extlib/module.rb +1 -1
  17. data/lib/extlib/nil.rb +1 -1
  18. data/lib/extlib/numeric.rb +1 -1
  19. data/lib/extlib/object.rb +8 -21
  20. data/lib/extlib/object_space.rb +3 -3
  21. data/lib/extlib/pathname.rb +10 -0
  22. data/lib/extlib/pooling.rb +9 -17
  23. data/lib/extlib/rubygems.rb +7 -7
  24. data/lib/extlib/simple_set.rb +35 -8
  25. data/lib/extlib/string.rb +85 -42
  26. data/lib/extlib/struct.rb +10 -1
  27. data/lib/extlib/symbol.rb +11 -7
  28. data/lib/extlib/time.rb +31 -9
  29. data/lib/extlib/version.rb +1 -1
  30. data/lib/extlib/virtual_file.rb +1 -1
  31. data/spec/blank_spec.rb +85 -0
  32. data/spec/class_spec.rb +141 -0
  33. data/spec/datetime_spec.rb +22 -0
  34. data/spec/hash_spec.rb +537 -0
  35. data/spec/hook_spec.rb +1198 -0
  36. data/spec/inflection/plural_spec.rb +564 -0
  37. data/spec/inflection/singular_spec.rb +497 -0
  38. data/spec/inflection_extras_spec.rb +93 -0
  39. data/spec/lazy_array_spec.rb +1869 -0
  40. data/spec/mash_spec.rb +286 -0
  41. data/spec/module_spec.rb +58 -0
  42. data/spec/object_space_spec.rb +9 -0
  43. data/spec/object_spec.rb +114 -0
  44. data/spec/pooling_spec.rb +499 -0
  45. data/spec/simple_set_spec.rb +57 -0
  46. data/spec/spec_helper.rb +7 -0
  47. data/spec/string_spec.rb +220 -0
  48. data/spec/struct_spec.rb +12 -0
  49. data/spec/symbol_spec.rb +8 -0
  50. data/spec/time_spec.rb +22 -0
  51. data/spec/try_dup_spec.rb +45 -0
  52. data/spec/virtual_file_spec.rb +21 -0
  53. metadata +51 -26
  54. data/README.txt +0 -3
@@ -365,7 +365,6 @@ module Extlib
365
365
  word 'plus' , 'plusses'
366
366
  word 'cross' , 'crosses'
367
367
  word 'medium' , 'media'
368
- word 'cow' , 'kine'
369
368
  word 'datum' , 'data'
370
369
  word 'basis' , 'bases'
371
370
  word 'diagnosis' , 'diagnoses'
@@ -1,30 +1,255 @@
1
1
  class LazyArray # borrowed partially from StrokeDB
2
- instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ send dup class object_id kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get extend ].include?(m.to_s) }
2
+ instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ send class dup object_id kind_of? respond_to? equal? assert_kind_of should should_not instance_variable_set instance_variable_get extend ].include?(m.to_s) }
3
3
 
4
4
  include Enumerable
5
5
 
6
- # these methods should return self or nil
7
- RETURN_SELF = [ :<<, :clear, :concat, :collect!, :each, :each_index,
8
- :each_with_index, :freeze, :insert, :map!, :push, :replace,
9
- :reject!, :reverse!, :reverse_each, :sort!, :unshift ]
10
-
11
- RETURN_SELF.each do |method|
12
- class_eval <<-EOS, __FILE__, __LINE__
13
- def #{method}(*args, &block)
6
+ # this avoids a strange Ruby 1.8.6 bug where it cannot delegate to super() in #first
7
+ if RUBY_VERSION <= '1.8.6'
8
+ def first(*args)
9
+ if lazy_possible?(@head, *args)
10
+ @head.first(*args)
11
+ else
14
12
  lazy_load
15
- results = @array.#{method}(*args, &block)
16
- results.kind_of?(Array) ? self : results
13
+ @array.first(*args)
14
+ end
15
+ end
16
+ else
17
+ def first(*args)
18
+ if lazy_possible?(@head, *args)
19
+ @head.first(*args)
20
+ else
21
+ super
17
22
  end
18
- EOS
23
+ end
19
24
  end
20
25
 
21
- (Array.public_instance_methods(false).map { |m| m.to_sym } - RETURN_SELF - [ :taguri= ]).each do |method|
22
- class_eval <<-EOS, __FILE__, __LINE__
23
- def #{method}(*args, &block)
24
- lazy_load
25
- @array.#{method}(*args, &block)
26
+ def last(*args)
27
+ if lazy_possible?(@tail, *args)
28
+ @tail.last(*args)
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ def at(index)
35
+ if index >= 0 && lazy_possible?(@head, index + 1)
36
+ @head.at(index)
37
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
38
+ @tail.at(index)
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ def fetch(*args, &block)
45
+ index = args.first
46
+
47
+ if index >= 0 && lazy_possible?(@head, index + 1)
48
+ @head.fetch(*args, &block)
49
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
50
+ @tail.fetch(*args, &block)
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ def values_at(*args)
57
+ accumulator = []
58
+
59
+ lazy_possible = args.all? do |arg|
60
+ index, length = extract_slice_arguments(arg)
61
+
62
+ if index >= 0 && lazy_possible?(@head, index + (length || 1))
63
+ accumulator.concat(head.values_at(*arg))
64
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
65
+ accumulator.concat(tail.values_at(*arg))
66
+ end
67
+ end
68
+
69
+ if lazy_possible
70
+ accumulator
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ def index(entry)
77
+ (lazy_possible?(@head) && @head.index(entry)) || super
78
+ end
79
+
80
+ def include?(entry)
81
+ (lazy_possible?(@tail) && @tail.include?(entry)) ||
82
+ (lazy_possible?(@head) && @head.include?(entry)) ||
83
+ super
84
+ end
85
+
86
+ def empty?
87
+ !any?
88
+ end
89
+
90
+ def any?
91
+ (lazy_possible?(@tail) && @tail.any?) ||
92
+ (lazy_possible?(@head) && @head.any?) ||
93
+ super
94
+ end
95
+
96
+ def [](*args)
97
+ index, length = extract_slice_arguments(*args)
98
+
99
+ if length.nil?
100
+ return at(index)
101
+ end
102
+
103
+ length ||= 1
104
+
105
+ if index >= 0 && lazy_possible?(@head, index + length)
106
+ @head.slice(*args)
107
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
108
+ @tail.slice(*args)
109
+ else
110
+ super
111
+ end
112
+ end
113
+
114
+ alias slice []
115
+
116
+ def slice!(*args)
117
+ index, length = extract_slice_arguments(*args)
118
+
119
+ length ||= 1
120
+
121
+ if index >= 0 && lazy_possible?(@head, index + length)
122
+ @head.slice!(*args)
123
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
124
+ @tail.slice!(*args)
125
+ else
126
+ super
127
+ end
128
+ end
129
+
130
+ def []=(*args)
131
+ index, length = extract_slice_arguments(*args[0..-2])
132
+
133
+ length ||= 1
134
+
135
+ if index >= 0 && lazy_possible?(@head, index + length)
136
+ @head.[]=(*args)
137
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
138
+ @tail.[]=(*args)
139
+ else
140
+ super
141
+ end
142
+ end
143
+
144
+ alias splice []=
145
+
146
+ def reverse
147
+ dup.reverse!
148
+ end
149
+
150
+ def reverse!
151
+ # reverse without kicking if possible
152
+ if loaded?
153
+ @array = @array.reverse
154
+ else
155
+ @head, @tail = @tail.reverse, @head.reverse
156
+
157
+ proc = @load_with_proc
158
+
159
+ @load_with_proc = lambda do |v|
160
+ proc.call(v)
161
+ v.instance_variable_get(:@array).reverse!
26
162
  end
27
- EOS
163
+ end
164
+
165
+ self
166
+ end
167
+
168
+ def <<(entry)
169
+ if loaded?
170
+ super
171
+ else
172
+ @tail << entry
173
+ end
174
+ self
175
+ end
176
+
177
+ alias add <<
178
+
179
+ def concat(other)
180
+ if loaded?
181
+ super
182
+ else
183
+ @tail.concat(other.entries)
184
+ end
185
+ self
186
+ end
187
+
188
+ def push(*entries)
189
+ if loaded?
190
+ super
191
+ else
192
+ @tail.push(*entries)
193
+ end
194
+ self
195
+ end
196
+
197
+ def unshift(*entries)
198
+ if loaded?
199
+ super
200
+ else
201
+ @head.unshift(*entries)
202
+ end
203
+ self
204
+ end
205
+
206
+ def insert(index, *entries)
207
+ if index >= 0 && lazy_possible?(@head, index)
208
+ @head.insert(index, *entries)
209
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1)
210
+ @tail.insert(index, *entries)
211
+ else
212
+ super
213
+ end
214
+ self
215
+ end
216
+
217
+ def pop
218
+ if lazy_possible?(@tail)
219
+ @tail.pop
220
+ else
221
+ super
222
+ end
223
+ end
224
+
225
+ def shift
226
+ if lazy_possible?(@head)
227
+ @head.shift
228
+ else
229
+ super
230
+ end
231
+ end
232
+
233
+ def delete_at(index)
234
+ if index >= 0 && lazy_possible?(@head, index + 1)
235
+ @head.delete_at(index)
236
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
237
+ @tail.delete_at(index)
238
+ else
239
+ super
240
+ end
241
+ end
242
+
243
+ def delete_if(&block)
244
+ if loaded?
245
+ super
246
+ else
247
+ @reapers ||= []
248
+ @reapers << block
249
+ @head.delete_if(&block)
250
+ @tail.delete_if(&block)
251
+ end
252
+ self
28
253
  end
29
254
 
30
255
  def replace(other)
@@ -39,12 +264,12 @@ class LazyArray # borrowed partially from StrokeDB
39
264
  self
40
265
  end
41
266
 
42
- def eql?(other)
267
+ def to_a
43
268
  lazy_load
44
- @array.eql?(other.entries)
269
+ @array.to_a
45
270
  end
46
271
 
47
- alias == eql?
272
+ alias to_ary to_a
48
273
 
49
274
  def load_with(&block)
50
275
  @load_with_proc = block
@@ -55,50 +280,116 @@ class LazyArray # borrowed partially from StrokeDB
55
280
  @loaded == true
56
281
  end
57
282
 
58
- def unload
59
- clear
60
- @loaded = false
61
- self
283
+ def kind_of?(klass)
284
+ super || @array.kind_of?(klass)
62
285
  end
63
286
 
64
287
  def respond_to?(method, include_private = false)
65
- super || @array.respond_to?(method, include_private)
288
+ super || @array.respond_to?(method)
289
+ end
290
+
291
+ def freeze
292
+ if loaded?
293
+ @array.freeze
294
+ else
295
+ @head.freeze
296
+ @tail.freeze
297
+ end
298
+ @frozen = true
299
+ self
66
300
  end
67
301
 
68
- def to_proc
69
- @load_with_proc
302
+ def frozen?
303
+ @frozen == true
304
+ end
305
+
306
+ def eql?(other)
307
+ lazy_load
308
+ @array.eql?(other.entries)
309
+ end
310
+
311
+ alias == eql?
312
+
313
+ protected
314
+
315
+ attr_reader :head, :tail
316
+
317
+ def lazy_possible?(list, need_length = 1)
318
+ !loaded? && need_length <= list.size
70
319
  end
71
320
 
72
321
  private
73
322
 
74
- def initialize(*args, &block)
75
- @loaded = false
76
- @load_with_proc = proc { |v| v }
77
- @array = Array.new(*args, &block)
323
+ def initialize
324
+ @load_with_proc = lambda { |v| v }
325
+ @head = []
326
+ @tail = []
327
+ @array = []
78
328
  end
79
329
 
80
330
  def initialize_copy(original)
81
- @array = original.entries
82
- load_with(&original)
83
- mark_loaded if @array.any?
331
+ if original.loaded?
332
+ mark_loaded
333
+ @array = @array.dup
334
+ @head = @tail = nil
335
+ else
336
+ @head = @head.dup
337
+ @tail = @tail.dup
338
+ @array = @array.dup
339
+ end
84
340
  end
85
341
 
86
342
  def lazy_load
87
343
  return if loaded?
88
344
  mark_loaded
89
345
  @load_with_proc[self]
346
+ @array.unshift(*@head)
347
+ @array.concat(@tail)
348
+ @head = @tail = nil
349
+ @reapers.each { |r| @array.delete_if(&r) } if @reapers
350
+ @array.freeze if frozen?
90
351
  end
91
352
 
92
353
  def mark_loaded
93
354
  @loaded = true
94
355
  end
95
356
 
357
+ ##
358
+ # Extract arguments for #slice an #slice! and return index and length
359
+ #
360
+ # @param [Integer, Array(Integer), Range] *args the index,
361
+ # index and length, or range indicating first and last position
362
+ #
363
+ # @return [Integer] the index
364
+ # @return [Integer,NilClass] the length, if any
365
+ #
366
+ # @api private
367
+ def extract_slice_arguments(*args)
368
+ first_arg, second_arg = args
369
+
370
+ if args.size == 2 && first_arg.kind_of?(Integer) && second_arg.kind_of?(Integer)
371
+ return first_arg, second_arg
372
+ elsif args.size == 1
373
+ if first_arg.kind_of?(Integer)
374
+ return first_arg
375
+ elsif first_arg.kind_of?(Range)
376
+ index = first_arg.first
377
+ length = first_arg.last - index
378
+ length += 1 unless first_arg.exclude_end?
379
+ return index, length
380
+ end
381
+ end
382
+
383
+ raise ArgumentError, "arguments may be 1 or 2 Integers, or 1 Range object, was: #{args.inspect}", caller(1)
384
+ end
385
+
96
386
  # delegate any not-explicitly-handled methods to @array, if possible.
97
387
  # this is handy for handling methods mixed-into Array like group_by
98
388
  def method_missing(method, *args, &block)
99
389
  if @array.respond_to?(method)
100
390
  lazy_load
101
- @array.send(method, *args, &block)
391
+ results = @array.send(method, *args, &block)
392
+ results.equal?(@array) ? self : results
102
393
  else
103
394
  super
104
395
  end
@@ -21,14 +21,14 @@ require "time" # httpdate
21
21
  # Merb.logger.info!(message<String>,&block)
22
22
  # Merb.logger.debug!(message<String>,&block)
23
23
  #
24
- # Flush the buffer to
24
+ # Flush the buffer to
25
25
  # Merb.logger.flush
26
26
  #
27
27
  # Remove the current log object
28
28
  # Merb.logger.close
29
- #
29
+ #
30
30
  # ==== Private Merb Logger API
31
- #
31
+ #
32
32
  # To initialize the logger you create a new object, proxies to set_log.
33
33
  # Merb::Logger.new(log{String, IO},level{Symbol, String})
34
34
  module Extlib
@@ -53,10 +53,10 @@ module Extlib
53
53
  # :warn:: A warning
54
54
  # :info:: generic (useful) information about system operation
55
55
  # :debug:: low-level information for developers
56
- Levels =
56
+ Levels =
57
57
  {
58
- :fatal => 7,
59
- :error => 6,
58
+ :fatal => 7,
59
+ :error => 6,
60
60
  :warn => 4,
61
61
  :info => 3,
62
62
  :debug => 0
@@ -96,7 +96,7 @@ module Extlib
96
96
  end
97
97
 
98
98
  # Replaces an existing logger with a new one.
99
- #
99
+ #
100
100
  # ==== Parameters
101
101
  # log<IO, String>:: Either an IO object or a name of a logfile.
102
102
  # log_level<~to_sym>::
@@ -198,5 +198,5 @@ module Extlib
198
198
  end
199
199
 
200
200
  end
201
-
201
+
202
202
  end