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 +7 -0
- data/LICENSE +1 -1
- data/README.md +268 -0
- data/Rakefile +140 -64
- data/images/giraffe.jpeg +0 -0
- data/images/map.png +0 -0
- data/lib/map/_lib.rb +85 -0
- data/lib/map/ordering.rb +126 -0
- data/lib/map.rb +151 -121
- data/map.gemspec +21 -12
- data/specs/001-ordered-map-module/checklists/requirements.md +62 -0
- data/specs/001-ordered-map-module/data-model.md +250 -0
- data/specs/001-ordered-map-module/plan.md +139 -0
- data/specs/001-ordered-map-module/quickstart.md +430 -0
- data/specs/001-ordered-map-module/research.md +189 -0
- data/specs/001-ordered-map-module/spec.md +108 -0
- data/specs/001-ordered-map-module/tasks.md +264 -0
- data/test/map_test.rb +21 -57
- metadata +39 -23
- data/a.rb +0 -10
- data/lib/map/integrations/active_record.rb +0 -140
- data/lib/map/params.rb +0 -79
- data/lib/map/struct.rb +0 -52
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
|
-
|
|
1
|
+
Ruby
|
data/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
NAME
|
|
2
|
+
----
|
|
3
|
+
map.rb
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
LOGO
|
|
7
|
+
----
|
|
8
|
+

|
|
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.
|
|
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 "
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
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
|
-
## <%=
|
|
143
|
+
## <%= name %>.gemspec
|
|
125
144
|
#
|
|
126
145
|
|
|
127
146
|
Gem::Specification::new do |spec|
|
|
128
|
-
spec.name = <%=
|
|
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 = <%=
|
|
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 = "#{
|
|
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
|
|
181
|
-
|
|
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 <<
|
|
185
|
-
samples << Util.indent(
|
|
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 <<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
226
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
299
|
+
# load actual shit _lib
|
|
269
300
|
#
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
#
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
#
|
|
309
|
+
# extract the name from the _lib
|
|
288
310
|
#
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
#
|
|
327
|
+
# now, fully grok This
|
|
294
328
|
#
|
|
295
|
-
|
|
296
|
-
|
|
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 =
|
|
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 = {
|
data/images/giraffe.jpeg
ADDED
|
Binary file
|
data/images/map.png
ADDED
|
Binary file
|