main 4.3.0 → 4.4.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.
- data/README +105 -0
- data/README.erb +79 -1
- data/TODO +17 -19
- data/a.rb +29 -2
- data/lib/main.rb +2 -1
- data/lib/main/cast.rb +46 -3
- data/lib/main/parameter.rb +22 -1
- data/lib/main/program/class_methods.rb +94 -6
- data/lib/main/program/instance_methods.rb +27 -8
- data/lib/main/util.rb +14 -0
- data/main.gemspec +1 -1
- data/samples/j.rb +25 -8
- data/test/main.rb +1 -1
- metadata +4 -4
data/README
CHANGED
@@ -450,6 +450,48 @@ SAMPLES
|
|
450
450
|
"forty-two"
|
451
451
|
|
452
452
|
|
453
|
+
<========< samples/j.rb >========>
|
454
|
+
|
455
|
+
~ > cat samples/j.rb
|
456
|
+
|
457
|
+
#!/usr/bin/env ruby
|
458
|
+
|
459
|
+
require 'open-uri'
|
460
|
+
|
461
|
+
require 'main'
|
462
|
+
require 'digest/sha2'
|
463
|
+
|
464
|
+
# you have access to a sequel/amalgalite/sqlite db for free
|
465
|
+
#
|
466
|
+
|
467
|
+
Main {
|
468
|
+
name :i_can_haz_db
|
469
|
+
|
470
|
+
db {
|
471
|
+
create_table(:mp3s) do
|
472
|
+
primary_key :id
|
473
|
+
String :url
|
474
|
+
String :sha
|
475
|
+
end unless table_exists?(:mp3s)
|
476
|
+
}
|
477
|
+
|
478
|
+
def run
|
479
|
+
url = 'http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3'
|
480
|
+
mp3 = open(url){|fd| fd.read}
|
481
|
+
sha = Digest::SHA2.hexdigest(mp3)
|
482
|
+
|
483
|
+
db[:mp3s].insert(:url => url, :sha => sha)
|
484
|
+
p db[:mp3s].all
|
485
|
+
p db
|
486
|
+
end
|
487
|
+
}
|
488
|
+
|
489
|
+
~ > ruby samples/j.rb
|
490
|
+
|
491
|
+
[{:url=>"http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3", :sha=>"54c99ac7588dcfce1e70540b734805e9c69ff98dcca001e6f2bdec140fb0f9dc", :id=>1}, {:url=>"http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3", :sha=>"54c99ac7588dcfce1e70540b734805e9c69ff98dcca001e6f2bdec140fb0f9dc", :id=>2}]
|
492
|
+
#<Sequel::Amalgalite::Database: "amalgalite://Users/ahoward/.i_can_haz_db/db.sqlite">
|
493
|
+
|
494
|
+
|
453
495
|
|
454
496
|
DOCS
|
455
497
|
test/main.rb
|
@@ -457,6 +499,69 @@ DOCS
|
|
457
499
|
API section below
|
458
500
|
|
459
501
|
HISTORY
|
502
|
+
4.4.0
|
503
|
+
- support for automatic sequel/sqlite/amalgalite dbs for persistent state
|
504
|
+
across invocations
|
505
|
+
|
506
|
+
Main {
|
507
|
+
db {
|
508
|
+
create_table :foo do
|
509
|
+
String key
|
510
|
+
String val
|
511
|
+
end unless table_exists? :foo
|
512
|
+
}
|
513
|
+
|
514
|
+
def run
|
515
|
+
db[:foo].create(:key => 'using', :val => 'amalgalite')
|
516
|
+
end
|
517
|
+
}
|
518
|
+
|
519
|
+
- support for automatic config files with auto populated template data
|
520
|
+
|
521
|
+
Main {
|
522
|
+
config :email => 'your.addy@gmail.com', :password => 'pa$$word'
|
523
|
+
|
524
|
+
def run
|
525
|
+
email = config[:email]
|
526
|
+
end
|
527
|
+
}
|
528
|
+
|
529
|
+
- new paramter types :pathname, :path, :slug, :input, and :output
|
530
|
+
|
531
|
+
- input/output parameters. can be filenames or '-' to supply
|
532
|
+
stdin/stdout respectively
|
533
|
+
|
534
|
+
Main {
|
535
|
+
input :i
|
536
|
+
output :o
|
537
|
+
|
538
|
+
def run
|
539
|
+
i = params[:i].value
|
540
|
+
o = params[:o].value
|
541
|
+
|
542
|
+
line = i.gets
|
543
|
+
o.puts line
|
544
|
+
end
|
545
|
+
}
|
546
|
+
|
547
|
+
- clean up warnings running with 'ruby -w'
|
548
|
+
|
549
|
+
- fix a failing test
|
550
|
+
|
551
|
+
- ability to ignore parameters in sub modes
|
552
|
+
|
553
|
+
Main {
|
554
|
+
argument :foo
|
555
|
+
argument :bar
|
556
|
+
|
557
|
+
def run
|
558
|
+
p param[:bar].value
|
559
|
+
end
|
560
|
+
|
561
|
+
mode :ignoring do
|
562
|
+
params[:foo].ignore!
|
563
|
+
end
|
564
|
+
}
|
460
565
|
4.0.0
|
461
566
|
- avoid duping ios. new methods Main.push_ios! and Main.pop_ios! are
|
462
567
|
utilized for testing. this was done to make it simple to wrap
|
data/README.erb
CHANGED
@@ -5,9 +5,9 @@ SYNOPSIS
|
|
5
5
|
a class factory and dsl for generating command line programs real quick
|
6
6
|
|
7
7
|
URI
|
8
|
+
http://github.com/ahoward/main
|
8
9
|
http://codeforpeople.com/lib/ruby/
|
9
10
|
http://rubyforge.org/projects/codeforpeople/
|
10
|
-
http://github.com/ahoward/main
|
11
11
|
|
12
12
|
INSTALL
|
13
13
|
gem install main
|
@@ -26,6 +26,8 @@ DESCRIPTION
|
|
26
26
|
- parsing user defined ARGV and ENV
|
27
27
|
- zero requirements for understanding the obtuse apis of *any* command
|
28
28
|
line option parsers
|
29
|
+
- built-in support for persistent state via sqlite/sequel/amalgalite
|
30
|
+
- built-in support for yaml config files
|
29
31
|
- leather pants
|
30
32
|
|
31
33
|
in short main.rb aims to drastically lower the barrier to writing uniform
|
@@ -186,6 +188,82 @@ DOCS
|
|
186
188
|
API section below
|
187
189
|
|
188
190
|
HISTORY
|
191
|
+
4.4.0
|
192
|
+
- app storage under a dotdir. for example
|
193
|
+
|
194
|
+
Main {
|
195
|
+
name :foobar
|
196
|
+
}
|
197
|
+
|
198
|
+
will have a ~/.foobar/ directory available for storing db/config/etc.
|
199
|
+
|
200
|
+
- support for automatic sequel/sqlite/amalgalite dbs for persistent state
|
201
|
+
across invocations. the db is automatically created under the main
|
202
|
+
programs dotdir (~/.$appname/db.sqlite)
|
203
|
+
|
204
|
+
Main {
|
205
|
+
db {
|
206
|
+
create_table :foo do
|
207
|
+
String key
|
208
|
+
String val
|
209
|
+
end unless table_exists? :foo
|
210
|
+
}
|
211
|
+
|
212
|
+
def run
|
213
|
+
db[:foo].create(:key => 'using', :val => 'amalgalite')
|
214
|
+
end
|
215
|
+
}
|
216
|
+
|
217
|
+
- support for automatic config files with auto populated template data.
|
218
|
+
the first time the program is run the user's editor will be invoked on a
|
219
|
+
config file pre-populate with the same config. subsequent invocations
|
220
|
+
will use the user configured values. the config file is stored at
|
221
|
+
~/.$appname/config.yml
|
222
|
+
|
223
|
+
Main {
|
224
|
+
config :email => 'your.addy@gmail.com', :password => 'pa$$word'
|
225
|
+
|
226
|
+
def run
|
227
|
+
email = config[:email]
|
228
|
+
end
|
229
|
+
}
|
230
|
+
|
231
|
+
- new paramter types :pathname, :path, :slug, :input, and :output
|
232
|
+
|
233
|
+
- input/output parameters. can be filenames or '-' to supply
|
234
|
+
stdin/stdout respectively
|
235
|
+
|
236
|
+
Main {
|
237
|
+
input :i
|
238
|
+
output :o
|
239
|
+
|
240
|
+
def run
|
241
|
+
i = params[:i].value
|
242
|
+
o = params[:o].value
|
243
|
+
|
244
|
+
line = i.gets
|
245
|
+
o.puts line
|
246
|
+
end
|
247
|
+
}
|
248
|
+
|
249
|
+
- clean up warnings running with 'ruby -w'
|
250
|
+
|
251
|
+
- fix a failing test
|
252
|
+
|
253
|
+
- ability to ignore parameters in sub modes
|
254
|
+
|
255
|
+
Main {
|
256
|
+
argument :foo
|
257
|
+
argument :bar
|
258
|
+
|
259
|
+
def run
|
260
|
+
p param[:bar].value
|
261
|
+
end
|
262
|
+
|
263
|
+
mode :ignoring do
|
264
|
+
params[:foo].ignore!
|
265
|
+
end
|
266
|
+
}
|
189
267
|
4.0.0
|
190
268
|
- avoid duping ios. new methods Main.push_ios! and Main.pop_ios! are
|
191
269
|
utilized for testing. this was done to make it simple to wrap
|
data/TODO
CHANGED
@@ -1,20 +1,18 @@
|
|
1
|
+
todo:
|
2
|
+
- examples of new features
|
3
|
+
- use map.rb
|
1
4
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
X calls to abort sometimes lead to STDERR prining twice ;-(
|
17
|
-
X main's' with modes, but no run do not operate properly - add default run w/wrap_run!
|
18
|
-
X usage fubar when extra chunks are set
|
19
|
-
X usage of arguments is fubar when negative arities are used
|
20
|
-
X add sanity checks at parameter contruction completion
|
5
|
+
done:
|
6
|
+
- clean up warnings under 'ruby -w'
|
7
|
+
- intput/output arguments
|
8
|
+
- support io cast '-' (:input, :output)
|
9
|
+
- slug casts
|
10
|
+
- support uri casts
|
11
|
+
- dotdir support (based on name)
|
12
|
+
- db support
|
13
|
+
- configuration/configfile file support
|
14
|
+
- calls to abort sometimes lead to STDERR prining twice ;-(
|
15
|
+
- main's' with modes, but no run do not operate properly - add default run w/wrap_run!
|
16
|
+
- usage fubar when extra chunks are set
|
17
|
+
- usage of arguments is fubar when negative arities are used
|
18
|
+
- add sanity checks at parameter contruction completion
|
data/a.rb
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
require 'main'
|
2
2
|
|
3
3
|
Main {
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
name :foobar
|
6
|
+
|
7
|
+
db {
|
8
|
+
create_table(:foo) do
|
9
|
+
primary_key :id
|
10
|
+
String :name
|
11
|
+
Float :price
|
12
|
+
end unless table_exists?(:foo)
|
13
|
+
}
|
14
|
+
|
15
|
+
config(
|
16
|
+
:email => 'your.addy@gmail.com',
|
17
|
+
:password => 'yourPa$$word'
|
18
|
+
)
|
19
|
+
|
20
|
+
io
|
21
|
+
|
22
|
+
|
23
|
+
def run
|
24
|
+
#p input.path
|
25
|
+
#p output.path
|
26
|
+
p params.map{|param| param.name}
|
27
|
+
output.puts(:foobar)
|
28
|
+
end
|
29
|
+
|
30
|
+
mode :foo do
|
31
|
+
params[:input].ignore!
|
32
|
+
end
|
6
33
|
}
|
data/lib/main.rb
CHANGED
@@ -2,7 +2,7 @@ module Main
|
|
2
2
|
#
|
3
3
|
# top level constants
|
4
4
|
#
|
5
|
-
Main::VERSION = '4.
|
5
|
+
Main::VERSION = '4.4.0' unless
|
6
6
|
defined? Main::VERSION
|
7
7
|
def self.version() Main::VERSION end
|
8
8
|
|
@@ -13,6 +13,7 @@ module Main
|
|
13
13
|
Main::EXIT_SUCCESS = 0 unless defined? Main::EXIT_SUCCESS
|
14
14
|
Main::EXIT_FAILURE = 1 unless defined? Main::EXIT_FAILURE
|
15
15
|
Main::EXIT_WARN = 42 unless defined? Main::EXIT_WARN
|
16
|
+
Main::EXIT_WARNING = 42 unless defined? Main::EXIT_WARNING
|
16
17
|
#
|
17
18
|
# built-in
|
18
19
|
#
|
data/lib/main/cast.rb
CHANGED
@@ -25,7 +25,7 @@ module Main
|
|
25
25
|
end
|
26
26
|
|
27
27
|
cast :integer do |obj|
|
28
|
-
|
28
|
+
Float(obj).to_i
|
29
29
|
end
|
30
30
|
|
31
31
|
cast :float do |obj|
|
@@ -45,7 +45,7 @@ module Main
|
|
45
45
|
end
|
46
46
|
|
47
47
|
cast :uri do |obj|
|
48
|
-
require 'uri'
|
48
|
+
require 'uri' unless defined?(::URI)
|
49
49
|
::URI.parse obj.to_s
|
50
50
|
end
|
51
51
|
|
@@ -55,10 +55,53 @@ module Main
|
|
55
55
|
end
|
56
56
|
|
57
57
|
cast :date do |obj|
|
58
|
-
require 'date'
|
58
|
+
require 'date' unless defined?(::Date)
|
59
59
|
::Date.parse obj.to_s
|
60
60
|
end
|
61
61
|
|
62
|
+
cast :pathname do |obj|
|
63
|
+
require 'pathname' unless defined?(::Pathname)
|
64
|
+
Pathname.new(obj.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
cast :path do |obj|
|
68
|
+
File.expand_path(obj.to_s)
|
69
|
+
end
|
70
|
+
|
71
|
+
cast :input do |obj|
|
72
|
+
case obj.to_s
|
73
|
+
when '-'
|
74
|
+
io = STDIN.dup
|
75
|
+
io.fattr(:path){ '/dev/stdin' }
|
76
|
+
io
|
77
|
+
else
|
78
|
+
io = open(obj.to_s, 'r+')
|
79
|
+
at_exit{ io.close }
|
80
|
+
io
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
cast :output do |obj|
|
85
|
+
case obj.to_s
|
86
|
+
when '-'
|
87
|
+
io = STDOUT.dup
|
88
|
+
io.fattr(:path){ '/dev/stdout' }
|
89
|
+
io
|
90
|
+
else
|
91
|
+
io = open(obj.to_s, 'w+')
|
92
|
+
at_exit{ io.close }
|
93
|
+
io
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
cast :slug do |obj|
|
98
|
+
string = [obj].flatten.compact.join('-')
|
99
|
+
words = string.to_s.scan(%r/\w+/)
|
100
|
+
words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
|
101
|
+
words.delete_if{|word| word.nil? or word.strip.empty?}
|
102
|
+
String(words.join('-').downcase)
|
103
|
+
end
|
104
|
+
|
62
105
|
cast :list do |*objs|
|
63
106
|
[*objs].flatten.join(',').split(/,/)
|
64
107
|
end
|
data/lib/main/parameter.rb
CHANGED
@@ -109,10 +109,15 @@ module Main
|
|
109
109
|
names.first
|
110
110
|
end
|
111
111
|
|
112
|
-
def default
|
112
|
+
def default(*values)
|
113
|
+
defaults(values) unless values.empty?
|
113
114
|
defaults.first
|
114
115
|
end
|
115
116
|
|
117
|
+
def default=(value)
|
118
|
+
default(value)
|
119
|
+
end
|
120
|
+
|
116
121
|
def typename
|
117
122
|
prefix = '--' if type.to_s =~ %r/option/
|
118
123
|
"#{ type }(#{ prefix }#{ name })"
|
@@ -248,6 +253,13 @@ module Main
|
|
248
253
|
end
|
249
254
|
end
|
250
255
|
|
256
|
+
def remove
|
257
|
+
main.parameters.delete(self)
|
258
|
+
end
|
259
|
+
alias_method('remove!', 'remove')
|
260
|
+
alias_method('ignore', 'remove')
|
261
|
+
alias_method('ignore!', 'ignore')
|
262
|
+
|
251
263
|
class Argument < Parameter
|
252
264
|
fattr 'required' => true
|
253
265
|
|
@@ -527,6 +539,15 @@ module Main
|
|
527
539
|
delete(*a)
|
528
540
|
super
|
529
541
|
end
|
542
|
+
|
543
|
+
def [](*index)
|
544
|
+
first = index.first
|
545
|
+
if(index.size == 1 and (first.is_a?(String) or first.is_a?(Symbol)))
|
546
|
+
first = first.to_s
|
547
|
+
return detect{|param| param.name == first}
|
548
|
+
end
|
549
|
+
return super
|
550
|
+
end
|
530
551
|
end
|
531
552
|
|
532
553
|
class DSL
|
@@ -21,11 +21,11 @@ module Main
|
|
21
21
|
fattr('exit_success'){ Main::EXIT_SUCCESS }
|
22
22
|
fattr('exit_failure'){ Main::EXIT_FAILURE }
|
23
23
|
fattr('exit_warn'){ Main::EXIT_WARN }
|
24
|
+
fattr('exit_warning'){ Main::EXIT_WARNING }
|
24
25
|
fattr('parameters'){ Main::Parameter::List[] }
|
25
26
|
fattr('can_has_hash'){ Hash.new }
|
26
27
|
fattr('mixin_table'){ Hash.new }
|
27
28
|
|
28
|
-
fattr('factory')
|
29
29
|
fattr('argv')
|
30
30
|
fattr('env')
|
31
31
|
fattr('opts')
|
@@ -35,6 +35,10 @@ module Main
|
|
35
35
|
end
|
36
36
|
alias_method 'create', 'factory'
|
37
37
|
|
38
|
+
def factory=(factory)
|
39
|
+
@factory = factory
|
40
|
+
end
|
41
|
+
|
38
42
|
class Factory
|
39
43
|
def initialize(&block)
|
40
44
|
@block = block || lambda{}
|
@@ -84,6 +88,10 @@ module Main
|
|
84
88
|
instance
|
85
89
|
end
|
86
90
|
|
91
|
+
def params
|
92
|
+
parameters
|
93
|
+
end
|
94
|
+
|
87
95
|
def evaluate(&block)
|
88
96
|
module_eval(&block)
|
89
97
|
end
|
@@ -182,23 +190,23 @@ module Main
|
|
182
190
|
end
|
183
191
|
|
184
192
|
def parameter(*a, &b)
|
185
|
-
(parameters << Parameter.create(:parameter, self, *a, &b)).last
|
193
|
+
(parameters << Parameter.create(:parameter, main=self, *a, &b)).last
|
186
194
|
end
|
187
195
|
|
188
196
|
def argument(*a, &b)
|
189
|
-
(parameters << Parameter.create(:argument, self, *a, &b)).last
|
197
|
+
(parameters << Parameter.create(:argument, main=self, *a, &b)).last
|
190
198
|
end
|
191
199
|
|
192
200
|
def option(*a, &b)
|
193
|
-
(parameters << Parameter.create(:option, self, *a, &b)).last
|
201
|
+
(parameters << Parameter.create(:option, main=self, *a, &b)).last
|
194
202
|
end
|
195
203
|
|
196
204
|
def keyword(*a, &b)
|
197
|
-
(parameters << Parameter.create(:keyword, self, *a, &b)).last
|
205
|
+
(parameters << Parameter.create(:keyword, main=self, *a, &b)).last
|
198
206
|
end
|
199
207
|
|
200
208
|
def environment(*a, &b)
|
201
|
-
(parameters << Parameter.create(:environment, self, *a, &b)).last
|
209
|
+
(parameters << Parameter.create(:environment, main=self, *a, &b)).last
|
202
210
|
end
|
203
211
|
|
204
212
|
def default_options!
|
@@ -259,6 +267,86 @@ module Main
|
|
259
267
|
block ||= lambda{}
|
260
268
|
define_method(:run, &block) if block
|
261
269
|
end
|
270
|
+
|
271
|
+
def dotdir(*dotdir, &block)
|
272
|
+
@dotdir = File.join(Util.home, ".#{ name }") unless defined?(@dotdir)
|
273
|
+
|
274
|
+
@dotdir = dotdir.join('/') unless dotdir.empty?
|
275
|
+
|
276
|
+
if block
|
277
|
+
require 'fileutils' unless defined?(FileUtils)
|
278
|
+
FileUtils.mkdir_p(@dotdir) unless test(?d, @dotdir)
|
279
|
+
Dir.chdir(&block)
|
280
|
+
else
|
281
|
+
@dotdir
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def db(*args, &block)
|
286
|
+
unless defined?(@db)
|
287
|
+
require 'sequel' unless defined?(Sequel)
|
288
|
+
require 'amalgalite' unless defined?(Amalgalite)
|
289
|
+
@db = dotdir{ Sequel.amalgalite(db_path) }
|
290
|
+
@db.instance_eval(&block) if block
|
291
|
+
end
|
292
|
+
@db
|
293
|
+
end
|
294
|
+
|
295
|
+
def db_path(*db_path)
|
296
|
+
@db_path = File.join(dotdir, 'db.sqlite') unless defined?(@db_path)
|
297
|
+
@db_path = File.join(*db_path) unless db_path.empty?
|
298
|
+
@db_path
|
299
|
+
end
|
300
|
+
|
301
|
+
def config(*args, &block)
|
302
|
+
unless defined?(@config)
|
303
|
+
require 'yaml' unless defined?(YAML)
|
304
|
+
if test(?s, config_path)
|
305
|
+
@config = YAML.load(IO.read(config_path))
|
306
|
+
else
|
307
|
+
config = args.last.is_a?(Hash) ? args.last : {}
|
308
|
+
lines = config.to_yaml.split(/\n/)
|
309
|
+
dash = lines.shift
|
310
|
+
open(config_path, 'w') do |fd|
|
311
|
+
fd.puts '### you may need to edit this config!'
|
312
|
+
fd.puts
|
313
|
+
fd.puts lines
|
314
|
+
end
|
315
|
+
editor = ENV['EDITOR'] || ENV['EDIT'] || 'vi'
|
316
|
+
system("#{ editor.inspect } #{ config_path }")
|
317
|
+
@config = YAML.load(IO.read(config_path))
|
318
|
+
end
|
319
|
+
end
|
320
|
+
@config
|
321
|
+
end
|
322
|
+
|
323
|
+
def config_path(*config_path)
|
324
|
+
@config_path = File.join(dotdir, 'config.yml') unless defined?(@config_path)
|
325
|
+
@config_path = File.join(*config_path) unless config_path.empty?
|
326
|
+
@config_path
|
327
|
+
end
|
328
|
+
|
329
|
+
def input(*args, &block)
|
330
|
+
first = args.first
|
331
|
+
args.push(:input) unless(first.is_a?(Symbol) or first.is_a?(String))
|
332
|
+
param = argument(*args, &block)
|
333
|
+
param.cast(:input)
|
334
|
+
param
|
335
|
+
end
|
336
|
+
|
337
|
+
def output(*args, &block)
|
338
|
+
first = args.first
|
339
|
+
args.push(:output) unless(first.is_a?(Symbol) or first.is_a?(String))
|
340
|
+
param = argument(*args, &block)
|
341
|
+
param.cast(:output)
|
342
|
+
param
|
343
|
+
end
|
344
|
+
|
345
|
+
def io(*args)
|
346
|
+
i = input(*[args.shift].compact).default('-')
|
347
|
+
o = output(*[args.shift].compact).default('-')
|
348
|
+
[i, o]
|
349
|
+
end
|
262
350
|
end
|
263
351
|
|
264
352
|
extend ClassMethods
|
@@ -16,7 +16,7 @@ module Main
|
|
16
16
|
|
17
17
|
%w(
|
18
18
|
program name synopsis description author version
|
19
|
-
exit_status exit_success exit_failure exit_warn
|
19
|
+
exit_status exit_success exit_failure exit_warn exit_warning
|
20
20
|
logger_level
|
21
21
|
usage
|
22
22
|
).each{|a| fattr(a){ self.class.send a}}
|
@@ -31,9 +31,9 @@ module Main
|
|
31
31
|
end
|
32
32
|
|
33
33
|
%w( debug info warn fatal error ).each do |m|
|
34
|
-
module_eval <<-code
|
35
|
-
def #{ m }
|
36
|
-
logger.#{ m }
|
34
|
+
module_eval <<-code, __FILE__, __LINE__
|
35
|
+
def #{ m }(*a, &b)
|
36
|
+
logger.#{ m }(*a, &b)
|
37
37
|
end
|
38
38
|
code
|
39
39
|
end
|
@@ -87,7 +87,6 @@ module Main
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def setup_io_restoration
|
90
|
-
return
|
91
90
|
@finalizers ||= []
|
92
91
|
[STDIN, STDOUT, STDERR].each do |io|
|
93
92
|
dup = io.dup
|
@@ -250,9 +249,9 @@ module Main
|
|
250
249
|
end
|
251
250
|
|
252
251
|
%w[ before instead after ].each do |which|
|
253
|
-
module_eval <<-code
|
254
|
-
def error_handler_#{ which }
|
255
|
-
block.call
|
252
|
+
module_eval <<-code, __FILE__, __LINE__
|
253
|
+
def error_handler_#{ which }(*argv, &block)
|
254
|
+
block.call(*argv)
|
256
255
|
end
|
257
256
|
code
|
258
257
|
end
|
@@ -265,6 +264,26 @@ module Main
|
|
265
264
|
singleton_class.module_eval{ define_method('__instance_eval_block', &block) }
|
266
265
|
fcall(self, '__instance_eval_block', *argv, &block)
|
267
266
|
end
|
267
|
+
|
268
|
+
def dotdir(&block)
|
269
|
+
self.class.dotdir(&block)
|
270
|
+
end
|
271
|
+
|
272
|
+
def db(&block)
|
273
|
+
self.class.db(&block)
|
274
|
+
end
|
275
|
+
|
276
|
+
def config(&block)
|
277
|
+
self.class.config(&block)
|
278
|
+
end
|
279
|
+
|
280
|
+
def input
|
281
|
+
@input ||= params[:input].value if params[:input]
|
282
|
+
end
|
283
|
+
|
284
|
+
def output
|
285
|
+
@output ||= params[:output].value if params[:output]
|
286
|
+
end
|
268
287
|
end
|
269
288
|
|
270
289
|
include InstanceMethods
|
data/lib/main/util.rb
CHANGED
@@ -71,6 +71,20 @@ module Main
|
|
71
71
|
|
72
72
|
return default
|
73
73
|
end
|
74
|
+
|
75
|
+
def home
|
76
|
+
home =
|
77
|
+
catch :home do
|
78
|
+
["HOME", "USERPROFILE"].each do |key|
|
79
|
+
throw(:home, ENV[key]) if ENV[key]
|
80
|
+
end
|
81
|
+
if ENV["HOMEDRIVE"] and ENV["HOMEPATH"]
|
82
|
+
throw(:home, "#{ ENV['HOMEDRIVE'] }:#{ ENV['HOMEPATH'] }")
|
83
|
+
end
|
84
|
+
File.expand_path("~") rescue(File::ALT_SEPARATOR ? "C:/" : "/")
|
85
|
+
end
|
86
|
+
File.expand_path(home)
|
87
|
+
end
|
74
88
|
end
|
75
89
|
|
76
90
|
BLESS = lambda do |other|
|
data/main.gemspec
CHANGED
data/samples/j.rb
CHANGED
@@ -1,14 +1,31 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'open-uri'
|
4
|
+
|
2
5
|
require 'main'
|
6
|
+
require 'digest/sha2'
|
7
|
+
|
8
|
+
# you have access to a sequel/amalgalite/sqlite db for free
|
9
|
+
#
|
3
10
|
|
4
11
|
Main {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
name :i_can_haz_db
|
13
|
+
|
14
|
+
db {
|
15
|
+
create_table(:mp3s) do
|
16
|
+
primary_key :id
|
17
|
+
String :url
|
18
|
+
String :sha
|
19
|
+
end unless table_exists?(:mp3s)
|
13
20
|
}
|
21
|
+
|
22
|
+
def run
|
23
|
+
url = 'http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3'
|
24
|
+
mp3 = open(url){|fd| fd.read}
|
25
|
+
sha = Digest::SHA2.hexdigest(mp3)
|
26
|
+
|
27
|
+
db[:mp3s].insert(:url => url, :sha => sha)
|
28
|
+
p db[:mp3s].all
|
29
|
+
p db
|
30
|
+
end
|
14
31
|
}
|
data/test/main.rb
CHANGED
@@ -258,7 +258,7 @@ class T < Test::Unit::TestCase
|
|
258
258
|
}
|
259
259
|
option('y'){
|
260
260
|
argument_required
|
261
|
-
|
261
|
+
cast{|*values| values.join.split(',').map{|value| value.upcase}}
|
262
262
|
}
|
263
263
|
define_method('run'){ param = params }
|
264
264
|
}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: main
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 47
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 4
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 4.
|
10
|
+
version: 4.4.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: 2010-11-
|
18
|
+
date: 2010-11-25 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|