map 4.2.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ same as ruby's
data/README CHANGED
@@ -139,3 +139,7 @@ DESCRIPTION
139
139
 
140
140
  USAGE
141
141
  see lib/map.rb and test/map_test.rb
142
+
143
+ HISTORY
144
+ 4.3.0:
145
+ - support for dot keys. map.set('a.b.c' => 42) #=> {'a'=>{'b'=>{'c'=>42}}}
data/Rakefile CHANGED
@@ -3,6 +3,9 @@ This.author = "Ara T. Howard"
3
3
  This.email = "ara.t.howard@gmail.com"
4
4
  This.homepage = "https://github.com/ahoward/#{ This.lib }"
5
5
 
6
+ task :license do
7
+ open('LICENSE', 'w'){|fd| fd.puts "same as ruby's"}
8
+ end
6
9
 
7
10
  task :default do
8
11
  puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
@@ -26,11 +29,10 @@ def run_tests!(which = nil)
26
29
 
27
30
  div = ('=' * 119)
28
31
  line = ('-' * 119)
29
- helper = "-r ./test/helper.rb" if test(?e, "./test/helper.rb")
30
32
 
31
33
  test_rbs.each_with_index do |test_rb, index|
32
34
  testno = index + 1
33
- command = "#{ This.ruby } -I ./lib -I ./test/lib #{ helper } #{ test_rb }"
35
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
34
36
 
35
37
  puts
36
38
  say(div, :color => :cyan, :bold => true)
data/a.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'map'
2
+
3
+ m = Map.new
4
+
5
+ m.default = []
6
+
7
+ m.get(:a, :b)
data/lib/map.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Map < Hash
2
- Version = '4.2.0' unless defined?(Version)
2
+ Version = '4.3.0' unless defined?(Version)
3
3
  Load = Kernel.method(:load) unless defined?(Load)
4
4
 
5
5
  class << Map
@@ -184,6 +184,8 @@ class Map < Hash
184
184
  when 1
185
185
  first = args.first
186
186
  case first
187
+ when nil, false
188
+ nil
187
189
  when Hash
188
190
  initialize_from_hash(first)
189
191
  when Array
@@ -227,9 +229,16 @@ class Map < Hash
227
229
  klass.map_for(hash)
228
230
  end
229
231
 
232
+ =begin
230
233
  def self.convert_key(key)
231
234
  key.kind_of?(Symbol) ? key.to_s : key
232
235
  end
236
+ =end
237
+
238
+ def self.convert_key(key)
239
+ key = key.kind_of?(Symbol) ? key.to_s : key
240
+ end
241
+
233
242
  def convert_key(key)
234
243
  if klass.respond_to?(:convert_key)
235
244
  klass.convert_key(key)
@@ -312,11 +321,13 @@ class Map < Hash
312
321
  alias_method 'store', '[]='
313
322
 
314
323
  def [](key)
315
- __get__(convert_key(key))
324
+ key = convert_key(key)
325
+ __get__(key)
316
326
  end
317
327
 
318
328
  def fetch(key, *args, &block)
319
- super(convert_key(key), *args, &block)
329
+ key = convert_key(key)
330
+ super(key, *args, &block)
320
331
  end
321
332
 
322
333
  def key?(key)
@@ -553,19 +564,11 @@ class Map < Hash
553
564
  hash
554
565
  end
555
566
 
556
- def as_hash
557
- @class = Hash
558
- yield
559
- ensure
560
- @class = nil
561
- end
562
-
563
- def class
564
- @class || super
565
- end
566
-
567
- def to_yaml(*args, &block)
568
- as_hash{ super }
567
+ def to_yaml( opts = {} )
568
+ map = self
569
+ YAML.quick_emit(self.object_id, opts){|out|
570
+ out.map('!omap'){|m| map.each{|k,v| m.add(k, v)}}
571
+ }
569
572
  end
570
573
 
571
574
  def to_array
@@ -625,8 +628,14 @@ class Map < Hash
625
628
  # support for compound key indexing and depth first iteration
626
629
  #
627
630
  def get(*keys)
628
- keys = keys.flatten
629
- return self[keys.first] if keys.size <= 1
631
+ keys = key_for(keys)
632
+ if keys.size <= 1
633
+ if !self.has_key?(keys.first) && block_given?
634
+ return yield
635
+ else
636
+ return self[keys.first]
637
+ end
638
+ end
630
639
  keys, key = keys[0..-2], keys[-1]
631
640
  collection = self
632
641
  keys.each do |k|
@@ -634,11 +643,17 @@ class Map < Hash
634
643
  collection = collection[k]
635
644
  return collection unless collection.respond_to?('[]')
636
645
  end
637
- collection[alphanumeric_key_for(key)]
646
+ alphanumeric_key = alphanumeric_key_for(key)
647
+
648
+ if !collection_has_key?(collection, alphanumeric_key) && block_given?
649
+ yield
650
+ else
651
+ collection[alphanumeric_key]
652
+ end
638
653
  end
639
654
 
640
655
  def has?(*keys)
641
- keys = keys.flatten
656
+ keys = key_for(keys)
642
657
  collection = self
643
658
  return collection_has_key?(collection, keys.first) if keys.size <= 1
644
659
  keys, key = keys[0..-2], keys[-1]
@@ -695,6 +710,9 @@ class Map < Hash
695
710
  keys = Array(keys).flatten
696
711
 
697
712
  collection = self
713
+
714
+ keys = key_for(keys)
715
+
698
716
  if keys.size <= 1
699
717
  key = keys.first
700
718
  collection[key] = value
@@ -789,6 +807,51 @@ class Map < Hash
789
807
  Map.alphanumeric_key_for(key)
790
808
  end
791
809
 
810
+ ## key path support
811
+ #
812
+ def self.dot_key_for(*keys)
813
+ dot = keys.compact.flatten.join('.')
814
+ dot.split(%r/\s*[,.:_-]\s*/).map{|part| part =~ %r/^\d+$/ ? Integer(part) : part}
815
+ end
816
+
817
+ def self.dot_keys
818
+ @@dot_keys = {} unless defined?(@@dot_keys)
819
+ @@dot_keys
820
+ end
821
+
822
+ def self.dot_keys?
823
+ ancestors.each do |ancestor|
824
+ return dot_keys[ancestor] if dot_keys.has_key?(ancestor)
825
+ end
826
+ false
827
+ end
828
+
829
+ def dot_keys?
830
+ @dot_keys = false unless defined?(@dot_keys)
831
+ @dot_keys
832
+ end
833
+
834
+ def self.dot_keys!(boolean = true)
835
+ dot_keys[self] = !!boolean
836
+ end
837
+
838
+ def dot_keys!(boolean = true)
839
+ @dot_keys = !!boolean
840
+ end
841
+
842
+ def self.key_for(*keys)
843
+ return keys.flatten unless dot_keys?
844
+ self.dot_key_for(*keys)
845
+ end
846
+
847
+ def key_for(*keys)
848
+ if dot_keys?
849
+ self.class.dot_key_for(*keys)
850
+ else
851
+ self.class.key_for(*keys)
852
+ end
853
+ end
854
+
792
855
  ## TODO - technically this returns only leaves so the name isn't *quite* right. re-factor for 3.0
793
856
  #
794
857
  def Map.depth_first_each(enumerable, path = [], accum = [], &block)
@@ -3,15 +3,17 @@
3
3
 
4
4
  Gem::Specification::new do |spec|
5
5
  spec.name = "map"
6
- spec.version = "4.2.0"
6
+ spec.version = "4.3.0"
7
7
  spec.platform = Gem::Platform::RUBY
8
8
  spec.summary = "map"
9
9
  spec.description = "description: map kicks the ass"
10
10
 
11
11
  spec.files =
12
- ["README",
12
+ ["LICENSE",
13
+ "README",
13
14
  "Rakefile",
14
15
  "TODO",
16
+ "a.rb",
15
17
  "lib",
16
18
  "lib/map",
17
19
  "lib/map.rb",
@@ -6,7 +6,7 @@
6
6
  Class.new(Test::Unit::TestCase) do
7
7
  eval("This=self")
8
8
 
9
- def This.slug_for(*args)
9
+ def self.slug_for(*args)
10
10
  string = args.flatten.compact.join('-')
11
11
  words = string.to_s.scan(%r/\w+/)
12
12
  words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
@@ -24,6 +24,11 @@ Testing Map do
24
24
  assert{ Map.new(*array) }
25
25
  end
26
26
 
27
+ testing 'that the constructor does not die when passed nil or false' do
28
+ assert{ Map.new(nil) }
29
+ assert{ Map.new(false) }
30
+ end
31
+
27
32
  testing 'that the contructor accepts an even sized array' do
28
33
  arrays = [
29
34
  [ %w( k v ), %w( key val ) ],
@@ -327,6 +332,35 @@ Testing Map do
327
332
  assert{ m[:x][:y][:z] == 42.0 }
328
333
  end
329
334
 
335
+ testing 'that maps can support compound key/val setting via key.dot notation' do
336
+ m = Class.new(Map){ dot_keys! }.new
337
+ assert{ m.set('a.b.c', 42) }
338
+ assert{ m[:a][:b][:c] == 42 }
339
+ assert{ m.get('a.b.c') == 42 }
340
+ assert{ m.set('x.y.z' => 42.0, 'A.2' => 'forty-two') }
341
+ assert{ m[:A].is_a?(Array) }
342
+ assert{ m[:A].size == 3}
343
+ assert{ m[:A][2] == 'forty-two' }
344
+ assert{ m[:x][:y].is_a?(Hash) }
345
+ assert{ m[:x][:y][:z] == 42.0 }
346
+ assert{ m.has?('a.b.c') }
347
+ assert{ m.has?('x.y.z') }
348
+ assert{ m.has?('A.2') }
349
+ end
350
+
351
+ testing 'that Map#get supports providing a default value in a block' do
352
+ m = Map.new
353
+ m.set(:a, :b, :c, 42)
354
+ m.set(:z, 1)
355
+
356
+ assert { m.get(:x) {1} == 1 }
357
+ assert { m.get(:z) {2} == 1 }
358
+ assert { m.get(:a, :b, :d) {1} == 1 }
359
+ assert { m.get(:a, :b, :c) {1} == 42 }
360
+ assert { m.get(:a, :b) {1} == Map.new({:c => 42}) }
361
+ assert { m.get(:a, :aa) {1} == 1 }
362
+ end
363
+
330
364
  testing 'that setting a sub-container does not eff up the container values' do
331
365
  m = Map.new
332
366
  assert{ m.set(:array => [0,1,2]) }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: map
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 4
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 4.2.0
10
+ version: 4.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ara T. Howard
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-08 00:00:00 -06:00
18
+ date: 2011-08-17 00:00:00 -06:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -28,9 +28,11 @@ extensions: []
28
28
  extra_rdoc_files: []
29
29
 
30
30
  files:
31
+ - LICENSE
31
32
  - README
32
33
  - Rakefile
33
34
  - TODO
35
+ - a.rb
34
36
  - lib/map.rb
35
37
  - lib/map/options.rb
36
38
  - lib/map/struct.rb