Class: DataMapper::Validations::OrderedHash

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/dm-validations/support/ordered_hash.rb

Overview

Dictionary

The Dictionary class is a Hash that preserves order. So it has some array-like extensions also. By defualt a Dictionary object preserves insertion order, but any order can be specified including alphabetical key order.

Usage

Just require this file and use Dictionary instead of Hash.

You can do simply

hsh = Dictionary.new hsh = 1 hsh = 2 hsh = 3 p hsh.keys #=> ['z','a','c']

or using Dictionary method

hsh = Dictionary['z', 1, 'a', 2, 'c', 3] p hsh.keys #=> ['z','a','c']

but this doesn't preserve order

hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3] p hsh.keys #=> ['a','c','z']

Dictionary has useful extensions: push, pop and unshift

p hsh.push('to_end', 15) #=> true, key added p hsh.push('to_end', 30) #=> false, already - nothing happen p hsh.unshift('to_begin', 50) #=> true, key added p hsh.unshift('to_begin', 60) #=> false, already - nothing happen p hsh.keys #=> ["to_begin", "a", "c", "z", "to_end"] p hsh.pop #=> ["to_end", 15], if nothing remains, return nil p hsh.keys #=> ["to_begin", "a", "c", "z"] p hsh.shift #=> ["to_begin", 30], if nothing remains, return nil

Usage Notes

  • You can use #order_by to set internal sort order.
  • #<< takes a two element [k,v] array and inserts.
  • Use ::auto which creates Dictionay sub-entries as needed.
  • And ::alpha which creates a new Dictionary sorted by key.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &blk) ⇒ OrderedHash

New Dictiionary.



136
137
138
139
140
141
142
143
144
145
146
# File 'lib/dm-validations/support/ordered_hash.rb', line 136

def initialize(*args, &blk)
  @order = []
  @order_by = nil
  if blk
    dict = self                                  # This ensure autmatic key entry effect the
    oblk = lambda{ |hsh, key| blk[dict,key] }    # dictionary rather then just the interal hash.
    @hash = Hash.new(*args, &oblk)
  else
    @hash = Hash.new(*args)
  end
end

Class Method Details

.[](*args) ⇒ Object

-- TODO is this needed? Doesn't the super class do this? ++



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/dm-validations/support/ordered_hash.rb', line 88

def [](*args)
  hsh = new
  if Hash === args[0]
    hsh.replace(args[0])
  elsif (args.size % 2) != 0
    raise ArgumentError, "odd number of elements for Hash"
  else
    while !args.empty?
      hsh[args.shift] = args.shift
    end
  end
  hsh
end

.alpha(*args, &block) ⇒ Object

Alternate to #new which creates a dictionary sorted by key.

d = Dictionary.alpha
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| key }


119
120
121
# File 'lib/dm-validations/support/ordered_hash.rb', line 119

def alpha(*args, &block)
  new(*args, &block).order_by_key
end

.auto(*args) ⇒ Object

Alternate to #new which auto-creates sub-dictionaries as needed.

d = Dictionary.auto
d["a"]["b"]["c"] = "abc"  #=> { "a"=>{"b"=>{"c"=>"abc"}}}


128
129
130
131
132
# File 'lib/dm-validations/support/ordered_hash.rb', line 128

def auto(*args)
  #AutoDictionary.new(*args)
  leet = lambda { |hsh, key| hsh[key] = new(&leet) }
  new(*args, &leet)
end

.new_by(*args, &blk) ⇒ Object

Like #new but the block sets the order.



104
105
106
# File 'lib/dm-validations/support/ordered_hash.rb', line 104

def new_by(*args, &blk)
  new(*args).order_by(&blk)
end

Instance Method Details

#<<(kv) ⇒ Object



323
324
325
# File 'lib/dm-validations/support/ordered_hash.rb', line 323

def <<(kv)
  push( *kv )
end

#==(hsh2) ⇒ Object



205
206
207
208
209
210
211
212
# File 'lib/dm-validations/support/ordered_hash.rb', line 205

def ==(hsh2)
  if hsh2.is_a?( Dictionary )
    @order == hsh2.order &&
    @hash  == hsh2.instance_variable_get("@hash")
  else
    false
  end
end

#[](k) ⇒ Object



214
215
216
# File 'lib/dm-validations/support/ordered_hash.rb', line 214

def [] k
  @hash[ k ]
end

#[]=(k, i = nil, v = nil) ⇒ Object

Store operator.

h[key] = value

Or with additional index.

h = value



229
230
231
232
233
234
235
# File 'lib/dm-validations/support/ordered_hash.rb', line 229

def []=(k, i=nil, v=nil)
  if v
    insert(i,k,v)
  else
    store(k,i)
  end
end

#clearObject



247
248
249
250
# File 'lib/dm-validations/support/ordered_hash.rb', line 247

def clear
  @order = []
  @hash.clear
end

#delete(key) ⇒ Object



252
253
254
255
# File 'lib/dm-validations/support/ordered_hash.rb', line 252

def delete( key )
  @order.delete( key )
  @hash.delete( key )
end

#delete_ifObject



273
274
275
276
# File 'lib/dm-validations/support/ordered_hash.rb', line 273

def delete_if
  order.clone.each { |k| delete k if yield(k,@hash[k]) }
  self
end

#dupObject



348
349
350
351
352
# File 'lib/dm-validations/support/ordered_hash.rb', line 348

def dup
  a = []
  each{ |k,v| a << k; a << v }
  self.class[*a]
end

#eachObject Also known as: each_pair



267
268
269
270
# File 'lib/dm-validations/support/ordered_hash.rb', line 267

def each
  order.each { |k| yield( k,@hash[k] ) }
  self
end

#each_keyObject



257
258
259
260
# File 'lib/dm-validations/support/ordered_hash.rb', line 257

def each_key
  order.each { |k| yield( k ) }
  self
end

#each_valueObject



262
263
264
265
# File 'lib/dm-validations/support/ordered_hash.rb', line 262

def each_value
  order.each { |k| yield( @hash[k] ) }
  self
end

#empty?Boolean

Returns:

  • (Boolean)


393
394
395
# File 'lib/dm-validations/support/ordered_hash.rb', line 393

def empty?
  @hash.empty?
end

#fetch(k, *a, &b) ⇒ Object



218
219
220
# File 'lib/dm-validations/support/ordered_hash.rb', line 218

def fetch(k, *a, &b)
  @hash.fetch(k, *a, &b)
end

#firstObject



380
381
382
# File 'lib/dm-validations/support/ordered_hash.rb', line 380

def first
  @hash[order.first]
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


397
398
399
# File 'lib/dm-validations/support/ordered_hash.rb', line 397

def has_key?(key)
  @hash.has_key?(key)
end

#insert(i, k, v) ⇒ Object



237
238
239
240
# File 'lib/dm-validations/support/ordered_hash.rb', line 237

def insert( i,k,v )
  @order.insert( i,k )
  @hash.store( k,v )
end

#inspectObject



342
343
344
345
346
# File 'lib/dm-validations/support/ordered_hash.rb', line 342

def inspect
  ary = []
  each {|k,v| ary << k.inspect + "=>" + v.inspect}
  '{' + ary.join(", ") + '}'
end

#invertObject



288
289
290
291
292
# File 'lib/dm-validations/support/ordered_hash.rb', line 288

def invert
  hsh2 = self.class.new
  order.each { |k| hsh2[@hash[k]] = k }
  hsh2
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


401
402
403
# File 'lib/dm-validations/support/ordered_hash.rb', line 401

def key?(key)
  @hash.key?(key)
end

#keysObject



284
285
286
# File 'lib/dm-validations/support/ordered_hash.rb', line 284

def keys
  order
end

#lastObject



384
385
386
# File 'lib/dm-validations/support/ordered_hash.rb', line 384

def last
  @hash[order.last]
end

#lengthObject Also known as: size



388
389
390
# File 'lib/dm-validations/support/ordered_hash.rb', line 388

def length
  @order.length
end

#merge(hsh2) ⇒ Object



361
362
363
# File 'lib/dm-validations/support/ordered_hash.rb', line 361

def merge( hsh2 )
  self.dup.update(hsh2)
end

#orderObject



148
149
150
151
# File 'lib/dm-validations/support/ordered_hash.rb', line 148

def order
  reorder if @order_by
  @order
end

#order_by(&block) ⇒ Object

Keep dictionary sorted by a specific sort order.



154
155
156
157
158
# File 'lib/dm-validations/support/ordered_hash.rb', line 154

def order_by( &block )
  @order_by = block
  order
  self
end

#order_by_keyObject

Keep dictionary sorted by key.

d = Dictionary.new.order_by_key
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| key }

The initializer Dictionary#alpha also provides this.



173
174
175
176
177
# File 'lib/dm-validations/support/ordered_hash.rb', line 173

def order_by_key
  @order_by = lambda { |k,v| k }
  order
  self
end

#order_by_valueObject

Keep dictionary sorted by value.

d = Dictionary.new.order_by_value
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| value }


190
191
192
193
194
# File 'lib/dm-validations/support/ordered_hash.rb', line 190

def order_by_value
  @order_by = lambda { |k,v| v }
  order
  self
end

#popObject



337
338
339
340
# File 'lib/dm-validations/support/ordered_hash.rb', line 337

def pop
  key = order.last
  key ? [key,delete(key)] : nil
end

#push(k, v) ⇒ Object



327
328
329
330
331
332
333
334
335
# File 'lib/dm-validations/support/ordered_hash.rb', line 327

def push( k,v )
  unless @hash.include?( k )
    @order.push( k )
    @hash.store( k,v )
    true
  else
    false
  end
end

#reject(&block) ⇒ Object



294
295
296
# File 'lib/dm-validations/support/ordered_hash.rb', line 294

def reject( &block )
  self.dup.delete_if(&block)
end

#reject!(&block) ⇒ Object



298
299
300
301
# File 'lib/dm-validations/support/ordered_hash.rb', line 298

def reject!( &block )
  hsh2 = reject(&block)
  self == hsh2 ? nil : hsh2
end

#reorderObject



197
198
199
200
201
202
203
# File 'lib/dm-validations/support/ordered_hash.rb', line 197

def reorder
  if @order_by
    assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
    @order = assoc.collect{ |k,v| k }
  end
  @order
end

#replace(hsh2) ⇒ Object



303
304
305
306
# File 'lib/dm-validations/support/ordered_hash.rb', line 303

def replace( hsh2 )
  @order = hsh2.order
  @hash = hsh2.hash
end

#reverseObject



376
377
378
# File 'lib/dm-validations/support/ordered_hash.rb', line 376

def reverse
  dup.reverse!
end

#reverse!Object



371
372
373
374
# File 'lib/dm-validations/support/ordered_hash.rb', line 371

def reverse!
  @order.reverse!
  self
end

#selectObject



365
366
367
368
369
# File 'lib/dm-validations/support/ordered_hash.rb', line 365

def select
  ary = []
  each { |k,v| ary << [k,v] if yield k,v }
  ary
end

#shiftObject



308
309
310
311
# File 'lib/dm-validations/support/ordered_hash.rb', line 308

def shift
  key = order.first
  key ? [key,delete(key)] : super
end

#store(a, b) ⇒ Object



242
243
244
245
# File 'lib/dm-validations/support/ordered_hash.rb', line 242

def store( a,b )
  @order.push( a ) unless @hash.has_key?( a )
  @hash.store( a,b )
end

#to_aObject



405
406
407
408
409
# File 'lib/dm-validations/support/ordered_hash.rb', line 405

def to_a
  ary = []
  each { |k,v| ary << [k,v] }
  ary
end

#to_hObject



430
431
432
# File 'lib/dm-validations/support/ordered_hash.rb', line 430

def to_h
  @hash.dup
end

#to_hashObject



426
427
428
# File 'lib/dm-validations/support/ordered_hash.rb', line 426

def to_hash
  @hash.dup
end

#to_jsonObject



411
412
413
414
415
416
417
418
419
420
# File 'lib/dm-validations/support/ordered_hash.rb', line 411

def to_json
  buf = "["
  map do |k,v|
    buf << k.to_json
    buf << ", "
    buf << v.to_json
  end.join(", ")
  buf << "]"
  buf
end

#to_sObject



422
423
424
# File 'lib/dm-validations/support/ordered_hash.rb', line 422

def to_s
  self.to_a.to_s
end

#unshift(k, v) ⇒ Object



313
314
315
316
317
318
319
320
321
# File 'lib/dm-validations/support/ordered_hash.rb', line 313

def unshift( k,v )
  unless @hash.include?( k )
    @order.unshift( k )
    @hash.store( k,v )
    true
  else
    false
  end
end

#update(hsh2) ⇒ Object Also known as: merge!



354
355
356
357
358
# File 'lib/dm-validations/support/ordered_hash.rb', line 354

def update( hsh2 )
  hsh2.each { |k,v| self[k] = v }
  reorder
  self
end

#valuesObject



278
279
280
281
282
# File 'lib/dm-validations/support/ordered_hash.rb', line 278

def values
  ary = []
  order.each { |k| ary.push @hash[k] }
  ary
end