cmds 0.0.1
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/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +333 -0
- data/Rakefile +1 -0
- data/ansible/dev.yml +25 -0
- data/ansible/hosts +6 -0
- data/cmds.gemspec +27 -0
- data/lib/cmds/version.rb +3 -0
- data/lib/cmds.rb +322 -0
- data/scratch/blah.rb +6 -0
- data/scratch/erb.rb +53 -0
- data/spec/cmds/call_spec.rb +16 -0
- data/spec/cmds/curry_spec.rb +14 -0
- data/spec/cmds/erb_context_spec.rb +23 -0
- data/spec/cmds/expand_option_hash_spec.rb +61 -0
- data/spec/cmds/replace_shortcuts_spec.rb +78 -0
- data/spec/cmds/run_spec.rb +49 -0
- data/spec/cmds/sub_spec.rb +159 -0
- data/spec/cmds_spec.rb +7 -0
- data/spec/spec_helper.rb +21 -0
- data/test/echo_cmd.rb +15 -0
- metadata +147 -0
data/lib/cmds.rb
ADDED
@@ -0,0 +1,322 @@
|
|
1
|
+
# stdlib
|
2
|
+
require 'shellwords'
|
3
|
+
require 'open3'
|
4
|
+
require 'erubis'
|
5
|
+
|
6
|
+
# deps
|
7
|
+
require 'nrser'
|
8
|
+
|
9
|
+
# project
|
10
|
+
require "cmds/version"
|
11
|
+
|
12
|
+
class Cmds
|
13
|
+
class Result
|
14
|
+
attr_reader :cmd, :status, :out, :err
|
15
|
+
|
16
|
+
def initialize cmd, status, out, err
|
17
|
+
@cmd = cmd
|
18
|
+
@status = status
|
19
|
+
@out = out
|
20
|
+
@err = err
|
21
|
+
end
|
22
|
+
|
23
|
+
def ok?
|
24
|
+
@status == 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def error?
|
28
|
+
! ok?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# extension of Erubis' EscapedEruby (which auto-escapes `<%= %>` and
|
33
|
+
# leaves `<%== %>` raw) that calls `Cmds.expand_sub` on the value
|
34
|
+
class ShellEruby < Erubis::EscapedEruby
|
35
|
+
def escaped_expr code
|
36
|
+
"::Cmds.expand_sub(#{code.strip})"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ERBContext < BasicObject
|
41
|
+
def initialize args, kwds
|
42
|
+
@args = args
|
43
|
+
@kwds = kwds
|
44
|
+
@arg_index = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing sym, *args, &block
|
48
|
+
if args.empty? && block.nil?
|
49
|
+
if sym.to_s[-1] == '?'
|
50
|
+
key = sym.to_s[0...-1].to_sym
|
51
|
+
@kwds[key]
|
52
|
+
else
|
53
|
+
@kwds.fetch sym
|
54
|
+
end
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_binding
|
61
|
+
::Kernel.send :binding
|
62
|
+
end
|
63
|
+
|
64
|
+
def arg
|
65
|
+
@args.fetch(@arg_index).tap {@arg_index += 1}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# shortcut for Shellwords.escape
|
70
|
+
#
|
71
|
+
# also makes it easier to change or customize or whatever
|
72
|
+
def self.esc str
|
73
|
+
Shellwords.escape str
|
74
|
+
end
|
75
|
+
|
76
|
+
# escape option hash.
|
77
|
+
#
|
78
|
+
# this is only useful for the two common option styles:
|
79
|
+
#
|
80
|
+
# - single character keys become `-<char> <value>`
|
81
|
+
#
|
82
|
+
# {x: 1} => "-x 1"
|
83
|
+
#
|
84
|
+
# - longer keys become `--<key>=<value>` options
|
85
|
+
#
|
86
|
+
# {blah: 2} => "--blah=2"
|
87
|
+
#
|
88
|
+
# if you have something else, you're going to have to just put it in
|
89
|
+
# the cmd itself, like:
|
90
|
+
#
|
91
|
+
# Cmds "blah -assholeOptionOn:%{s}", "ok"
|
92
|
+
#
|
93
|
+
# or whatever similar shit said command requires.
|
94
|
+
#
|
95
|
+
# however, if the value is an Array, it will repeat the option for each
|
96
|
+
# value:
|
97
|
+
#
|
98
|
+
# {x: [1, 2, 3]} => "-x 1 -x 2 -x 3"
|
99
|
+
# {blah: [1, 2, 3]} => "--blah=1 --blah=2 --blah=3"
|
100
|
+
#
|
101
|
+
# i can't think of any right now, but i swear i've seen commands that take
|
102
|
+
# opts that way.
|
103
|
+
#
|
104
|
+
def self.expand_option_hash hash
|
105
|
+
hash.map {|key, values|
|
106
|
+
# keys need to be strings
|
107
|
+
key = key.to_s unless key.is_a? String
|
108
|
+
|
109
|
+
[key, values]
|
110
|
+
|
111
|
+
}.sort {|(key_a, values_a), (key_b, values_b)|
|
112
|
+
# sort by the (now string) keys
|
113
|
+
key_a <=> key_b
|
114
|
+
|
115
|
+
}.map {|key, values|
|
116
|
+
# for simplicity's sake, treat all values like an array
|
117
|
+
values = [values] unless values.is_a? Array
|
118
|
+
|
119
|
+
# keys of length 1 expand to `-x v` form
|
120
|
+
expanded = if key.length == 1
|
121
|
+
values.map {|value|
|
122
|
+
if value.nil?
|
123
|
+
"-#{ esc key }"
|
124
|
+
else
|
125
|
+
"-#{ esc key } #{ esc value}"
|
126
|
+
end
|
127
|
+
}
|
128
|
+
|
129
|
+
# longer keys expand to `--key=value` form
|
130
|
+
else
|
131
|
+
values.map {|value|
|
132
|
+
if value.nil?
|
133
|
+
"--#{ esc key }"
|
134
|
+
else
|
135
|
+
"--#{ esc key }=#{ esc value }"
|
136
|
+
end
|
137
|
+
}
|
138
|
+
end
|
139
|
+
}.flatten.join ' '
|
140
|
+
end # ::expand_option_hash
|
141
|
+
|
142
|
+
# expand one of the substitutions
|
143
|
+
def self.expand_sub sub
|
144
|
+
case sub
|
145
|
+
when nil
|
146
|
+
# nil is just an empty string, NOT an empty string bash token
|
147
|
+
''
|
148
|
+
when Hash
|
149
|
+
expand_option_hash sub
|
150
|
+
else
|
151
|
+
esc sub.to_s
|
152
|
+
end
|
153
|
+
end # ::expand_sub
|
154
|
+
|
155
|
+
# substitute values into a command, escaping them for the shell and
|
156
|
+
# offering convenient expansions for some structures.
|
157
|
+
#
|
158
|
+
# `cmd` is a string that can be substituted via ruby's `%` operator, like
|
159
|
+
#
|
160
|
+
# "git diff %s"
|
161
|
+
#
|
162
|
+
# for positional substitution, or
|
163
|
+
#
|
164
|
+
# "git diff %{path}"
|
165
|
+
#
|
166
|
+
# for keyword substitution.
|
167
|
+
#
|
168
|
+
# `subs` is either:
|
169
|
+
#
|
170
|
+
# - an Array when `cmd` has positional placeholders
|
171
|
+
# - a Hash when `cmd` has keyword placeholders.
|
172
|
+
#
|
173
|
+
# the elements of the `subs` array or values of the `subs` hash are:
|
174
|
+
#
|
175
|
+
# - strings that are substituted into `cmd` after being escaped:
|
176
|
+
#
|
177
|
+
# sub "git diff %{path}", path: "some path/to somewhere"
|
178
|
+
# # => 'git diff some\ path/to\ somewhere'
|
179
|
+
#
|
180
|
+
# - hashes that are expanded into options:
|
181
|
+
#
|
182
|
+
# sub "psql %{opts} %{database} < %{filepath}",
|
183
|
+
# database: "blah",
|
184
|
+
# filepath: "/where ever/it/is.psql",
|
185
|
+
# opts: {
|
186
|
+
# username: "bingo bob",
|
187
|
+
# host: "localhost",
|
188
|
+
# port: 12345,
|
189
|
+
# }
|
190
|
+
# # => 'psql --host=localhost --port=12345 --username=bingo\ bob blah < /where\ ever/it/is.psql'
|
191
|
+
#
|
192
|
+
def self.sub cmd, args = [], kwds = {}
|
193
|
+
raise TypeError.new("args must be an Array") unless args.is_a? Array
|
194
|
+
raise TypeError.new("kwds must be an Hash") unless kwds.is_a? Hash
|
195
|
+
|
196
|
+
context = ERBContext.new(args, kwds)
|
197
|
+
erb = ShellEruby.new(replace_shortcuts cmd)
|
198
|
+
|
199
|
+
NRSER.squish erb.result(context.get_binding)
|
200
|
+
end # ::sub
|
201
|
+
|
202
|
+
def self.subs_to_args_and_kwds subs
|
203
|
+
args = []
|
204
|
+
kwds = {}
|
205
|
+
|
206
|
+
case subs.length
|
207
|
+
when 0
|
208
|
+
# pass
|
209
|
+
when 1
|
210
|
+
case subs[0]
|
211
|
+
when Hash
|
212
|
+
kwds = subs[0]
|
213
|
+
|
214
|
+
when Array
|
215
|
+
args = subs[0]
|
216
|
+
|
217
|
+
else
|
218
|
+
raise TypeError.new NRSER.squish <<-BLOCK
|
219
|
+
first *subs arg must be Array or Hash, not #{ subs[0].inspect }
|
220
|
+
BLOCK
|
221
|
+
end
|
222
|
+
|
223
|
+
when 2
|
224
|
+
unless subs[0].is_a? Array
|
225
|
+
raise TypeError.new NRSER.squish <<-BLOCK
|
226
|
+
first *subs arg needs to be an array, not #{ subs[0].inspect }
|
227
|
+
BLOCK
|
228
|
+
end
|
229
|
+
|
230
|
+
unless subs[1].is_a? Hash
|
231
|
+
raise TypeError.new NRSER.squish <<-BLOCK
|
232
|
+
third *subs arg needs to be a Hash, not #{ subs[1].inspect }
|
233
|
+
BLOCK
|
234
|
+
end
|
235
|
+
|
236
|
+
args, kwds = subs
|
237
|
+
else
|
238
|
+
raise ArgumentError.new NRSER.squish <<-BLOCK
|
239
|
+
must provide one or two *subs arguments, received #{ 1 + subs.length }
|
240
|
+
BLOCK
|
241
|
+
end
|
242
|
+
|
243
|
+
[args, kwds]
|
244
|
+
end
|
245
|
+
|
246
|
+
# create a new Cmd from template and subs and call it
|
247
|
+
def self.run template, *subs
|
248
|
+
self.new(template, *subs).call
|
249
|
+
end
|
250
|
+
|
251
|
+
def self.replace_shortcuts template
|
252
|
+
template
|
253
|
+
.gsub(
|
254
|
+
# %s => <%= arg %>
|
255
|
+
/(\A|[[:space:]])\%s(\Z|[[:space:]])/,
|
256
|
+
'\1<%= arg %>\2'
|
257
|
+
)
|
258
|
+
.gsub(
|
259
|
+
# %%s => %s (escpaing)
|
260
|
+
/(\A|[[:space:]])(\%+)\%s(\Z|[[:space:]])/,
|
261
|
+
'\1\2s\3'
|
262
|
+
)
|
263
|
+
.gsub(
|
264
|
+
# %{key} => <%= key %>, %{key?} => <%= key? %>
|
265
|
+
/(\A|[[:space:]])\%\{([a-zA-Z_]+\??)\}(\Z|[[:space:]])/,
|
266
|
+
'\1<%= \2 %>\3'
|
267
|
+
)
|
268
|
+
.gsub(
|
269
|
+
# %%{key} => %{key}, %%{key?} => %{key?} (escpaing)
|
270
|
+
/(\A|[[:space:]])(\%+)\%\{([a-zA-Z_]+\??)\}(\Z|[[:space:]])/,
|
271
|
+
'\1\2{\3}\4'
|
272
|
+
)
|
273
|
+
.gsub(
|
274
|
+
# %<key>s => <%= key %>, %<key?>s => <%= key? %>
|
275
|
+
/(\A|[[:space:]])\%\<([a-zA-Z_]+\??)\>s(\Z|[[:space:]])/,
|
276
|
+
'\1<%= \2 %>\3'
|
277
|
+
)
|
278
|
+
.gsub(
|
279
|
+
# %%<key>s => %<key>s, %%<key?>s => %<key?>s (escaping)
|
280
|
+
/(\A|[[:space:]])(\%+)\%\<([a-zA-Z_]+\??)\>s(\Z|[[:space:]])/,
|
281
|
+
'\1\2<\3>s\4'
|
282
|
+
)
|
283
|
+
end
|
284
|
+
|
285
|
+
attr_reader :tempalte, :args, :kwds
|
286
|
+
|
287
|
+
def initialize template, *subs
|
288
|
+
@template = template
|
289
|
+
@args, @kwds = Cmds.subs_to_args_and_kwds subs
|
290
|
+
end #initialize
|
291
|
+
|
292
|
+
def call *subs
|
293
|
+
args, kwds = merge_subs subs
|
294
|
+
|
295
|
+
cmd = Cmds.sub @template, args, kwds
|
296
|
+
|
297
|
+
out, err, status = Open3.capture3 cmd
|
298
|
+
|
299
|
+
Cmds::Result.new cmd, status, out, err
|
300
|
+
end #call
|
301
|
+
|
302
|
+
# returns a new `Cmds` with the subs merged in
|
303
|
+
def curry *subs
|
304
|
+
self.class.new @template, *merge_subs(subs)
|
305
|
+
end
|
306
|
+
|
307
|
+
private
|
308
|
+
|
309
|
+
def merge_subs subs
|
310
|
+
# break `subs` into `args` and `kwds`
|
311
|
+
args, kwds = Cmds.subs_to_args_and_kwds subs
|
312
|
+
|
313
|
+
[@args + args, @kwds.merge(kwds)]
|
314
|
+
end #merge_subs
|
315
|
+
|
316
|
+
# end private
|
317
|
+
end # Cmds
|
318
|
+
|
319
|
+
# convenience for Cmds::run
|
320
|
+
def Cmds *args
|
321
|
+
Cmds.run *args
|
322
|
+
end
|
data/scratch/blah.rb
ADDED
data/scratch/erb.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'erubis'
|
3
|
+
require 'nrser'
|
4
|
+
|
5
|
+
class ShellEruby < Erubis::EscapedEruby
|
6
|
+
def escaped_expr code
|
7
|
+
"Shellwords.escape((#{code.strip}).to_s)"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ERBContext
|
12
|
+
def initialize args, kwargs
|
13
|
+
@args = args
|
14
|
+
@kwargs = kwargs
|
15
|
+
@arg_index = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing sym, *args, &block
|
19
|
+
if args.empty? && block.nil?
|
20
|
+
if sym.to_s[-1] == '?'
|
21
|
+
key = sym.to_s[0...-1].to_sym
|
22
|
+
@kwargs[key]
|
23
|
+
else
|
24
|
+
@kwargs.fetch(sym)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_binding
|
32
|
+
binding
|
33
|
+
end
|
34
|
+
|
35
|
+
def arg
|
36
|
+
@args.fetch(@arg_index).tap {@arg_index += 1}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
tpl = <<-BLOCK
|
41
|
+
defaults write <%= domain %> <%= key %> -dict
|
42
|
+
<% values.each do |key, value| %>
|
43
|
+
<%= key %> <%= value %>
|
44
|
+
<% end %>
|
45
|
+
BLOCK
|
46
|
+
|
47
|
+
ctx = ERBContext.new [], domain: "com.nrser.blah",
|
48
|
+
key: "don't do it",
|
49
|
+
values: {x: '<ex>', y: 'why'}
|
50
|
+
|
51
|
+
s = NRSER.squish ShellEruby.new(tpl).result(ctx.get_binding)
|
52
|
+
|
53
|
+
puts s
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe "Cmds::call" do
|
6
|
+
it "is reusable" do
|
7
|
+
args_cmd = Cmds.new "./test/echo_cmd.rb <%= arg %>"
|
8
|
+
kwds_cmd = Cmds.new "./test/echo_cmd.rb <%= s %>"
|
9
|
+
|
10
|
+
["arg one", "arg two", "arg three"].each do |arg|
|
11
|
+
[args_cmd.call([arg]), kwds_cmd.call(s: arg)].each do |result|
|
12
|
+
expect_argv( result ).to eq [arg]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end # is reusable
|
16
|
+
end # Cmds::run
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Cmds::curry" do
|
4
|
+
it "currys" do
|
5
|
+
base = Cmds.new "./test/echo_cmd.rb <%= x %> <%= y %>"
|
6
|
+
|
7
|
+
x1 = base.curry x: 1
|
8
|
+
x2 = base.curry x: 2
|
9
|
+
|
10
|
+
expect_argv( x1.call y: 'why' ).to eq ['1', 'why']
|
11
|
+
expect_argv( x2.call y: 'who' ).to eq ['2', 'who']
|
12
|
+
expect_argv( base.call x: 3, y: 4 ).to eq ['3', '4']
|
13
|
+
end # it currys
|
14
|
+
end # Cmds::run
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cmds::ERBContext do
|
4
|
+
let(:tpl) {
|
5
|
+
<<-BLOCK
|
6
|
+
defaults
|
7
|
+
<% if current_host? %>
|
8
|
+
-currentHost <%= current_host %>
|
9
|
+
<% end %>
|
10
|
+
export <%= domain %> <%= filepath %>
|
11
|
+
BLOCK
|
12
|
+
}
|
13
|
+
|
14
|
+
def get_result tpl, bnd
|
15
|
+
NRSER.squish ERB.new(tpl).result(bnd.get_binding)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should work" do
|
19
|
+
bnd = Cmds::ERBContext.new [], current_host: 'xyz', domain: 'com.nrser.blah', filepath: '/tmp/export.plist'
|
20
|
+
|
21
|
+
expect(get_result tpl, bnd).to eq "defaults -currentHost xyz export com.nrser.blah /tmp/export.plist"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Cmds::expand_option_hash_spec" do
|
4
|
+
|
5
|
+
context "one single char key" do
|
6
|
+
it "handles nil value" do
|
7
|
+
expect(Cmds.expand_option_hash x: nil).to eq "-x"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "handles simple value" do
|
11
|
+
expect(Cmds.expand_option_hash x: 1).to eq "-x 1"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "handles array value" do
|
15
|
+
expect(Cmds.expand_option_hash x: [1, 2, 3]).to eq "-x 1 -x 2 -x 3"
|
16
|
+
end
|
17
|
+
end # single char key
|
18
|
+
|
19
|
+
context "multiple single char keys" do
|
20
|
+
it "order expansion by key" do
|
21
|
+
expect(Cmds.expand_option_hash b: 2, a: 1, c: 3).to eq "-a 1 -b 2 -c 3"
|
22
|
+
end
|
23
|
+
end # multiple single char keys
|
24
|
+
|
25
|
+
context "one longer key" do
|
26
|
+
it "handles nil value" do
|
27
|
+
expect(Cmds.expand_option_hash blah: nil).to eq "--blah"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "handles a simple value" do
|
31
|
+
expect(Cmds.expand_option_hash blah: 1).to eq "--blah=1"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "handles an array value" do
|
35
|
+
expect(Cmds.expand_option_hash blah: [1, 2, 3]).to eq "--blah=1 --blah=2 --blah=3"
|
36
|
+
end
|
37
|
+
end # one longer key
|
38
|
+
|
39
|
+
context "multiple longer keys" do
|
40
|
+
it "order expansion by key" do
|
41
|
+
expect(Cmds.expand_option_hash bob: 2, al: 1, cat: 3).to eq "--al=1 --bob=2 --cat=3"
|
42
|
+
end
|
43
|
+
end # multiple longer keys
|
44
|
+
|
45
|
+
it "handles a mess of stuff" do
|
46
|
+
expect(
|
47
|
+
Cmds.expand_option_hash d: 1,
|
48
|
+
blah: "blow",
|
49
|
+
cat: nil,
|
50
|
+
x: ['m', 'e',]
|
51
|
+
).to eq "--blah=blow --cat -d 1 -x m -x e"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "escapes paths" do
|
55
|
+
expect(
|
56
|
+
Cmds.expand_option_hash path: "/some folder/some where",
|
57
|
+
p: "maybe ov/er here..."
|
58
|
+
).to eq '-p maybe\ ov/er\ here... --path=/some\ folder/some\ where'
|
59
|
+
end
|
60
|
+
|
61
|
+
end # ::expand_option_hash_spec
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def expect_to_replace input, output
|
4
|
+
[
|
5
|
+
"#{ input }",
|
6
|
+
"blah #{ input }",
|
7
|
+
"#{ input } blah",
|
8
|
+
"blah\n#{ input }\nblah",
|
9
|
+
].each do |str|
|
10
|
+
expect( Cmds.replace_shortcuts input ).to eq output
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'Cmds::replace_shortcuts' do
|
15
|
+
it "should replace %s with <%= arg %>" do
|
16
|
+
expect_to_replace "%s", "<%= arg %>"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should replace %%s with %s (escaping)" do
|
20
|
+
expect_to_replace "%%s", "%s"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should replace %%%s with %%s (escaping)" do
|
24
|
+
expect_to_replace "%%%s", "%%s"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should replace %{key} with <%= key %>" do
|
28
|
+
expect_to_replace "%{key}", "<%= key %>"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should replace %%{key} with %{key} (escaping)" do
|
32
|
+
expect_to_replace '%%{key}', '%{key}'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should replace %%%{key} with %%{key} (escaping)" do
|
36
|
+
expect_to_replace '%%%{key}', '%%{key}'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should replace %{key?} with <%= key? %>" do
|
40
|
+
expect_to_replace "%{key?}", "<%= key? %>"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should replace %%{key?} with %{key?} (escaping)" do
|
44
|
+
expect_to_replace '%%{key?}', '%{key?}'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should replace %%%{key?} with %%{key?} (escaping)" do
|
48
|
+
expect_to_replace '%%%{key?}', '%%{key?}'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should replace %<key>s with <%= key %>" do
|
52
|
+
expect_to_replace "%<key>s", "<%= key %>"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should replace %%<key>s with %<key>s (escaping)" do
|
56
|
+
expect_to_replace "%%<key>s", "%<key>s"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should replace %%%<key>s with %%<key>s (escaping)" do
|
60
|
+
expect_to_replace "%%%<key>s", "%%<key>s"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should replace %<key?>s with <%= key? %>" do
|
64
|
+
expect_to_replace '%<key?>s', '<%= key? %>'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should replace %%<key?>s with %<key?>s (escaping)" do
|
68
|
+
expect_to_replace '%%<key?>s', '%<key?>s'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should replace %%%<key?>s with %%<key?>s (escaping)" do
|
72
|
+
expect_to_replace '%%%<key?>s', '%%<key?>s'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not touch % that don't fit the shortcut sytax" do
|
76
|
+
expect( Cmds.replace_shortcuts "50%" ).to eq "50%"
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe "Cmds::run" do
|
6
|
+
context "echo_cmd.rb 'hello world!'" do
|
7
|
+
|
8
|
+
shared_examples "executes correctly" do
|
9
|
+
it_behaves_like "ok"
|
10
|
+
|
11
|
+
it "should have 'hello world!' as ARGV[0]" do
|
12
|
+
expect( JSON.load(result.out)['ARGV'][0] ).to eq "hello world!"
|
13
|
+
end
|
14
|
+
end # executes correctly
|
15
|
+
|
16
|
+
context "positional args" do
|
17
|
+
let(:result) {
|
18
|
+
Cmds "./test/echo_cmd.rb <%= arg %>", ["hello world!"]
|
19
|
+
}
|
20
|
+
|
21
|
+
it_behaves_like "executes correctly"
|
22
|
+
end
|
23
|
+
|
24
|
+
context "keyword args" do
|
25
|
+
let(:result) {
|
26
|
+
Cmds "./test/echo_cmd.rb <%= s %>", s: "hello world!"
|
27
|
+
}
|
28
|
+
|
29
|
+
it_behaves_like "executes correctly"
|
30
|
+
end
|
31
|
+
|
32
|
+
end # context echo_cmd.rb 'hello world!'
|
33
|
+
|
34
|
+
# context "feeding kwargs to args cmd" do
|
35
|
+
# let(:result) {
|
36
|
+
# Cmds "./test/echo_cmd.rb %s", s: "sup y'all"
|
37
|
+
# }
|
38
|
+
|
39
|
+
# it "" do
|
40
|
+
# expect( result.cmd ).to eq nil
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
|
44
|
+
it "should error when second (subs) arg is not a hash or array" do
|
45
|
+
expect {
|
46
|
+
Cmds "./test/echo_cmd.rb <%= arg %>", "hello world!"
|
47
|
+
}.to raise_error TypeError
|
48
|
+
end
|
49
|
+
end # Cmds::run
|