coulis 0.1.2 → 0.2.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/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
|