map 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/Rakefile +371 -0
  2. data/lib/map.rb +396 -0
  3. data/test/lib/testing.rb +68 -0
  4. data/test/map.rb +157 -0
  5. metadata +70 -0
data/Rakefile ADDED
@@ -0,0 +1,371 @@
1
+ This.rubyforge_project = 'codeforpeople'
2
+ This.author = "Ara T. Howard"
3
+ This.email = "ara.t.howard@gmail.com"
4
+ This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
5
+
6
+
7
+ task :default do
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
11
+ task :test do
12
+ run_tests!
13
+ end
14
+
15
+ namespace :test do
16
+ task(:unit){ run_tests!(:unit) }
17
+ task(:functional){ run_tests!(:functional) }
18
+ task(:integration){ run_tests!(:integration) }
19
+ end
20
+
21
+ def run_tests!(which = nil)
22
+ which ||= '**'
23
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+ helper = "-r ./test/helper.rb" if test(?e, "./test/helper.rb")
30
+
31
+ test_rbs.each_with_index do |test_rb, index|
32
+ testno = index + 1
33
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ helper } #{ test_rb }"
34
+
35
+ puts
36
+ say(div, :color => :cyan, :bold => true)
37
+ say("@#{ testno } => ", :bold => true, :method => :print)
38
+ say(command, :color => :cyan, :bold => true)
39
+ say(line, :color => :cyan, :bold => true)
40
+
41
+ system(command)
42
+
43
+ say(line, :color => :cyan, :bold => true)
44
+
45
+ status = $?.exitstatus
46
+
47
+ if status.zero?
48
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
49
+ say("SUCCESS", :color => :green, :bold => true)
50
+ else
51
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
52
+ say("FAILURE", :color => :red, :bold => true)
53
+ end
54
+ say(line, :color => :cyan, :bold => true)
55
+
56
+ exit(status) unless status.zero?
57
+ end
58
+ end
59
+
60
+
61
+ task :gemspec do
62
+ ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
63
+ ignore_directories = 'pkg'
64
+ ignore_files = 'test/log'
65
+
66
+ shiteless =
67
+ lambda do |list|
68
+ list.delete_if do |entry|
69
+ next unless test(?e, entry)
70
+ extension = File.basename(entry).split(%r/[.]/).last
71
+ ignore_extensions.any?{|ext| ext === extension}
72
+ end
73
+ list.delete_if do |entry|
74
+ next unless test(?d, entry)
75
+ dirname = File.expand_path(entry)
76
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
77
+ end
78
+ list.delete_if do |entry|
79
+ next unless test(?f, entry)
80
+ filename = File.expand_path(entry)
81
+ ignore_files.any?{|file| File.expand_path(file) == filename}
82
+ end
83
+ end
84
+
85
+ lib = This.lib
86
+ object = This.object
87
+ version = This.version
88
+ files = shiteless[Dir::glob("**/**")]
89
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
90
+ has_rdoc = true #File.exist?('doc')
91
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
92
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
93
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
94
+
95
+ if This.extensions.nil?
96
+ This.extensions = []
97
+ extensions = This.extensions
98
+ %w( Makefile configure extconf.rb ).each do |ext|
99
+ extensions << ext if File.exists?(ext)
100
+ end
101
+ end
102
+ extensions = [extensions].flatten.compact
103
+
104
+ template =
105
+ if test(?e, 'gemspec.erb')
106
+ Template{ IO.read('gemspec.erb') }
107
+ else
108
+ Template {
109
+ <<-__
110
+ ## #{ lib }.gemspec
111
+ #
112
+
113
+ Gem::Specification::new do |spec|
114
+ spec.name = #{ lib.inspect }
115
+ spec.version = #{ version.inspect }
116
+ spec.platform = Gem::Platform::RUBY
117
+ spec.summary = #{ lib.inspect }
118
+ spec.description = #{ description.inspect }
119
+
120
+ spec.files = #{ files.inspect }
121
+ spec.executables = #{ executables.inspect }
122
+
123
+ spec.require_path = "lib"
124
+
125
+ spec.has_rdoc = #{ has_rdoc.inspect }
126
+ spec.test_files = #{ test_files.inspect }
127
+ #spec.add_dependency 'lib', '>= version'
128
+ #spec.add_dependency 'fattr'
129
+
130
+ spec.extensions.push(*#{ extensions.inspect })
131
+
132
+ spec.rubyforge_project = #{ This.rubyforge_project.inspect }
133
+ spec.author = #{ This.author.inspect }
134
+ spec.email = #{ This.email.inspect }
135
+ spec.homepage = #{ This.homepage.inspect }
136
+ end
137
+ __
138
+ }
139
+ end
140
+
141
+ Fu.mkdir_p(This.pkgdir)
142
+ gemspec = File.join(This.pkgdir, "#{ lib }.gemspec")
143
+ open(gemspec, "w"){|fd| fd.puts(template)}
144
+ This.gemspec = gemspec
145
+ end
146
+
147
+ task :gem => [:clean, :gemspec] do
148
+ Fu.mkdir_p(This.pkgdir)
149
+ before = Dir['*.gem']
150
+ cmd = "gem build #{ This.gemspec }"
151
+ `#{ cmd }`
152
+ after = Dir['*.gem']
153
+ gem = ((after - before).first || after.first) or abort('no gem!')
154
+ Fu.mv(gem, This.pkgdir)
155
+ This.gem = File.join(This.pkgdir, File.basename(gem))
156
+ end
157
+
158
+ task :readme do
159
+ samples = ''
160
+ prompt = '~ > '
161
+ lib = This.lib
162
+ version = This.version
163
+
164
+ Dir['sample*/*'].sort.each do |sample|
165
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
166
+
167
+ cmd = "cat #{ sample }"
168
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
169
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
170
+
171
+ cmd = "ruby #{ sample }"
172
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
173
+
174
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
175
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
176
+ end
177
+
178
+ template =
179
+ if test(?e, 'readme.erb')
180
+ Template{ IO.read('readme.erb') }
181
+ else
182
+ Template {
183
+ <<-__
184
+ NAME
185
+ #{ lib }
186
+
187
+ DESCRIPTION
188
+
189
+ INSTALL
190
+ gem install #{ lib }
191
+
192
+ SAMPLES
193
+ #{ samples }
194
+ __
195
+ }
196
+ end
197
+
198
+ open("README", "w"){|fd| fd.puts template}
199
+ end
200
+
201
+
202
+ task :clean do
203
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
204
+ end
205
+
206
+
207
+ task :release => [:clean, :gemspec, :gem] do
208
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
209
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
210
+ raise "no gems?" if gems.size < 1
211
+
212
+ cmd = "gem push #{ This.gem }"
213
+ puts cmd
214
+ puts
215
+ system(cmd)
216
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
217
+
218
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
219
+ puts cmd
220
+ puts
221
+ system(cmd)
222
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
223
+ end
224
+
225
+
226
+
227
+
228
+
229
+ BEGIN {
230
+ # support for this rakefile
231
+ #
232
+ $VERBOSE = nil
233
+
234
+ require 'ostruct'
235
+ require 'erb'
236
+ require 'fileutils'
237
+ require 'rbconfig'
238
+
239
+ # fu shortcut
240
+ #
241
+ Fu = FileUtils
242
+
243
+ # cache a bunch of stuff about this rakefile/environment
244
+ #
245
+ This = OpenStruct.new
246
+
247
+ This.file = File.expand_path(__FILE__)
248
+ This.dir = File.dirname(This.file)
249
+ This.pkgdir = File.join(This.dir, 'pkg')
250
+
251
+ # grok lib
252
+ #
253
+ lib = ENV['LIB']
254
+ unless lib
255
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
256
+ end
257
+ This.lib = lib
258
+
259
+ # grok version
260
+ #
261
+ version = ENV['VERSION']
262
+ unless version
263
+ require "./lib/#{ This.lib }"
264
+ This.name = lib.capitalize
265
+ This.object = eval(This.name)
266
+ version = This.object.send(:version)
267
+ end
268
+ This.version = version
269
+
270
+ # we need to know the name of the lib an it's version
271
+ #
272
+ abort('no lib') unless This.lib
273
+ abort('no version') unless This.version
274
+
275
+ # discover full path to this ruby executable
276
+ #
277
+ c = Config::CONFIG
278
+ bindir = c["bindir"] || c['BINDIR']
279
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
280
+ ruby_ext = c['EXEEXT'] || ''
281
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
282
+ This.ruby = ruby
283
+
284
+ # some utils
285
+ #
286
+ module Util
287
+ def indent(s, n = 2)
288
+ s = unindent(s)
289
+ ws = ' ' * n
290
+ s.gsub(%r/^/, ws)
291
+ end
292
+
293
+ def unindent(s)
294
+ indent = nil
295
+ s.each do |line|
296
+ next if line =~ %r/^\s*$/
297
+ indent = line[%r/^\s*/] and break
298
+ end
299
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
300
+ end
301
+ extend self
302
+ end
303
+
304
+ # template support
305
+ #
306
+ class Template
307
+ def initialize(&block)
308
+ @block = block
309
+ @template = block.call.to_s
310
+ end
311
+ def expand(b=nil)
312
+ ERB.new(Util.unindent(@template)).result(b||@block)
313
+ end
314
+ alias_method 'to_s', 'expand'
315
+ end
316
+ def Template(*args, &block) Template.new(*args, &block) end
317
+
318
+ # colored console output support
319
+ #
320
+ This.ansi = {
321
+ :clear => "\e[0m",
322
+ :reset => "\e[0m",
323
+ :erase_line => "\e[K",
324
+ :erase_char => "\e[P",
325
+ :bold => "\e[1m",
326
+ :dark => "\e[2m",
327
+ :underline => "\e[4m",
328
+ :underscore => "\e[4m",
329
+ :blink => "\e[5m",
330
+ :reverse => "\e[7m",
331
+ :concealed => "\e[8m",
332
+ :black => "\e[30m",
333
+ :red => "\e[31m",
334
+ :green => "\e[32m",
335
+ :yellow => "\e[33m",
336
+ :blue => "\e[34m",
337
+ :magenta => "\e[35m",
338
+ :cyan => "\e[36m",
339
+ :white => "\e[37m",
340
+ :on_black => "\e[40m",
341
+ :on_red => "\e[41m",
342
+ :on_green => "\e[42m",
343
+ :on_yellow => "\e[43m",
344
+ :on_blue => "\e[44m",
345
+ :on_magenta => "\e[45m",
346
+ :on_cyan => "\e[46m",
347
+ :on_white => "\e[47m"
348
+ }
349
+ def say(phrase, *args)
350
+ options = args.last.is_a?(Hash) ? args.pop : {}
351
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
352
+ keys = options.keys
353
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
354
+
355
+ color = options[:color]
356
+ bold = options.has_key?(:bold)
357
+
358
+ parts = [phrase]
359
+ parts.unshift(This.ansi[color]) if color
360
+ parts.unshift(This.ansi[:bold]) if bold
361
+ parts.push(This.ansi[:clear]) if parts.size > 1
362
+
363
+ method = options[:method] || :puts
364
+
365
+ Kernel.send(method, parts.join)
366
+ end
367
+
368
+ # always run out of the project dir
369
+ #
370
+ Dir.chdir(This.dir)
371
+ }
data/lib/map.rb ADDED
@@ -0,0 +1,396 @@
1
+ class Map < Hash
2
+ Version = '0.0.1' unless defined?(Version)
3
+ Load = Kernel.method(:load) unless defined?(Load)
4
+
5
+ class << Map
6
+ def version
7
+ Map::Version
8
+ end
9
+
10
+ # class constructor
11
+ #
12
+ def new(*args, &block)
13
+ map = super(&block)
14
+
15
+ case args.size
16
+ when 0
17
+ return map
18
+
19
+ when 1
20
+ case arg = args.first
21
+ when Hash
22
+ new_from_hash(arg, map)
23
+ when Array
24
+ new_from_array(arg, map)
25
+ else
26
+ new_from_hash(arg.to_hash, map)
27
+ end
28
+
29
+ else
30
+ new_from_array(args, map)
31
+ end
32
+
33
+ map
34
+ end
35
+
36
+ def new_from_hash(hash, map = new)
37
+ map.update(hash)
38
+ map
39
+ end
40
+
41
+ def new_from_array(array, map = new)
42
+ each_pair(array){|key, val| map[key] = val}
43
+ map
44
+ end
45
+
46
+ # iterate over arguments in pairs smartly.
47
+ #
48
+ def each_pair(*args)
49
+ size = args.size
50
+ parity = size % 2 == 0 ? :even : :odd
51
+ first = args.first
52
+
53
+ return args if size == 0
54
+
55
+ if size == 1 and first.respond_to?(:each_pair)
56
+ first.each_pair do |key, val|
57
+ yield(key, val)
58
+ end
59
+ return args
60
+ end
61
+
62
+ if size == 1 and first.respond_to?(:each_slice)
63
+ first.each_slice(2) do |key, val|
64
+ yield(key, val)
65
+ end
66
+ return args
67
+ end
68
+
69
+ array_of_pairs = args.all?{|a| a.is_a?(Array) and a.size == 2}
70
+
71
+ if array_of_pairs
72
+ args.each do |pair|
73
+ key, val, *ignored = pair
74
+ yield(key, val)
75
+ end
76
+ else
77
+ 0.step(args.size - 1, 2) do |a|
78
+ key = args[a]
79
+ val = args[a + 1]
80
+ yield(key, val)
81
+ end
82
+ end
83
+
84
+ args
85
+ end
86
+
87
+ alias_method '[]', 'new'
88
+ end
89
+
90
+
91
+ # instance constructor
92
+ #
93
+ attr_accessor :keys
94
+
95
+ def initialize(*args, &block)
96
+ super
97
+ @keys = []
98
+ end
99
+
100
+ # support methods
101
+ #
102
+ def map
103
+ self
104
+ end
105
+
106
+ def map_for(hash)
107
+ map = Map.new(hash)
108
+ map.default = hash.default
109
+ map
110
+ end
111
+
112
+ def convert_key(key)
113
+ key.kind_of?(Symbol) ? key.to_s : key
114
+ end
115
+
116
+ def convert_val(val)
117
+ case val
118
+ when Hash
119
+ map_for(val)
120
+ when Array
121
+ val.collect{|v| Hash === v ? map_for(v) : v}
122
+ else
123
+ val
124
+ end
125
+ end
126
+
127
+ def convert(key, val)
128
+ [convert_key(key), convert_val(val)]
129
+ end
130
+
131
+ # maps are aggressive with copy operations. they are all deep copies. make a
132
+ # new one if you really want a shallow copy
133
+ #
134
+ def copy
135
+ default = self.default
136
+ self.default = nil
137
+ copy = Marshal.load(Marshal.dump(self))
138
+ copy.default = default
139
+ copy
140
+ ensure
141
+ self.default = default
142
+ end
143
+
144
+ def dup
145
+ copy
146
+ end
147
+
148
+ def clone
149
+ copy
150
+ end
151
+
152
+ def default(key = nil)
153
+ key.is_a?(Symbol) && include?(key = key.to_s) ? self[key] : super
154
+ end
155
+
156
+ # writer/reader methods
157
+ #
158
+ alias_method '__set__', '[]=' unless method_defined?('__set__')
159
+ alias_method '__get__', '[]' unless method_defined?('__get__')
160
+ alias_method '__update__', 'update' unless method_defined?('__update__')
161
+
162
+ def set(key, val)
163
+ key, val = convert(key, val)
164
+ @keys.push(key) unless has_key?(key)
165
+ __set__(key, val)
166
+ end
167
+ alias_method 'store', 'set'
168
+ alias_method '[]=', 'set'
169
+
170
+ def get(key)
171
+ __get__(key)
172
+ end
173
+ alias_method '[]', 'get'
174
+
175
+ def fetch(key, *args, &block)
176
+ super(convert_key(key), *args, &block)
177
+ end
178
+
179
+ def key?(key)
180
+ super(convert_key(key))
181
+ end
182
+ alias_method 'include?', 'key?'
183
+ alias_method 'has_key?', 'key?'
184
+ alias_method 'member?', 'key?'
185
+
186
+ def update(*args)
187
+ Map.each_pair(*args) do |key, val|
188
+ set(key, val)
189
+ end
190
+ self
191
+ end
192
+ alias_method 'merge!', 'update'
193
+
194
+ def merge(*args)
195
+ copy.update(*args)
196
+ end
197
+
198
+ def reverse_merge(hash)
199
+ map = copy
200
+ hash.each{|key, val| map[key] = val unless map.key?(key)}
201
+ map
202
+ end
203
+
204
+ def reverse_merge!(hash)
205
+ replace(reverse_merge(hash))
206
+ end
207
+
208
+ def values
209
+ array = []
210
+ @keys.each{|key| array.push(self[key])}
211
+ array
212
+ end
213
+ alias_method 'vals', 'values'
214
+
215
+ def values_at(*keys)
216
+ keys.map{|key| self[key]}
217
+ end
218
+
219
+ def first
220
+ [@keys.first, self[@keys.first]]
221
+ end
222
+
223
+ def last
224
+ [@keys.last, self[@keys.last]]
225
+ end
226
+
227
+ # iterator methods
228
+ #
229
+ def each_with_index
230
+ @keys.each_with_index{|key, index| yield([key, self[key]], index)}
231
+ self
232
+ end
233
+
234
+ def each_key
235
+ @keys.each{|key| yield(key)}
236
+ self
237
+ end
238
+
239
+ def each_value
240
+ @keys.each{|key| yield self[key]}
241
+ self
242
+ end
243
+
244
+ def each
245
+ @keys.each{|key| yield(key, self[key])}
246
+ self
247
+ end
248
+ alias_method 'each_pair', 'each'
249
+
250
+ # mutators
251
+ #
252
+ def delete(key)
253
+ key = convert_key(key)
254
+ @keys.delete(key)
255
+ super(key)
256
+ end
257
+
258
+ def clear
259
+ @keys = []
260
+ super
261
+ end
262
+
263
+ def delete_if
264
+ to_delete = []
265
+ @keys.each{|key| to_delete.push(key) if yield(key)}
266
+ to_delete.each{|key| delete(key)}
267
+ map
268
+ end
269
+
270
+ def replace(hash)
271
+ clear
272
+ update(hash)
273
+ end
274
+
275
+ # ordered container specific methods
276
+ #
277
+ def shift
278
+ unless empty?
279
+ key = @keys.first
280
+ val = delete(key)
281
+ [key, val]
282
+ end
283
+ end
284
+
285
+ def unshift(*args)
286
+ Map.each_pair(*args) do |key, val|
287
+ if key?(key)
288
+ delete(key)
289
+ else
290
+ @keys.unshift(key)
291
+ end
292
+ __set__(key, val)
293
+ end
294
+ self
295
+ end
296
+
297
+ def push(*args)
298
+ Map.each_pair(*args) do |key, val|
299
+ if key?(key)
300
+ delete(key)
301
+ else
302
+ @keys.push(key)
303
+ end
304
+ __set__(key, val)
305
+ end
306
+ self
307
+ end
308
+
309
+ def pop
310
+ unless empty?
311
+ key = @keys.last
312
+ val = delete(key)
313
+ [key, val]
314
+ end
315
+ end
316
+
317
+ # misc
318
+ #
319
+ def ==(hash)
320
+ return false if @keys != hash.keys
321
+ super hash
322
+ end
323
+
324
+ def invert
325
+ inverted = Map.new
326
+ inverted.default = self.default
327
+ @keys.each{|key| inverted[self[key]] = key }
328
+ inverted
329
+ end
330
+
331
+ def reject(&block)
332
+ dup.delete_if(&block)
333
+ end
334
+
335
+ def reject!(&block)
336
+ hash = reject(&block)
337
+ self == hash ? nil : hash
338
+ end
339
+
340
+ def select
341
+ array = []
342
+ each{|key, val| array << [key,val] if yield(key, val)}
343
+ array
344
+ end
345
+
346
+ def inspect
347
+ array = []
348
+ each{|key, val| array << (key.inspect + "=>" + val.inspect)}
349
+ string = '{' + array.join(", ") + '}'
350
+ end
351
+
352
+ # converions
353
+ #
354
+ def to_hash
355
+ hash = Hash.new(default)
356
+ each do |key, val|
357
+ val = val.to_hash if val.respond_to?(:to_hash)
358
+ hash[key] = val
359
+ end
360
+ hash
361
+ end
362
+
363
+ def to_yaml(*args, &block)
364
+ to_hash.to_yaml(*args, &block)
365
+ end
366
+
367
+ def to_array
368
+ array = []
369
+ each{|*pair| array.push(pair)}
370
+ array
371
+ end
372
+ alias_method 'to_a', 'to_array'
373
+
374
+ def to_s
375
+ to_array.to_s
376
+ end
377
+
378
+ def stringify_keys!; self end
379
+ def symbolize_keys!; self end
380
+ def to_options!; self end
381
+
382
+ def class
383
+ Hash
384
+ end
385
+
386
+ def __class__
387
+ Map
388
+ end
389
+ end
390
+
391
+ module Kernel
392
+ private
393
+ def Map(*args, &block)
394
+ Map.new(*args, &block)
395
+ end
396
+ end
@@ -0,0 +1,68 @@
1
+ # simple testing support
2
+ #
3
+ require 'test/unit'
4
+
5
+ def Testing(*args, &block)
6
+ Class.new(Test::Unit::TestCase) do
7
+ def self.slug_for(*args)
8
+ string = args.flatten.compact.join('-')
9
+ words = string.to_s.scan(%r/\w+/)
10
+ words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
11
+ words.delete_if{|word| word.nil? or word.strip.empty?}
12
+ words.join('-').downcase
13
+ end
14
+
15
+ @@testing_subclass_count = 0 unless defined?(@@testing_subclass_count)
16
+ @@testing_subclass_count += 1
17
+ slug = slug_for(*args).gsub(%r/-/,'_')
18
+ name = ['TESTING', '%03d' % @@testing_subclass_count, slug].delete_if{|part| part.empty?}.join('_')
19
+ name = name.upcase!
20
+ const_set(:Name, name)
21
+ def self.name() const_get(:Name) end
22
+
23
+ def self.testno()
24
+ '%05d' % (@testno ||= 0)
25
+ ensure
26
+ @testno += 1
27
+ end
28
+
29
+ def self.testing(*args, &block)
30
+ method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_')
31
+ define_method("test_#{ testno }_#{ slug_for(*args) }", &block)
32
+ end
33
+
34
+ alias_method '__assert__', 'assert'
35
+
36
+ def assert(*args, &block)
37
+ if block
38
+ label = "assert(#{ args.join ' ' })"
39
+ result = nil
40
+ assert_nothing_raised{ result = block.call }
41
+ __assert__(result, label)
42
+ result
43
+ else
44
+ result = args.shift
45
+ label = "assert(#{ args.join ' ' })"
46
+ __assert__(result, label)
47
+ result
48
+ end
49
+ end
50
+
51
+ def subclass_of exception
52
+ class << exception
53
+ def ==(other) super or self > other end
54
+ end
55
+ exception
56
+ end
57
+
58
+ alias_method '__assert_raises__', 'assert_raises'
59
+
60
+ def assert_raises(*args, &block)
61
+ args.push(subclass_of(Exception)) if args.empty?
62
+ __assert_raises__(*args, &block)
63
+ end
64
+
65
+ module_eval &block
66
+ self
67
+ end
68
+ end
data/test/map.rb ADDED
@@ -0,0 +1,157 @@
1
+ require 'testing'
2
+ require 'map'
3
+
4
+ Testing Map do
5
+ testing 'that bare constructor werks' do
6
+ assert{ Map.new }
7
+ end
8
+
9
+ testing 'that the contructor accepts a hash' do
10
+ assert{ Map.new(hash = {}) }
11
+ end
12
+
13
+ testing 'that the constructor accepts the empty array' do
14
+ array = []
15
+ assert{ Map.new(array) }
16
+ assert{ Map.new(*array) }
17
+ end
18
+
19
+ testing 'that the contructor accepts an even sized array' do
20
+ arrays = [
21
+ [ %w( k v ), %w( key val ) ],
22
+ [ %w( k v ), %w( key val ), %w( a b ) ],
23
+ [ %w( k v ), %w( key val ), %w( a b ), %w( x y ) ]
24
+ ]
25
+ arrays.each do |array|
26
+ assert{ Map.new(array) }
27
+ assert{ Map.new(*array) }
28
+ end
29
+ end
30
+
31
+ testing 'that the contructor accepts an odd sized array' do
32
+ arrays = [
33
+ [ %w( k v ) ],
34
+ [ %w( k v ), %w( key val ), %w( a b ) ]
35
+ ]
36
+ arrays.each do |array|
37
+ assert{ Map.new(array) }
38
+ assert{ Map.new(*array) }
39
+ end
40
+ end
41
+
42
+ testing 'that the constructor accepts arrays of pairs' do
43
+ arrays = [
44
+ [],
45
+ [ %w( k v ) ],
46
+ [ %w( k v ), %w( key val ) ],
47
+ [ %w( k v ), %w( key val ), %w( a b ) ]
48
+ ]
49
+ arrays.each do |array|
50
+ assert{ Map.new(array) }
51
+ assert{ Map.new(*array) }
52
+ end
53
+ end
54
+
55
+ testing 'that "[]" is a synonym for "new"' do
56
+ list = [
57
+ [],
58
+ [{}],
59
+ [[:key, :val]],
60
+ [:key, :val]
61
+ ]
62
+ list.each do |args|
63
+ map = assert{ Map[*args] }
64
+ assert{ map.is_a?(Map) }
65
+ assert{ Map.new(*args) == map }
66
+ end
67
+ end
68
+
69
+ testing 'that #each yields pairs in order' do
70
+ map = new_int_map
71
+ i = 0
72
+ map.each do |key, val|
73
+ assert{ key == i.to_s }
74
+ assert{ val == i }
75
+ i += 1
76
+ end
77
+ end
78
+
79
+ testing 'that keys and values are ordered' do
80
+ n = 2048
81
+ map = new_int_map(n)
82
+ values = Array.new(n){|i| i}
83
+ keys = values.map{|value| value.to_s}
84
+ assert{ map.keys.size == n }
85
+ assert{ map.keys == keys}
86
+ assert{ map.values == values}
87
+ end
88
+
89
+ testing 'that maps are string/symbol indifferent for simple look-ups' do
90
+ map = Map.new
91
+ map[:k] = :v
92
+ map['a'] = 'b'
93
+ assert{ map[:k] == :v }
94
+ assert{ map[:k.to_s] == :v }
95
+ assert{ map[:a] == 'b' }
96
+ assert{ map[:a.to_s] == 'b' }
97
+ end
98
+
99
+ testing 'that maps are string/symbol indifferent for recursive look-ups' do
100
+ map = Map.new
101
+ assert{ map[:a] = Map[:b, 42] }
102
+ assert{ map[:a][:b] = Map[:c, 42] }
103
+ assert{ map[:a][:b][:c] == 42 }
104
+ assert{ map['a'][:b][:c] == 42 }
105
+ assert{ map['a']['b'][:c] == 42 }
106
+ assert{ map['a']['b']['c'] == 42 }
107
+ assert{ map[:a]['b'][:c] == 42 }
108
+ assert{ map[:a]['b']['c'] == 42 }
109
+ assert{ map[:a][:b]['c'] == 42 }
110
+ assert{ map['a'][:b]['c'] == 42 }
111
+ end
112
+
113
+ testing 'that maps support shift like a good ordered container' do
114
+ map = Map.new
115
+ 10.times do |i|
116
+ key, val = i.to_s, i
117
+ assert{ map.unshift(key, val) }
118
+ assert{ map[key] == val }
119
+ assert{ map.keys.first.to_s == key.to_s}
120
+ assert{ map.values.first.to_s == val.to_s}
121
+ end
122
+
123
+ map = Map.new
124
+ args = []
125
+ 10.times do |i|
126
+ key, val = i.to_s, i
127
+ args.unshift([key, val])
128
+ end
129
+ map.unshift(*args)
130
+ 10.times do |i|
131
+ key, val = i.to_s, i
132
+ assert{ map[key] == val }
133
+ assert{ map.keys[i].to_s == key.to_s}
134
+ assert{ map.values[i].to_s == val.to_s}
135
+ end
136
+ end
137
+
138
+ protected
139
+ def new_int_map(n = 1024)
140
+ map = Map.new
141
+ n.times{|i| map[i.to_s] = i}
142
+ map
143
+ end
144
+ end
145
+
146
+
147
+
148
+
149
+ BEGIN {
150
+ testdir = File.dirname(File.expand_path(__FILE__))
151
+ testlibdir = File.join(testdir, 'lib')
152
+ rootdir = File.dirname(testdir)
153
+ libdir = File.join(rootdir, 'lib')
154
+
155
+ $LOAD_PATH.push(libdir)
156
+ $LOAD_PATH.push(testlibdir)
157
+ }
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: map
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Ara T. Howard
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-03 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "description: map kicks the ass"
23
+ email: ara.t.howard@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/map.rb
32
+ - Rakefile
33
+ - test/lib/testing.rb
34
+ - test/map.rb
35
+ has_rdoc: true
36
+ homepage: http://github.com/ahoward/map/tree/master
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project: codeforpeople
65
+ rubygems_version: 1.3.7
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: map
69
+ test_files:
70
+ - test/map.rb