map 1.4.0 → 1.5.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.
Files changed (4) hide show
  1. data/README +39 -3
  2. data/lib/map.rb +2 -1
  3. data/lib/map/options.rb +151 -0
  4. metadata +4 -6
data/README CHANGED
@@ -5,6 +5,12 @@ SYNOPSIS
5
5
  the ruby container you've always wanted: a string/symbol indifferent ordered
6
6
  hash that works in all rubies
7
7
 
8
+ maps are rad ordered hashes that are both ordered, string/symbol
9
+ indifferent, and have all sorts of sweetness like recursive convertsion,
10
+ more robust implementation than HashWithIndifferentAccess, support for
11
+ struct like (map.foo) access, and support for option/keyword access which
12
+ avoids several nasty classes of errors in many ruby libraries
13
+
8
14
  INSTALL
9
15
  gem install map
10
16
 
@@ -13,8 +19,8 @@ URI
13
19
 
14
20
  DESCRIPTION
15
21
 
16
- # maps are ordered. constructing them in an ordered fashion builds them that
17
- # way
22
+ # maps are always ordered. constructing them in an ordered fashion builds
23
+ # them that way, although the normal hash contructor is also supported
18
24
  #
19
25
  m = Map[:k, :v, :key, :val]
20
26
  m = Map(:k, :v, :key, :val)
@@ -51,5 +57,35 @@ DESCRIPTION
51
57
  s = m.struct
52
58
  p s.foo.bar #=> 42
53
59
 
60
+ # because option parsing is such a common use case for needing string/symbol
61
+ # indifference map.rb comes out of the box for option support
62
+ #
63
+ def foo(*args, &block)
64
+ opts = Map.options(args)
65
+ a = opts.getopt(:a)
66
+ b = opts.getopt(:b, :default => false)
67
+ end
68
+
69
+
70
+ opts = Map.options(:a => 42, :b => nil, :c => false)
71
+ opts.getopt(:a) #=> 42
72
+ opts.getopt(:b) #=> nil
73
+ opts.getopt(:b, :default => 42) #=> 42
74
+ opts.getopt(:c) #=> false
75
+ opts.getopt(:d, :default => false) #=> false
76
+
77
+ # this avoids such bugs as
78
+ #
79
+ options = {:read_only => true}
80
+ read_only = options[:read_only] || true # should be false but is true
81
+
82
+ # with options this becomes
83
+ #
84
+ options = Map.options(:read_only => true)
85
+ read_only = options.getopt(:read_only, :default => false) #=> true
86
+
87
+ # tons more goodness, see test/map_test.rb
88
+ #
89
+
54
90
  USAGE
55
- test/map_test.rb
91
+ again, see test/map_test.rb
data/lib/map.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Map < Hash
2
- Version = '1.4.0' unless defined?(Version)
2
+ Version = '1.5.0' unless defined?(Version)
3
3
  Load = Kernel.method(:load) unless defined?(Load)
4
4
 
5
5
  class << Map
@@ -452,3 +452,4 @@ private
452
452
  end
453
453
 
454
454
  Map.load('struct.rb')
455
+ Map.load('options.rb')
@@ -0,0 +1,151 @@
1
+ class Map
2
+ module Options
3
+ class << Options
4
+ def for(arg)
5
+ hash =
6
+ case arg
7
+ when Hash
8
+ arg
9
+ when Array
10
+ parse(arg)
11
+ when String, Symbol
12
+ {arg => true}
13
+ else
14
+ raise(ArgumentError, arg.inspect) unless arg.respond_to?(:to_hash)
15
+ arg.to_hash
16
+ end
17
+ map = Map.coerce(hash)
18
+ ensure
19
+ map.extend(Options) unless map.is_a?(Options)
20
+ end
21
+
22
+ def parse(arg)
23
+ case arg
24
+ when Array
25
+ arg.extend(Arguments) unless arg.is_a?(Arguments)
26
+ arg.options
27
+ when Hash
28
+ Options.for(arg)
29
+ else
30
+ raise(ArgumentError, "`arg` should be an Array or Hash")
31
+ end
32
+ end
33
+ end
34
+
35
+ attr_accessor :arguments
36
+
37
+ %w( to_options stringify_keys ).each do |method|
38
+ module_eval <<-__, __FILE__, __LINE__
39
+ def #{ method }() dup end
40
+ def #{ method }!() self end
41
+ __
42
+ end
43
+
44
+ def get_opt(opts, options = {})
45
+ options = Map.for(options.is_a?(Hash) ? options : {:default => options})
46
+ default = options[:default]
47
+ [ opts ].flatten.each do |opt|
48
+ return fetch(opt) if has_key?(opt)
49
+ end
50
+ default
51
+ end
52
+ alias_method('getopt', 'get_opt')
53
+
54
+ def get_opts(*opts)
55
+ opts.flatten.map{|opt| getopt(opt)}
56
+ end
57
+ alias_method('getopts', 'get_opts')
58
+
59
+ def has_opt(opts)
60
+ [ opts ].flatten.each do |opt|
61
+ return true if has_key?(opt)
62
+ end
63
+ false
64
+ end
65
+ alias_method('hasopt', 'has_opt')
66
+ alias_method('hasopt?', 'has_opt')
67
+ alias_method('has_opt?', 'has_opt')
68
+
69
+ def has_opts(*opts)
70
+ opts.flatten.all?{|opt| hasopt(opt)}
71
+ end
72
+ alias_method('hasopts?', 'has_opts')
73
+ alias_method('has_opts?', 'has_opts')
74
+
75
+ def del_opt(opts)
76
+ [ opts ].flatten.each do |opt|
77
+ return delete(opt) if has_key?(opt)
78
+ end
79
+ nil
80
+ end
81
+ alias_method('delopt', 'del_opt')
82
+
83
+ def del_opts(*opts)
84
+ opts.flatten.map{|opt| delopt(opt)}
85
+ opts
86
+ end
87
+ alias_method('delopts', 'del_opts')
88
+ alias_method('delopts!', 'del_opts')
89
+
90
+ def set_opt(opts, value = nil)
91
+ [ opts ].flatten.each do |opt|
92
+ return self[opt]=value
93
+ end
94
+ return value
95
+ end
96
+ alias_method('setopt', 'set_opt')
97
+ alias_method('setopt!', 'set_opt')
98
+
99
+ def set_opts(opts)
100
+ opts.each{|key, value| setopt(key, value)}
101
+ opts
102
+ end
103
+ alias_method('setopts', 'set_opts')
104
+ alias_method('setopts!', 'set_opts')
105
+
106
+ def pop
107
+ pop! unless popped?
108
+ self
109
+ end
110
+
111
+ def popped?
112
+ defined?(@popped) and @popped
113
+ end
114
+
115
+ def pop!
116
+ if arguments.last.is_a?(Hash)
117
+ @popped = arguments.pop
118
+ else
119
+ @popped = true
120
+ end
121
+ end
122
+ end
123
+
124
+ module Arguments
125
+ def options
126
+ @options ||= Options.for(last.is_a?(Hash) ? last : {})
127
+ ensure
128
+ @options.arguments = self
129
+ end
130
+
131
+ class << Arguments
132
+ def for(args)
133
+ args.extend(Arguments) unless args.is_a?(Arguments)
134
+ args
135
+ end
136
+
137
+ def parse(args)
138
+ [args, Options.parse(args)]
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+
145
+ def Map.options(*args, &block)
146
+ Map::Options.for(*args, &block)
147
+ end
148
+
149
+ def Map.opts(*args, &block)
150
+ Map::Options.for(*args, &block)
151
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: map
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
- - 4
7
+ - 5
9
8
  - 0
10
- version: 1.4.0
9
+ version: 1.5.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Ara T. Howard
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-10-21 00:00:00 -06:00
17
+ date: 2010-10-28 00:00:00 -06:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
@@ -29,6 +28,7 @@ extra_rdoc_files: []
29
28
 
30
29
  files:
31
30
  - a.rb
31
+ - lib/map/options.rb
32
32
  - lib/map/struct.rb
33
33
  - lib/map.rb
34
34
  - Rakefile
@@ -50,7 +50,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- hash: 3
54
53
  segments:
55
54
  - 0
56
55
  version: "0"
@@ -59,7 +58,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
58
  requirements:
60
59
  - - ">="
61
60
  - !ruby/object:Gem::Version
62
- hash: 3
63
61
  segments:
64
62
  - 0
65
63
  version: "0"