coulis 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/coulis.rb +116 -42
- data/test/coulis_test.rb +106 -37
- metadata +10 -7
data/lib/coulis.rb
CHANGED
@@ -2,7 +2,7 @@ require "timeout"
|
|
2
2
|
|
3
3
|
class Coulis
|
4
4
|
class << self
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :_definitions, :bin, :timeout, :no_double_dash
|
6
6
|
|
7
7
|
def exec(*args, &block)
|
8
8
|
self.new.exec *args, &block
|
@@ -12,69 +12,49 @@ class Coulis
|
|
12
12
|
self.new(&block)
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
@
|
15
|
+
def _bin(p)
|
16
|
+
@bin = p.to_s
|
17
17
|
end
|
18
18
|
|
19
19
|
def _timeout(t)
|
20
20
|
@timeout = t
|
21
21
|
end
|
22
22
|
|
23
|
+
def _no_double_dash
|
24
|
+
@no_double_dash = true
|
25
|
+
end
|
26
|
+
|
23
27
|
def adef(name, option=nil, &block)
|
24
|
-
(@_definitions||={})[name.to_sym] = (option ||
|
25
|
-
end
|
26
|
-
|
27
|
-
def method_missing(m, args=nil)
|
28
|
-
m = m.to_s.gsub("=", "")
|
29
|
-
@args ||= []
|
30
|
-
definition = @_definitions[m.to_sym] rescue nil
|
31
|
-
|
32
|
-
#puts "m: #{m}, def: #{definition.inspect} | args:#{args}"
|
33
|
-
if definition.is_a?(Proc)
|
34
|
-
definition.call
|
35
|
-
else
|
36
|
-
arg_name = "#{"-" if m[0..0] != "-"}#{m}"
|
37
|
-
arg_name = "-" + arg_name.gsub("_", "-") if arg_name.size > 2
|
38
|
-
|
39
|
-
if args.to_s.empty?
|
40
|
-
@args << [ definition || arg_name ]
|
41
|
-
else
|
42
|
-
q = ""
|
43
|
-
q = "'" if args.to_s[0..0] != "'"
|
44
|
-
@args << [ definition || arg_name , "#{q}#{args}#{q}" ]
|
45
|
-
end
|
46
|
-
end
|
28
|
+
(@_definitions||={})[name.to_sym] = (option || block )
|
47
29
|
end
|
48
30
|
end
|
49
31
|
|
50
32
|
attr_accessor :args
|
51
33
|
|
52
34
|
def initialize(&block)
|
53
|
-
|
54
|
-
|
55
|
-
self.class.args = []
|
35
|
+
@args ||= []
|
36
|
+
self.instance_eval(&block) if block_given?
|
56
37
|
self
|
57
38
|
end
|
58
39
|
|
59
40
|
def options(&block)
|
60
|
-
self.
|
61
|
-
self
|
41
|
+
self.instance_eval(&block)
|
42
|
+
self
|
62
43
|
end
|
63
44
|
|
64
45
|
def remove(*args)
|
65
46
|
new_args = []
|
47
|
+
defs = self.class._definitions || {}
|
66
48
|
args.each do |a|
|
67
|
-
@args.select {|b| b[0] == (
|
49
|
+
@args.select {|b| b[0] == (defs[a] || argumentize(a))}.each do |b|
|
68
50
|
@args.delete(b)
|
69
51
|
end
|
70
52
|
end
|
71
|
-
self.class.args = @args
|
72
53
|
self
|
73
54
|
end
|
74
55
|
|
75
56
|
def reset
|
76
57
|
@args = []
|
77
|
-
self.class.args = []
|
78
58
|
end
|
79
59
|
|
80
60
|
def build_args
|
@@ -82,22 +62,52 @@ class Coulis
|
|
82
62
|
@args.flatten.join(" ")
|
83
63
|
end
|
84
64
|
|
65
|
+
def argumentize(argname)
|
66
|
+
argname = "#{"-" if argname.to_s[0..0] != "-"}#{argname}"
|
67
|
+
if !self.class.no_double_dash && argname.size > 2
|
68
|
+
argname = "-" + argname.gsub("_", "-")
|
69
|
+
end
|
70
|
+
argname
|
71
|
+
end
|
72
|
+
|
73
|
+
def value_by_arg(argname)
|
74
|
+
definition = self.class._definitions[argname.to_sym] || argumentize(argname)
|
75
|
+
|
76
|
+
result = @args.find{|a| a[0].to_s == definition.to_s}
|
77
|
+
return if result.nil?
|
78
|
+
|
79
|
+
value = result[1]
|
80
|
+
return nil if value.nil?
|
81
|
+
|
82
|
+
if value[0..0] == "'" && value[-1..-1]
|
83
|
+
return value[1..-2]
|
84
|
+
else
|
85
|
+
return value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
85
89
|
def command
|
86
|
-
"#{self.class.
|
90
|
+
"#{self.class.bin || self.class.to_s.downcase} #{build_args}".strip
|
87
91
|
end
|
88
92
|
|
89
93
|
def fire_command(&block)
|
90
94
|
puts command + " (timeout: #{self.class.timeout || -1}) + #{block_given?}" if $DEBUG
|
91
|
-
res = ""
|
95
|
+
res = ""
|
92
96
|
IO.popen(command + " 3>&2 2>&1") do |pipe|
|
93
97
|
pipe.each("\r") do |line|
|
98
|
+
res << line
|
94
99
|
if block_given?
|
95
100
|
yield parse_output(line)
|
96
|
-
else
|
97
|
-
res << line
|
98
101
|
end
|
99
102
|
end
|
100
103
|
end
|
104
|
+
if $?.exitstatus != 0
|
105
|
+
@on_error_block.call(res) if @on_error_block.is_a?(Proc)
|
106
|
+
after_error($?, res)
|
107
|
+
else
|
108
|
+
@on_success_block.call(res) if @on_success_block.is_a?(Proc)
|
109
|
+
after_success($?, res)
|
110
|
+
end
|
101
111
|
return (block_given? ? $? : parse_output(res))
|
102
112
|
end
|
103
113
|
|
@@ -105,10 +115,74 @@ class Coulis
|
|
105
115
|
output
|
106
116
|
end
|
107
117
|
|
108
|
-
def
|
109
|
-
|
110
|
-
self
|
111
|
-
|
118
|
+
def on_error(&block)
|
119
|
+
@on_error_block = block
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
def on_success(&block)
|
124
|
+
@on_success_block = block
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def after_success(proc, res); end
|
129
|
+
def after_error(proc, res); end
|
130
|
+
|
131
|
+
def _timeout(value)
|
132
|
+
self.class.timeout = value
|
133
|
+
end
|
134
|
+
|
135
|
+
def _bin(path)
|
136
|
+
self.class.bin = path
|
137
|
+
end
|
138
|
+
|
139
|
+
def method_missing(m, *args)
|
140
|
+
m = m.to_s.gsub("=", "")
|
141
|
+
@args ||= []
|
142
|
+
definition = self.class._definitions[m.to_sym] rescue nil
|
143
|
+
#puts "m: #{m}, args: #{args.inspect}, definition: #{definition.inspect}"
|
144
|
+
arg_name = argumentize(m)
|
145
|
+
|
146
|
+
if args.to_s.empty?
|
147
|
+
insert_arg [ definition || arg_name ]
|
148
|
+
return self
|
149
|
+
end
|
150
|
+
|
151
|
+
q = ""
|
152
|
+
q = "'" if args[0].to_s[0..0] != "'"
|
153
|
+
full_arg = [ definition || arg_name , "#{q}#{args[0]}#{q}" ]
|
154
|
+
|
155
|
+
insert_arg(full_arg, args[1])
|
156
|
+
# delete doublon
|
157
|
+
if args[1] && args[1].has_key?(:uniq)
|
158
|
+
uniq_arg(definition || arg_name)
|
159
|
+
end
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
def uniq_arg(arg)
|
164
|
+
if found = @args.find{|a| a[0] == arg}
|
165
|
+
@args.delete found
|
166
|
+
end
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
def insert_arg(arg, opts=nil)
|
171
|
+
if !opts
|
172
|
+
@args << arg
|
173
|
+
return self
|
174
|
+
end
|
175
|
+
|
176
|
+
if arg_to_find = opts[:before] || opts[:after]
|
177
|
+
found = @args.find{|a|
|
178
|
+
a[0] == self.class._definitions[arg_to_find.to_sym] || arg_to_find
|
179
|
+
}
|
180
|
+
if found && index = @args.index(found)
|
181
|
+
@args.insert(index+1, arg)
|
182
|
+
end
|
183
|
+
else
|
184
|
+
@args << arg
|
185
|
+
end
|
112
186
|
self
|
113
187
|
end
|
114
188
|
|
data/test/coulis_test.rb
CHANGED
@@ -4,14 +4,16 @@ require "coulis"
|
|
4
4
|
class Ls < Coulis
|
5
5
|
adef :all, "-a"
|
6
6
|
adef :human, "-h"
|
7
|
+
adef :full, "-a -h"
|
8
|
+
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
class FFMpeg < Coulis
|
11
|
+
_no_double_dash
|
12
|
+
adef :input, "-i"
|
11
13
|
end
|
12
14
|
|
13
15
|
class Ping < Coulis
|
14
|
-
|
16
|
+
_bin `whereis ping`.strip
|
15
17
|
adef :count, "-c"
|
16
18
|
end
|
17
19
|
|
@@ -25,8 +27,12 @@ end
|
|
25
27
|
|
26
28
|
class SimpleCliTest < Test::Unit::TestCase
|
27
29
|
def teardown
|
28
|
-
Ls.new.reset
|
29
|
-
Ping.new.reset
|
30
|
+
#Ls.new.reset
|
31
|
+
#Ping.new.reset
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_shit
|
35
|
+
#p Ls.options { full }
|
30
36
|
end
|
31
37
|
|
32
38
|
def test_default_bin
|
@@ -35,7 +41,7 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
35
41
|
|
36
42
|
def test_defined_bin
|
37
43
|
assert_equal Ping.new.command, `whereis ping`.strip
|
38
|
-
assert_equal Ping.new.command, Ping.
|
44
|
+
assert_equal Ping.new.command, Ping.bin
|
39
45
|
end
|
40
46
|
|
41
47
|
def test_adef
|
@@ -43,9 +49,8 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
43
49
|
assert_equal Ls._definitions[:human], "-h"
|
44
50
|
end
|
45
51
|
|
46
|
-
def
|
47
|
-
|
48
|
-
assert_equal Ls._definitions[:full].call, ["-a", "-h"]
|
52
|
+
def test_adef_with_multiple_args
|
53
|
+
assert_equal Ls._definitions[:full], "-a -h"
|
49
54
|
end
|
50
55
|
|
51
56
|
def test_argument_added
|
@@ -53,51 +58,58 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
53
58
|
assert true, ls.args[0] == "-a"
|
54
59
|
end
|
55
60
|
|
56
|
-
def test_all_arguments_from_adef_added
|
57
|
-
ls = Ls.options { full }
|
58
|
-
assert_equal ls.args.size, 2
|
59
|
-
end
|
60
|
-
|
61
61
|
def test_not_defined_short_argument
|
62
|
-
ls = Ls.options {
|
63
|
-
assert_equal ls.args.size
|
64
|
-
assert_equal ls.args.to_s
|
62
|
+
ls = Ls.options { g }
|
63
|
+
assert_equal 1, ls.args.size
|
64
|
+
assert_equal "-g", ls.args.to_s
|
65
65
|
end
|
66
66
|
|
67
67
|
def test_not_defined_long_argument
|
68
68
|
ls = Ls.options { color }
|
69
|
-
assert_equal ls.args.size
|
70
|
-
assert_equal ls.args.to_s
|
69
|
+
assert_equal 1, ls.args.size
|
70
|
+
assert_equal "--color", ls.args.to_s
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_not_defined_long_argument_with_underscore
|
74
74
|
ls = Ls.options { color_test }
|
75
|
-
assert_equal ls.args.size
|
76
|
-
assert_equal
|
75
|
+
assert_equal 1, ls.args.size
|
76
|
+
assert_equal "--color-test", ls.args.to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_no_double_dash_option
|
80
|
+
ffmpeg = FFMpeg.options { vcodec "libx264" }
|
81
|
+
assert_equal "ffmpeg -vcodec 'libx264'", ffmpeg.command
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_remove_args_if_not_defined
|
85
|
+
ffmpeg = FFMpeg.options { vcodec "libx264" }
|
86
|
+
assert_equal 1, ffmpeg.args.size
|
87
|
+
ffmpeg.remove :vcodec
|
88
|
+
assert_equal 0, ffmpeg.args.size
|
77
89
|
end
|
78
90
|
|
79
91
|
def test_command
|
80
|
-
assert_equal Ls.options { full;
|
92
|
+
assert_equal "ls -a -h -g", Ls.options { full; g }.command
|
81
93
|
end
|
82
94
|
|
83
95
|
def test_add_options
|
84
96
|
ls = Ls.options { a }
|
85
|
-
assert_equal ls.args.flatten.size
|
97
|
+
assert_equal 1, ls.args.flatten.size
|
86
98
|
ls.options { l; h }
|
87
|
-
assert_equal ls.args.flatten.size
|
99
|
+
assert_equal 3, ls.args.flatten.size
|
88
100
|
|
89
|
-
assert_equal
|
101
|
+
assert_equal "ls -a -l -h", ls.command
|
90
102
|
end
|
91
103
|
|
92
104
|
def test_add_option
|
93
105
|
ls = Ls.new
|
94
106
|
ls.all
|
95
|
-
assert_equal ls.args.flatten.size
|
96
|
-
assert_equal
|
107
|
+
assert_equal 1, ls.args.flatten.size
|
108
|
+
assert_equal "ls -a", ls.command
|
97
109
|
|
98
110
|
ls.l
|
99
|
-
assert_equal ls.args.flatten.size
|
100
|
-
assert_equal
|
111
|
+
assert_equal 2, ls.args.flatten.size
|
112
|
+
assert_equal "ls -a -l", ls.command
|
101
113
|
end
|
102
114
|
|
103
115
|
def test_add_option_with_args
|
@@ -105,25 +117,25 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
105
117
|
@args << ["-c", 2] << ["google.com"]
|
106
118
|
}
|
107
119
|
|
108
|
-
assert_equal ping.command, "#{Ping.
|
120
|
+
assert_equal ping.command, "#{Ping.bin} -c 2 google.com"
|
109
121
|
end
|
110
122
|
|
111
123
|
def test_remove_options
|
112
124
|
ls = Ls.options { a; l; h }
|
113
125
|
ls.remove :a, :h
|
114
|
-
assert_equal
|
126
|
+
assert_equal "ls -l", ls.command
|
115
127
|
|
116
128
|
ls.reset
|
117
129
|
ls.all
|
118
130
|
ls.remove :all
|
119
|
-
assert_equal ls
|
131
|
+
assert_equal "ls", ls.command
|
120
132
|
end
|
121
133
|
|
122
134
|
def test_reset
|
123
135
|
ls = Ls.options { a; l; h }
|
124
|
-
assert_equal
|
136
|
+
assert_equal "ls -a -l -h", ls.command
|
125
137
|
ls.reset
|
126
|
-
assert_equal ls
|
138
|
+
assert_equal "ls", ls.command
|
127
139
|
end
|
128
140
|
|
129
141
|
def test_exec
|
@@ -141,7 +153,7 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
141
153
|
end
|
142
154
|
|
143
155
|
assert_instance_of Process::Status, process
|
144
|
-
assert_equal process.exitstatus
|
156
|
+
assert_equal 0, process.exitstatus
|
145
157
|
end
|
146
158
|
|
147
159
|
def test_timeout
|
@@ -151,7 +163,7 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
151
163
|
_timeout 2
|
152
164
|
}.exec
|
153
165
|
end
|
154
|
-
assert_equal Ping.timeout
|
166
|
+
assert_equal 2, Ping.timeout
|
155
167
|
end
|
156
168
|
|
157
169
|
def test_stdout
|
@@ -174,4 +186,61 @@ class SimpleCliTest < Test::Unit::TestCase
|
|
174
186
|
assert true, ips.size > 1
|
175
187
|
end
|
176
188
|
end
|
189
|
+
|
190
|
+
def test_success_event
|
191
|
+
process = Ls.options {
|
192
|
+
all
|
193
|
+
}.on_success {|out|
|
194
|
+
assert_instance_of Process::Status, $?
|
195
|
+
assert_equal 0, $?.exitstatus
|
196
|
+
assert_instance_of String, out
|
197
|
+
}.exec {|out|
|
198
|
+
assert_instance_of String, out
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_error_event
|
203
|
+
process = Ls.options {
|
204
|
+
@args = ["/not/a/path"]
|
205
|
+
}.on_error {|out|
|
206
|
+
assert_instance_of Process::Status, $?
|
207
|
+
assert_equal 1, $?.exitstatus
|
208
|
+
assert_instance_of String, out
|
209
|
+
}.exec {|out|
|
210
|
+
assert_instance_of String, out
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_getting_value_by_arg
|
215
|
+
ffmpeg = FFMpeg.options { input "video.mp4"; vcodec "libx264"}
|
216
|
+
assert_equal "video.mp4", ffmpeg.value_by_arg(:input)
|
217
|
+
assert_equal "libx264", ffmpeg.value_by_arg(:vcodec)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_adding_arg_before_another
|
221
|
+
ffmpeg = FFMpeg.options {
|
222
|
+
input "video.mp4"
|
223
|
+
y "out.avi"
|
224
|
+
vcodec "libx264", :before => "-y"
|
225
|
+
}
|
226
|
+
assert_equal "ffmpeg -i 'video.mp4' -vcodec 'libx264' -y 'out.avi'", ffmpeg.command
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_adding_arg_after_another
|
230
|
+
ffmpeg = FFMpeg.options {
|
231
|
+
input "video.mp4"
|
232
|
+
y "out.avi"
|
233
|
+
}
|
234
|
+
ffmpeg.vcodec "libx264", :after => :input
|
235
|
+
assert_equal "ffmpeg -i 'video.mp4' -vcodec 'libx264' -y 'out.avi'", ffmpeg.command
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_adding_uniq_arg
|
239
|
+
ffmpeg = FFMpeg.options {
|
240
|
+
input "video.mp4"
|
241
|
+
y "out.avi"
|
242
|
+
}
|
243
|
+
ffmpeg.input "video2.mp4", :before => "-y", :uniq => true
|
244
|
+
assert_equal "ffmpeg -i 'video2.mp4' -y 'out.avi'", ffmpeg.command
|
245
|
+
end
|
177
246
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coulis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
- 1
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Bruno Celeste
|
@@ -14,8 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
-
default_executable:
|
18
|
+
date: 2012-07-03 00:00:00 Z
|
19
19
|
dependencies: []
|
20
20
|
|
21
21
|
description: Simple but powerful CLI Wrapper
|
@@ -29,7 +29,6 @@ extra_rdoc_files: []
|
|
29
29
|
files:
|
30
30
|
- lib/coulis.rb
|
31
31
|
- test/coulis_test.rb
|
32
|
-
has_rdoc: true
|
33
32
|
homepage: http://github.com/sadikzzz/coulis
|
34
33
|
licenses: []
|
35
34
|
|
@@ -39,23 +38,27 @@ rdoc_options: []
|
|
39
38
|
require_paths:
|
40
39
|
- lib
|
41
40
|
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
42
|
requirements:
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
45
46
|
segments:
|
46
47
|
- 0
|
47
48
|
version: "0"
|
48
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
49
51
|
requirements:
|
50
52
|
- - ">="
|
51
53
|
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
52
55
|
segments:
|
53
56
|
- 0
|
54
57
|
version: "0"
|
55
58
|
requirements: []
|
56
59
|
|
57
60
|
rubyforge_project:
|
58
|
-
rubygems_version: 1.
|
61
|
+
rubygems_version: 1.8.24
|
59
62
|
signing_key:
|
60
63
|
specification_version: 3
|
61
64
|
summary: A simple CLI Wrapper
|