map 6.6.0 → 8.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6943612f809404a5d3045cefd7c293970fc2926053bef6b86c732f984eb10fee
4
+ data.tar.gz: b3c701393f2d1064897b3f9b26da0314d15e9131e26d16027bbf84f92b2039d8
5
+ SHA512:
6
+ metadata.gz: a1b125e4b5bc8cbdd56c059dd5f34421701989503ff435535d032eca5bff4239dd9faea22597e9dd5209bd5db02348a3288a91a7c4a2d68e67dbec26f20d2904
7
+ data.tar.gz: 46037e4bc03b517dff6ddb936784b7400c403977391b87911fc6481482d6049fe2fafefb29331a25026ddfa739fa05df804fe820243ea47ada4cee8045bc2725
data/LICENSE CHANGED
@@ -1 +1 @@
1
- same as ruby's
1
+ Ruby
data/README.md ADDED
@@ -0,0 +1,268 @@
1
+ NAME
2
+ ----
3
+ map.rb
4
+
5
+
6
+ LOGO
7
+ ----
8
+ ![weed whacking giraffe]('https://github.com/ahoward/map/blob/master/images/map.png')
9
+
10
+
11
+ SYNOPSIS
12
+ --------
13
+ the awesome ruby container you've always wanted: a string/symbol indifferent
14
+ ordered hash that works in all rubies.
15
+
16
+ maps are bitchin ordered hashes that are both ordered, string/symbol
17
+ indifferent, and have all sorts of sweetness like recursive conversion, more
18
+ robust, not to mention dependency-less, implementation than
19
+ HashWithIndifferentAccess.
20
+
21
+ bestiest of all, maps support some very powerful tree-like iterators that
22
+ make working with structured data, like json, insanely simple.
23
+
24
+ map.rb has been in production usage for 14 years and is commensurately
25
+ hardened. if you process json, you will love map.rb
26
+
27
+
28
+ INSTALL
29
+ -------
30
+ gem install map
31
+
32
+
33
+ URI
34
+ ---
35
+ http://github.com/ahoward/map
36
+
37
+
38
+ DESCRIPTION
39
+ -----------
40
+
41
+ > maps are always ordered. constructing them in an ordered fashion builds
42
+ > them that way, although the normal hash contructor is also supported
43
+ >
44
+ ```ruby
45
+
46
+ m = Map[:k, :v, :key, :val]
47
+ m = Map(:k, :v, :key, :val)
48
+ m = Map.new(:k, :v, :key, :val)
49
+
50
+ m = Map[[:k, :v], [:key, :val]]
51
+ m = Map(:k => :v, :key => :val) # ruh-oh, the input hash loses order!
52
+ m = Map.new(:k => :v, :key => :val) # ruh-oh, the input hash loses order!
53
+
54
+ m = Map.new
55
+ m[:a] = 0
56
+ m[:b] = 1
57
+ m[:c] = 2
58
+
59
+ p m.keys #=> ['a','b','c'] ### always ordered!
60
+ p m.values #=> [0,1,2] ### always ordered!
61
+
62
+ ```
63
+
64
+ > maps don't care about symbol vs.string keys
65
+ >
66
+ ```ruby
67
+
68
+ p m[:a] #=> 0
69
+ p m["a"] #=> 0
70
+
71
+ ```
72
+
73
+ > even via deep nesting
74
+ >
75
+ ```ruby
76
+
77
+ p m[:foo]['bar'][:baz] #=> 42
78
+
79
+ ```
80
+
81
+ > many functions operate in a way one would expect from an ordered container
82
+ >
83
+ ```ruby
84
+
85
+ m.update(:k2 => :v2)
86
+ m.update(:k2, :v2)
87
+
88
+ key_val_pair = m.shift
89
+ key_val_pair = m.pop
90
+
91
+ ```
92
+
93
+ > maps keep mapiness for even deep operations
94
+ >
95
+ ```ruby
96
+
97
+ m.update :nested => {:hashes => {:are => :converted}}
98
+
99
+ ```
100
+
101
+ > maps can give back clever little struct objects
102
+ >
103
+ ```ruby
104
+
105
+ m = Map(:foo => {:bar => 42})
106
+ s = m.struct
107
+ p s.foo.bar #=> 42
108
+
109
+ ```
110
+
111
+ > because option parsing is such a common use case for needing string/symbol
112
+ > indifference map.rb comes out of the box loaded with option support
113
+ >
114
+ ```ruby
115
+
116
+ def foo(*args, &block)
117
+ opts = Map.options(args)
118
+ a = opts.getopt(:a)
119
+ b = opts.getopt(:b, :default => false)
120
+ end
121
+
122
+
123
+ opts = Map.options(:a => 42, :b => nil, :c => false)
124
+ opts.getopt(:a) #=> 42
125
+ opts.getopt(:b) #=> nil
126
+ opts.getopt(:b, :default => 42) #=> 42
127
+ opts.getopt(:c) #=> false
128
+ opts.getopt(:d, :default => false) #=> false
129
+
130
+ ```
131
+
132
+ > this avoids such bugs as
133
+ >
134
+ ```ruby
135
+
136
+ options = {:read_only => false}
137
+ read_only = options[:read_only] || true # should be false but is true
138
+
139
+ ```
140
+
141
+ > with options this becomes
142
+ >
143
+ ```ruby
144
+
145
+ options = Map.options(:read_only => true)
146
+ read_only = options.getopt(:read_only, :default => false) #=> true
147
+
148
+ ```
149
+
150
+ > maps support some really nice operators that hashes/orderedhashes do not
151
+ >
152
+ ```ruby
153
+
154
+ m = Map.new
155
+ m.set(:h, :a, 0, 42)
156
+ m.has?(:h, :a) #=> true
157
+ p m #=> {'h' => {'a' => [42]}}
158
+ m.set(:h, :a, 1, 42.0)
159
+ p m #=> {'h' => {'a' => [42, 42.0]}}
160
+
161
+ m.get(:h, :a, 1) #=> 42.0
162
+ m.get(:x, :y, :z) #=> nil
163
+ m[:x][:y][:z] #=> raises exception!
164
+
165
+ m = Map.new(:array => [0,1])
166
+ defaults = {:array => [nil, nil, 2]}
167
+ m.apply(defaults)
168
+ p m[:array] #=> [0,1,2]
169
+
170
+ ```
171
+
172
+ > they also support some *powerful* tree-ish iteration styles
173
+ >
174
+ ```ruby
175
+
176
+ m = Map.new
177
+
178
+ m.set(
179
+ [:a, :b, :c, 0] => 0,
180
+ [:a, :b, :c, 1] => 10,
181
+ [:a, :b, :c, 2] => 20,
182
+ [:a, :b, :c, 3] => 30
183
+ )
184
+
185
+ m.set(:x, :y, 42)
186
+ m.set(:x, :z, 42.0)
187
+
188
+ m.depth_first_each do |key, val|
189
+ p key => val
190
+ end
191
+
192
+ #=> [:a, :b, :c, 0] => 0
193
+ #=> [:a, :b, :c, 1] => 10
194
+ #=> [:a, :b, :c, 2] => 20
195
+ #=> [:a, :b, :c, 3] => 30
196
+ #=> [:x, :y] => 42
197
+ #=> [:x, :z] => 42.0
198
+
199
+ ```
200
+
201
+
202
+ TESTING
203
+ -------
204
+
205
+ map.rb supports two ordering implementations:
206
+
207
+ 1. **Ruby 1.9+**: Uses native Hash ordering (memory optimized, no @keys array)
208
+ 2. **Ruby < 1.9**: Uses Map::Ordering module with explicit @keys array
209
+
210
+ ### Testing Both Code Paths
211
+
212
+ The `MAP_FORCE_ORDERING=1` environment variable forces inclusion of the Map::Ordering
213
+ module **on Ruby >= 1.9 only**, allowing you to test the legacy ordering code path on
214
+ modern Ruby versions. (On Ruby < 1.9, the module is always included regardless of this
215
+ setting, since it's required for Hash ordering.)
216
+
217
+ ```sh
218
+ # Test with native Hash ordering (Ruby 1.9+ default)
219
+ rake test
220
+ rake test:without_ordering
221
+
222
+ # Test with Map::Ordering module (simulates Ruby < 1.9)
223
+ MAP_FORCE_ORDERING=1 rake test
224
+ rake test:with_ordering
225
+
226
+ # Quick verification of both modes
227
+ ruby test/verify_ordering.rb
228
+ MAP_FORCE_ORDERING=1 ruby test/verify_ordering.rb
229
+ ```
230
+
231
+ Both modes pass the same 56 tests with 4940 assertions, proving functional equivalence.
232
+
233
+ ### Testing Across Ruby Versions
234
+
235
+ **Quick validation (RECOMMENDED):**
236
+
237
+ ```sh
238
+ # Test both code paths on your current Ruby
239
+ ./test_hash_ordering.sh
240
+
241
+ # Summary output shows:
242
+ # - Native mode: no @keys (optimized)
243
+ # - Forced mode: has @keys (simulates Ruby < 1.9)
244
+ # - Both: 56 tests, 4940 assertions pass
245
+ ```
246
+
247
+ **Test across multiple Ruby versions:**
248
+
249
+ ```sh
250
+ # Test all installed Ruby versions automatically
251
+ ./test_all_rubies.sh
252
+
253
+ # Or manually test with specific Ruby versions
254
+ RBENV_VERSION=3.2.8 ./test_hash_ordering.sh
255
+ RBENV_VERSION=3.3.4 rake test
256
+ RBENV_VERSION=3.3.4 MAP_FORCE_ORDERING=1 rake test
257
+ ```
258
+
259
+ **Note**: Old Ruby Docker images (< 2.0) are no longer available. Use `MAP_FORCE_ORDERING=1`
260
+ to test the Ruby < 1.9 code path on modern Ruby - it uses the exact same `Map::Ordering`
261
+ module with the same `@keys` array logic and behavior.
262
+
263
+ **CI/CD testing:**
264
+
265
+ The `.github/workflows/test.yml` workflow automatically tests across Ruby 2.7, 3.0,
266
+ 3.1, 3.2, 3.3, and head on every push and pull request, running both with and without
267
+ the ordering module.
268
+
data/Rakefile CHANGED
@@ -1,10 +1,11 @@
1
- This.rubyforge_project = 'codeforpeople'
2
1
  This.author = "Ara T. Howard"
3
2
  This.email = "ara.t.howard@gmail.com"
4
- This.homepage = "https://github.com/ahoward/#{ This.lib }"
3
+ This.github = "ahoward"
4
+ This.homepage = "https://github.com/#{ This.github }/#{ This.basename }"
5
+ This.repo = "https://github.com/#{ This.github }/#{ This.basename }"
5
6
 
6
7
  task :license do
7
- open('LICENSE', 'w'){|fd| fd.puts "same as ruby's"}
8
+ open('LICENSE', 'w'){|fd| fd.puts "Ruby"}
8
9
  end
9
10
 
10
11
  task :default do
@@ -19,6 +20,24 @@ namespace :test do
19
20
  task(:unit){ run_tests!(:unit) }
20
21
  task(:functional){ run_tests!(:functional) }
21
22
  task(:integration){ run_tests!(:integration) }
23
+
24
+ # Test with Map::Ordering module forced (simulates Ruby < 1.9)
25
+ task(:with_ordering) do
26
+ ENV['MAP_FORCE_ORDERING'] = '1'
27
+ puts "\n#{ '=' * 60 }"
28
+ puts "Running tests WITH Map::Ordering module (MAP_FORCE_ORDERING=1)"
29
+ puts "#{ '=' * 60 }\n\n"
30
+ run_tests!
31
+ end
32
+
33
+ # Test without Map::Ordering module (Ruby 1.9+ native Hash ordering)
34
+ task(:without_ordering) do
35
+ ENV.delete('MAP_FORCE_ORDERING')
36
+ puts "\n#{ '=' * 60 }"
37
+ puts "Running tests WITHOUT Map::Ordering module (Ruby 1.9+ mode)"
38
+ puts "#{ '=' * 60 }\n\n"
39
+ run_tests!
40
+ end
22
41
  end
23
42
 
24
43
  def run_tests!(which = nil)
@@ -72,11 +91,13 @@ task :gemspec do
72
91
  extension = File.basename(entry).split(%r/[.]/).last
73
92
  ignore_extensions.any?{|ext| ext === extension}
74
93
  end
94
+
75
95
  list.delete_if do |entry|
76
96
  next unless test(?d, entry)
77
97
  dirname = File.expand_path(entry)
78
98
  ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
79
99
  end
100
+
80
101
  list.delete_if do |entry|
81
102
  next unless test(?f, entry)
82
103
  filename = File.expand_path(entry)
@@ -84,22 +105,20 @@ task :gemspec do
84
105
  end
85
106
  end
86
107
 
87
- lib = This.lib
108
+ name = This.basename
88
109
  object = This.object
89
110
  version = This.version
90
111
  files = shiteless[Dir::glob("**/**")]
91
112
  executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
92
- #has_rdoc = true #File.exist?('doc')
93
- test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
94
- summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
95
- description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
96
- license = object.respond_to?(:license) ? object.license : "same as ruby's"
113
+ summary = Util.unindent(This.summary).strip
114
+ description = Util.unindent(This.description).strip
115
+ license = This.license.strip
97
116
 
98
117
  if This.extensions.nil?
99
118
  This.extensions = []
100
119
  extensions = This.extensions
101
120
  %w( Makefile configure extconf.rb ).each do |ext|
102
- extensions << ext if File.exists?(ext)
121
+ extensions << ext if File.exist?(ext)
103
122
  end
104
123
  end
105
124
  extensions = [extensions].flatten.compact
@@ -121,14 +140,15 @@ task :gemspec do
121
140
  else
122
141
  Template {
123
142
  <<-__
124
- ## <%= lib %>.gemspec
143
+ ## <%= name %>.gemspec
125
144
  #
126
145
 
127
146
  Gem::Specification::new do |spec|
128
- spec.name = <%= lib.inspect %>
147
+ spec.name = <%= name.inspect %>
129
148
  spec.version = <%= version.inspect %>
149
+ spec.required_ruby_version = '>= 3.0'
130
150
  spec.platform = Gem::Platform::RUBY
131
- spec.summary = <%= lib.inspect %>
151
+ spec.summary = <%= summary.inspect %>
132
152
  spec.description = <%= description.inspect %>
133
153
  spec.license = <%= license.inspect %>
134
154
 
@@ -137,15 +157,12 @@ task :gemspec do
137
157
 
138
158
  spec.require_path = "lib"
139
159
 
140
- spec.test_files = <%= test_files.inspect %>
141
-
142
160
  <% dependencies.each do |lib_version| %>
143
161
  spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
144
162
  <% end %>
145
163
 
146
164
  spec.extensions.push(*<%= extensions.inspect %>)
147
165
 
148
- spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
149
166
  spec.author = <%= This.author.inspect %>
150
167
  spec.email = <%= This.email.inspect %>
151
168
  spec.homepage = <%= This.homepage.inspect %>
@@ -155,7 +172,7 @@ task :gemspec do
155
172
  end
156
173
 
157
174
  Fu.mkdir_p(This.pkgdir)
158
- gemspec = "#{ lib }.gemspec"
175
+ gemspec = "#{ name }.gemspec"
159
176
  open(gemspec, "w"){|fd| fd.puts(template)}
160
177
  This.gemspec = gemspec
161
178
  end
@@ -171,28 +188,49 @@ task :gem => [:clean, :gemspec] do
171
188
  This.gem = File.join(This.pkgdir, File.basename(gem))
172
189
  end
173
190
 
191
+ task :README => [:readme]
192
+
174
193
  task :readme do
175
194
  samples = ''
176
195
  prompt = '~ > '
177
196
  lib = This.lib
178
197
  version = This.version
179
198
 
180
- Dir['sample*/*'].sort.each do |sample|
181
- samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
199
+ Dir['sample*/**/**.rb'].sort.each do |sample|
200
+ link = "[#{ sample }](#{ This.repo }/blob/main/#{ sample })"
201
+ samples << " #### <========< #{ link } >========>\n"
182
202
 
183
203
  cmd = "cat #{ sample }"
184
- samples << Util.indent(prompt + cmd, 2) << "\n\n"
185
- samples << Util.indent(`#{ cmd }`, 4) << "\n"
204
+ samples << "```sh\n"
205
+ samples << Util.indent(prompt + cmd, 2) << "\n"
206
+ samples << "```\n"
207
+ samples << "```ruby\n"
208
+ samples << Util.indent(IO.binread(sample), 4) << "\n"
209
+ samples << "```\n"
210
+
211
+ samples << "\n"
186
212
 
187
213
  cmd = "ruby #{ sample }"
188
- samples << Util.indent(prompt + cmd, 2) << "\n\n"
214
+ samples << "```sh\n"
215
+ samples << Util.indent(prompt + cmd, 2) << "\n"
216
+ samples << "```\n"
189
217
 
190
218
  cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
191
- samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
219
+ oe = `#{ cmd } 2>&1`
220
+ samples << "```txt\n"
221
+ samples << Util.indent(oe, 4) << "\n"
222
+ samples << "```\n"
223
+
224
+ samples << "\n"
192
225
  end
193
226
 
227
+ This.samples = samples
228
+
194
229
  template =
195
- if test(?e, 'README.erb')
230
+ case
231
+ when test(?e, 'README.md.erb')
232
+ Template{ IO.read('README.md.erb') }
233
+ when test(?e, 'README.erb')
196
234
  Template{ IO.read('README.erb') }
197
235
  else
198
236
  Template {
@@ -211,31 +249,23 @@ task :readme do
211
249
  }
212
250
  end
213
251
 
214
- open("README", "w"){|fd| fd.puts template}
252
+ IO.binwrite('README.md', template)
215
253
  end
216
254
 
217
-
218
255
  task :clean do
219
256
  Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
220
257
  end
221
258
 
222
-
223
- task :release => [:clean, :gemspec, :gem] do
259
+ task :release => [:dist, :gem] do
224
260
  gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
225
- raise "which one? : #{ gems.inspect }" if gems.size > 1
226
- raise "no gems?" if gems.size < 1
261
+ abort "which one? : #{ gems.inspect }" if gems.size > 1
262
+ abort "no gems?" if gems.size < 1
227
263
 
228
264
  cmd = "gem push #{ This.gem }"
229
265
  puts cmd
230
266
  puts
231
267
  system(cmd)
232
268
  abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
233
-
234
- cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
235
- puts cmd
236
- puts
237
- system(cmd)
238
- abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
239
269
  end
240
270
 
241
271
 
@@ -253,58 +283,66 @@ BEGIN {
253
283
  require 'rbconfig'
254
284
  require 'pp'
255
285
 
256
- # fu shortcut
286
+ # fu shortcut!
257
287
  #
258
288
  Fu = FileUtils
259
289
 
260
- # cache a bunch of stuff about this rakefile/environment
290
+ # guess a bunch of stuff about this rakefile/environment based on the
261
291
  #
262
292
  This = OpenStruct.new
263
293
 
264
294
  This.file = File.expand_path(__FILE__)
265
295
  This.dir = File.dirname(This.file)
266
296
  This.pkgdir = File.join(This.dir, 'pkg')
297
+ This.basename = File.basename(This.dir)
267
298
 
268
- # grok lib
299
+ # load actual shit _lib
269
300
  #
270
- lib = ENV['LIB']
271
- unless lib
272
- lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
273
- end
274
- This.lib = lib
301
+ _libpath = ["./lib/#{ This.basename }/_lib.rb", "./lib/#{ This.basename }.rb"]
302
+ _lib = _libpath.detect{|l| test(?s, l)}
275
303
 
276
- # grok version
277
- #
278
- version = ENV['VERSION']
279
- unless version
280
- require "./lib/#{ This.lib }"
281
- This.name = lib.capitalize
282
- This.object = eval(This.name)
283
- version = This.object.send(:version)
284
- end
285
- This.version = version
304
+ abort "could not find a _lib in ./lib/ via #{ _libpath.join(':') }" unless _lib
305
+
306
+ This._lib = _lib
307
+ require This._lib
286
308
 
287
- # see if dependencies are export by the module
309
+ # extract the name from the _lib
288
310
  #
289
- if This.object.respond_to?(:dependencies)
290
- This.dependencies = This.object.dependencies
311
+ lines = IO.binread(This._lib).split("\n")
312
+ re = %r`\A \s* (module|class) \s+ ([^\s]+) \s* \z`iomx
313
+ name = nil
314
+ lines.each do |line|
315
+ match = line.match(re)
316
+ if match
317
+ name = match.to_a.last
318
+ break
319
+ end
291
320
  end
321
+ unless name
322
+ abort "could not extract `name` from #{ This._lib }"
323
+ end
324
+ This.name = name
325
+ This.basename = This.name.downcase
292
326
 
293
- # we need to know the name of the lib an it's version
327
+ # now, fully grok This
294
328
  #
295
- abort('no lib') unless This.lib
296
- abort('no version') unless This.version
329
+ This.object = eval(This.name)
330
+ This.version = This.object.version
331
+ This.dependencies = This.object.dependencies
332
+ This.summary = This.object.summary
333
+ This.description = This.object.respond_to?(:description) ? This.object.description : This.summary
334
+ This.license = This.object.respond_to?(:license) ? This.object.license : IO.binread('LICENSE').strip
297
335
 
298
336
  # discover full path to this ruby executable
299
337
  #
300
- c = Config::CONFIG
338
+ c = RbConfig::CONFIG
301
339
  bindir = c["bindir"] || c['BINDIR']
302
340
  ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
303
341
  ruby_ext = c['EXEEXT'] || ''
304
342
  ruby = File.join(bindir, (ruby_install_name + ruby_ext))
305
343
  This.ruby = ruby
306
344
 
307
- # some utils
345
+ # some utils, alwayze teh utils...
308
346
  #
309
347
  module Util
310
348
  def indent(s, n = 2)
@@ -319,7 +357,8 @@ BEGIN {
319
357
  next if line =~ %r/^\s*$/
320
358
  indent = line[%r/^\s*/] and break
321
359
  end
322
- indent ? s.gsub(%r/^#{ indent }/, "") : s
360
+ unindented = indent ? s.gsub(%r/^#{ indent }/, "") : s
361
+ unindented.strip
323
362
  end
324
363
  extend self
325
364
  end
@@ -327,17 +366,54 @@ BEGIN {
327
366
  # template support
328
367
  #
329
368
  class Template
369
+ def Template.indent(string, n = 2)
370
+ string = string.to_s
371
+ n = n.to_i
372
+ padding = (42 - 10).chr * n
373
+ initial = %r/^#{ Regexp.escape(padding) }/
374
+ #require 'debug'
375
+ #binding.break
376
+ Util.indent(string, n).sub(initial, '')
377
+ end
330
378
  def initialize(&block)
331
379
  @block = block
332
380
  @template = block.call.to_s
333
381
  end
334
382
  def expand(b=nil)
335
- ERB.new(Util.unindent(@template)).result((b||@block).binding)
383
+ ERB.new(Util.unindent(@template), trim_mode: '%<>-').result((b||@block).binding)
336
384
  end
337
385
  alias_method 'to_s', 'expand'
338
386
  end
339
387
  def Template(*args, &block) Template.new(*args, &block) end
340
388
 
389
+ # os / platform support
390
+ #
391
+ module Platform
392
+ def Platform.windows?
393
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
394
+ end
395
+
396
+ def Platform.darwin?
397
+ (/darwin/ =~ RUBY_PLATFORM) != nil
398
+ end
399
+
400
+ def Platform.mac?
401
+ Platform.darwin?
402
+ end
403
+
404
+ def Platform.unix?
405
+ !Platform.windows?
406
+ end
407
+
408
+ def Platform.linux?
409
+ Platform.unix? and not Platform.darwin?
410
+ end
411
+
412
+ def Platform.jruby?
413
+ RUBY_ENGINE == 'jruby'
414
+ end
415
+ end
416
+
341
417
  # colored console output support
342
418
  #
343
419
  This.ansi = {
Binary file
data/images/map.png ADDED
Binary file