objective_command 0.1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/AUTHORS +5 -0
  2. data/ChangeLog +17 -0
  3. data/NEWS +3 -0
  4. data/README +2 -0
  5. data/Rakefile +8 -0
  6. data/SPEC.gemspec +15 -0
  7. data/SPEC.yml +43 -0
  8. data/bin/ocmd +32 -0
  9. data/lib/hookable.rb +284 -0
  10. data/lib/hooker.rb +47 -0
  11. data/lib/objective_command/all.rb +32 -0
  12. data/lib/objective_command/commands/command.rb +535 -0
  13. data/lib/objective_command/commands/factory.rb +69 -0
  14. data/lib/objective_command/commands/pipe.rb +121 -0
  15. data/lib/objective_command/commands/seq.rb +35 -0
  16. data/lib/objective_command/datas/composite.rb +55 -0
  17. data/lib/objective_command/datas/data.rb +175 -0
  18. data/lib/objective_command/datas/factory.rb +74 -0
  19. data/lib/objective_command/datas/pipe.rb +55 -0
  20. data/lib/objective_command/datas/temp.rb +24 -0
  21. data/lib/objective_command/datas.rb +11 -0
  22. data/lib/objective_command/helpers.rb +113 -0
  23. data/lib/objective_command/runners/exec.rb +46 -0
  24. data/lib/objective_command/runners/fork.rb +91 -0
  25. data/lib/objective_command/runners/mockable.rb +62 -0
  26. data/lib/objective_command/runners/no_run.rb +44 -0
  27. data/lib/objective_command/runners/popen.rb +49 -0
  28. data/lib/objective_command/runners/runner.rb +227 -0
  29. data/lib/objective_command/runners/system.rb +54 -0
  30. data/lib/objective_command/runners.rb +11 -0
  31. data/lib/objective_command/shell.rb +173 -0
  32. data/lib/objective_command/version_id.rb +10 -0
  33. data/lib/objective_command.rb +54 -0
  34. data/test/check-objective_command.yml +10 -0
  35. data/test/check-pkg-objective_command.yml +13 -0
  36. data/test/sanity/multiple-requires.yml +62 -0
  37. data/test/sanity/single-requires.yml +40 -0
  38. data/test/sanity-suite.yml +10 -0
  39. data/test/unit-suite.yml +14 -0
  40. metadata +97 -0
@@ -0,0 +1,62 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners/mockable.rb 23187 2006-03-31T21:59:37.612710Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+
10
+ module Mockable
11
+
12
+ def make_mock log=[], &block
13
+ @log = log
14
+ @block = block
15
+
16
+ class << self
17
+ attr_accessor :log
18
+ attr_accessor :block
19
+
20
+ def exec ( aCommand, aData )
21
+ @block[aCommand, aData]
22
+ end
23
+
24
+ def display_command ( m )
25
+ @log << m
26
+ end
27
+ end # class << self
28
+
29
+ self
30
+ end
31
+
32
+ end # module Mockable
33
+
34
+ Runner.include Mockable
35
+
36
+ test_section __FILE__ do
37
+
38
+ class MockTest < Test::Unit::TestCase
39
+
40
+ def setup
41
+ assert_nothing_raised { @runner = System.new.make_mock }
42
+ end
43
+
44
+ def test_0_initialize
45
+ end
46
+
47
+ def test_simple
48
+ assert_nothing_raised do
49
+ @cmd = 'foo bar baz'.to_ocmd
50
+ @data = @runner.run(@cmd)
51
+ end
52
+ assert_kind_of(Datas::Data, @data)
53
+ assert_equal([@cmd], @runner.log)
54
+ end
55
+
56
+ end # class SystemTest
57
+
58
+ end
59
+
60
+ end # module Runners
61
+
62
+ end # module ObjectiveCommand
@@ -0,0 +1,44 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners/no_run.rb 23187 2006-03-31T21:59:37.612710Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+
10
+ # This very particular runner returns it's command instead of running it.
11
+ class NoRun < Runner
12
+ make Concrete
13
+
14
+ def run ( aCommand )
15
+ aCommand
16
+ end
17
+
18
+ end # class NoRun
19
+
20
+
21
+
22
+ test_section __FILE__ do
23
+
24
+ class NoRunTest < Test::Unit::TestCase
25
+
26
+ def setup
27
+ assert_nothing_raised { @runner = NoRun.new }
28
+ end
29
+
30
+ def test_0_initialize
31
+ end
32
+
33
+ def test_simple
34
+ cmd = 'sleep'.to_ocmd[10]
35
+ assert_kind_of Commands::Command, cmd.run(@runner)
36
+ end
37
+
38
+ end # class NoRunTest
39
+
40
+ end
41
+
42
+ end # module Runners
43
+
44
+ end # module ObjectiveCommand
@@ -0,0 +1,49 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners/popen.rb 23187 2006-03-31T21:59:37.612710Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+
10
+ class Popen < Fork
11
+ make Concrete
12
+
13
+ def initialize ( *a, &b )
14
+ super
15
+ @command_data_factory.command_data_class = Datas::Pipe
16
+ end
17
+
18
+ end # class Popen
19
+
20
+
21
+
22
+ test_section __FILE__ do
23
+
24
+ class PopenTest < Test::Unit::TestCase
25
+
26
+ def setup
27
+ assert_nothing_raised { @runner = Popen.new }
28
+ end
29
+
30
+ def test_0_initialize
31
+ end
32
+
33
+ # FIXME
34
+ def test_simple
35
+ # TempPath.new do |tmp|
36
+ # cmd = %Q[ruby -e "sleep 0.5
37
+ # File.open('#{tmp}', 'w') { |f| f.puts :foo }"]
38
+ # @runner.run(cmd.to_ocmd)
39
+ # assert(tmp.exist?)
40
+ # end
41
+ end
42
+
43
+ end # class PopenTest
44
+
45
+ end
46
+
47
+ end # module Runners
48
+
49
+ end # module ObjectiveCommand
@@ -0,0 +1,227 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners/runner.rb 29674 2006-09-12T21:05:16.387536Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+
10
+ class Runner
11
+
12
+ include Abstract
13
+ include Hookable
14
+ include Hooker
15
+
16
+
17
+ #
18
+ # Accessors
19
+ #
20
+
21
+ attr_accessor :command_data_factory
22
+
23
+
24
+ #
25
+ # Hooks declaration
26
+ #
27
+
28
+ hook_declare :display_command
29
+ hook_declare :data
30
+ hook_declare :fork
31
+ hook_declare :son
32
+ hook_declare :before_open
33
+ hook_declare :before_chdir
34
+ hook_declare :before_exec
35
+ hook_declare :exec
36
+ hook_declare :exception_raised_during_exec
37
+ hook_declare :waitpid
38
+ hook_declare :failure
39
+ hook_declare :abort
40
+ hook_declare :already_killed
41
+ hook_declare :kill
42
+ hook_declare :before_return
43
+
44
+
45
+ #
46
+ # Construction methods.
47
+ #
48
+
49
+ def initialize *opts
50
+ @command_data_factory = Datas::Factory.new
51
+ @open_mode = :w
52
+ hooker_subscribe self
53
+ apply_options(*opts)
54
+ end
55
+
56
+
57
+ def initialize_copy ( copy )
58
+ super
59
+ if defined? @hookers
60
+ @hookers = @hookers.dup
61
+ else
62
+ @hookers = []
63
+ end
64
+ end
65
+
66
+
67
+ #
68
+ # Methods.
69
+ #
70
+
71
+ def run ( aCommand )
72
+ unless aCommand.is_a? Commands::Command
73
+ raise ArgumentError, "Need a OCmd::Commands::Command not #{aCommand}"
74
+ end
75
+
76
+ hook_trigger :display_command, aCommand
77
+
78
+ data = @command_data_factory.create
79
+ begin
80
+ data.open_mode = @open_mode
81
+ data.input = aCommand.input unless aCommand.input.nil?
82
+ data.output = aCommand.output unless aCommand.output.nil?
83
+ data.error = aCommand.error unless aCommand.error.nil?
84
+ hook_trigger :data, aCommand, data
85
+
86
+ hook_trigger :fork, data do
87
+ begin
88
+ hook_trigger :son, aCommand, data
89
+ hook_trigger :before_open, data
90
+ aCommand = aCommand.instanciate_args
91
+ STDIN.reopen(data.input.to_io_for_ocmd) unless data.input.nil?
92
+ STDOUT.reopen(data.output.to_io_for_ocmd) unless data.output.nil?
93
+ STDERR.reopen(data.error.to_io_for_ocmd) unless data.error.nil?
94
+ STDOUT.flush
95
+ STDERR.flush
96
+
97
+ hook_trigger :before_chdir, data
98
+ Dir.chdir(aCommand.dir) unless aCommand.dir.nil?
99
+
100
+ hook_trigger :before_exec, aCommand, data
101
+ hook_trigger :exec, aCommand, data
102
+ rescue Exception => ex
103
+ hook_trigger :exception_raised_during_exec, ex
104
+ end
105
+ end
106
+
107
+ hook_trigger :waitpid, data
108
+ if data.status.nil? or not data.status.success?
109
+ hook_trigger :failure, aCommand, data
110
+ end
111
+
112
+ hook_trigger :before_return, aCommand, data
113
+ rescue Exception => ex
114
+ hook_trigger :abort, data
115
+ raise ex
116
+ end
117
+ data
118
+ end
119
+
120
+
121
+ def make_verbose
122
+ hooker_subscribe VerboseHooker.new
123
+ self
124
+ end
125
+
126
+
127
+ def make_debug
128
+ hooker_subscribe DebugHooker.new
129
+ self
130
+ end
131
+
132
+
133
+ def raise_on_failures
134
+ hooker_subscribe FailureHooker.new
135
+ self
136
+ end
137
+
138
+
139
+ @@running_options =
140
+ {
141
+ :verbose => :make_verbose,
142
+ :v => :make_verbose,
143
+ :raise => :raise_on_failures,
144
+ :r => :raise_on_failures,
145
+ :debug => :make_debug,
146
+ :d => :make_debug,
147
+ :mock => :make_mock,
148
+ :m => :make_mock,
149
+ }
150
+
151
+ def apply_options ( *options )
152
+ options.flatten.each do |k|
153
+ option = @@running_options[k]
154
+ if option.nil?
155
+ raise ArgumentError, "Bad runner option: #{k}"
156
+ else
157
+ send option
158
+ end
159
+ end
160
+ self
161
+ end
162
+
163
+ def fork data, &block
164
+ block.call
165
+ end
166
+
167
+ #
168
+ # Hookers
169
+ #
170
+
171
+ class DebugHooker
172
+ include Hooker
173
+
174
+ def log ( m, *a )
175
+ STDERR.puts
176
+ STDERR.puts "#{m}: #{a.inspect}"
177
+ end
178
+
179
+ hook_default_method :log
180
+
181
+ end # class DebugHooker
182
+
183
+
184
+ class VerboseHooker
185
+ include Hooker
186
+
187
+ def display_command ( m )
188
+ STDERR.puts "Running: #{m.to_a.join(' ')}"
189
+ end
190
+
191
+ end # class VerboseHooker
192
+
193
+
194
+ class FailureHooker
195
+ include Hooker
196
+
197
+ class Error < Exception
198
+ end
199
+
200
+ def failure ( aCommand, data )
201
+ raise Error, { 'reason' => 'Command failed',
202
+ 'command' => aCommand.to_s,
203
+ 'data' => data }.to_yaml
204
+ end
205
+
206
+ end # class FailureHooker
207
+
208
+
209
+ end # class Runner
210
+
211
+
212
+ test_section __FILE__ do
213
+
214
+ class RunnerTest < Test::Unit::TestCase
215
+
216
+ def test_abstract
217
+ if defined? RubyEx
218
+ assert_raise(TypeError) { Runner.new }
219
+ end
220
+ end
221
+
222
+ end # class RunnerTest
223
+ end
224
+
225
+ end # module Runners
226
+
227
+ end # module ObjectiveCommand
@@ -0,0 +1,54 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners/system.rb 23187 2006-03-31T21:59:37.612710Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+
10
+ class WaitpidHooker
11
+ include Hooker
12
+
13
+ def waitpid ( data )
14
+ data.waitpid
15
+ end
16
+ end
17
+
18
+
19
+ # This version wait to reach the end of the command before returns.
20
+ class System < Fork
21
+ make Concrete
22
+
23
+ hooker_subscribe WaitpidHooker.new
24
+
25
+ end # class System
26
+
27
+
28
+ test_section __FILE__ do
29
+
30
+ class SystemTest < Test::Unit::TestCase
31
+
32
+ def setup
33
+ assert_nothing_raised { @runner = System.new }
34
+ end
35
+
36
+ def test_0_initialize
37
+ end
38
+
39
+ def test_simple
40
+ TempPath.new do |tmp|
41
+ cmd = %Q[ruby -e "sleep 0.5
42
+ File.open('#{tmp}', 'w') { |f| f.puts :foo }"]
43
+ @runner.run(cmd.to_ocmd)
44
+ assert(tmp.exist?)
45
+ end
46
+ end
47
+
48
+ end # class SystemTest
49
+
50
+ end
51
+
52
+ end # module Runners
53
+
54
+ end # module ObjectiveCommand
@@ -0,0 +1,11 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/runners.rb 22684 2006-03-12T16:36:11.301558Z pouillar $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Runners
9
+ end # module Runners
10
+
11
+ end # module ObjectiveCommand
@@ -0,0 +1,173 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id$
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Shell
9
+
10
+ module MethodMissing
11
+
12
+ setup do
13
+ cattr_accessor :runner unless respond_to? :runner
14
+ cattr_accessor :shell_options unless respond_to? :shell_options
15
+ end
16
+
17
+ def method_missing meth, *args, &block
18
+ super if block
19
+ meth = meth.to_s
20
+ if meth =~ /^(.*)!$/
21
+ raise 'No runner' unless respond_to? :runner or runner.nil?
22
+ Object.send(:remove_const, :Commands) if defined? ::Commands
23
+ Commands::Command.new($1, *args).run(runner)
24
+ else
25
+ cmd = Commands::Command.new(meth, *args)
26
+ cmd.freeze if shell_options and shell_options[:frozen]
27
+ cmd
28
+ end
29
+ end
30
+
31
+ end # module MethodMissing
32
+
33
+ class Simple
34
+
35
+ include Shell::MethodMissing
36
+ attr_accessor :runner, :shell_options
37
+
38
+ def initialize runner=nil, options=nil, &block
39
+ @runner = runner || OCmd::Runners::System.new
40
+ @shell_options = options || {}
41
+ other_opts = @shell_options.keys - [:frozen]
42
+ @runner.apply_options other_opts
43
+ block.bind(self).call if block
44
+ end
45
+
46
+ end # class Simple
47
+
48
+ module Attribute
49
+
50
+ setup do |*args|
51
+ runner, options = args
52
+ mattr_accessor :ocmd_shell
53
+ self.ocmd_shell = Shell::Simple.new runner, options
54
+ end
55
+
56
+ def shell *args, &block
57
+ local_shell = ocmd_shell
58
+ unless args.empty?
59
+ runner = ocmd_shell.runner
60
+ options = {}
61
+ for arg in args.flatten do
62
+ case arg
63
+ when OCmd::Runners::Runner then runner = arg
64
+ when Hash then options.merge! arg
65
+ when Symbol then options[arg] = true
66
+ else raise ArgumentError, "Bad argument: #{arg}"
67
+ end
68
+ end
69
+ local_shell = Shell::Simple.new runner, options
70
+ end
71
+ if block
72
+ block.bind(local_shell).call
73
+ else
74
+ local_shell
75
+ end
76
+ end
77
+
78
+ def shell! *args, &block
79
+ raise ArgumentError, 'Block needed' if block.nil?
80
+ local_shell = shell(*args)
81
+ block.bind(local_shell).call.run local_shell.runner
82
+ end
83
+
84
+ end # module Attribute
85
+
86
+ end # module Shell
87
+
88
+
89
+ have Shell::Attribute
90
+ module_function :shell, :shell!
91
+
92
+
93
+ test_section __FILE__ do
94
+ OCmd::Runners::Mockable.import!
95
+
96
+ class ShellTest < Test::Unit::TestCase
97
+
98
+ class Foo
99
+ include OCmd::Shell::MethodMissing
100
+ def bar
101
+ cat
102
+ end
103
+ end
104
+ class Bar < Foo
105
+ attr_accessor :runner
106
+ def initialize runner
107
+ @runner = runner
108
+ end
109
+ def bar!
110
+ cat!
111
+ end
112
+ end
113
+ attr_reader :file1, :file2
114
+
115
+ def setup
116
+ @file1 = TempPath.new('file1').overwrite('contents1')
117
+ @file2 = TempPath.new('file2').overwrite('contents2')
118
+ @runner = OCmd::Runners::System.new.make_mock()
119
+ end
120
+
121
+ def assert_shell_cmd! ref, &block
122
+ my = block[]
123
+ assert_kind_of Datas::Data, my
124
+ assert_equal 1, @runner.log.size, 'bad runner log size'
125
+ assert_equal ref, @runner.log.first.to_a
126
+ @runner.log.shift
127
+ end
128
+
129
+ def test_simple_shell
130
+ ref = ['cat', file1.to_s, file2.to_s]
131
+ my = OCmd.shell.cat file1, file2
132
+ assert_equal ref, my.to_a
133
+ end
134
+
135
+ def test_simple_shell_env
136
+ ref = ['cat', file1.to_s, file2.to_s]
137
+ OCmd.shell do
138
+ my = cat file1, file2
139
+ assert_equal ref, my.to_a
140
+ end
141
+ end
142
+
143
+ def test_simple_shell_included
144
+ assert_equal ['cat'], Foo.new.bar.to_a
145
+ end
146
+
147
+ def test_with_run
148
+ ref = ['cat', file1.to_s, file2.to_s]
149
+ assert_shell_cmd!(ref) { OCmd.shell(@runner).cat! file1, file2 }
150
+ t = self
151
+ assert_shell_cmd!(ref) {OCmd.shell(@runner) { cat! t.file1, t.file2 }}
152
+ assert_shell_cmd!(['cat']) { Bar.new(@runner).bar! }
153
+ end
154
+
155
+ def test_with_run2
156
+ ref = ['cat', file1.to_s, file2.to_s]
157
+ t = self
158
+ assert_shell_cmd!(ref) {OCmd.shell!(@runner) { cat t.file1, t.file2 }}
159
+ end
160
+
161
+ def test_frozen_shell
162
+ ref = ['cat', file1.to_s, file2.to_s]
163
+ t = self
164
+ opts = [@runner, { :frozen => true }]
165
+ assert_shell_cmd!(ref) { OCmd.shell!(opts) { cat t.file1, t.file2 } }
166
+ assert_raise(TypeError) { OCmd.shell!(opts) { cat << 'foo' } }
167
+ end
168
+
169
+ end # class ShellTest
170
+
171
+ end
172
+
173
+ end # module ObjectiveCommand
@@ -0,0 +1,10 @@
1
+ # Copyright:: Copyright (c) 2006 Nicolas Pouillard. All rights reserved.
2
+ # Author:: Nicolas Pouillard <nicolas.pouillard@gmail.com>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/version_id.rb 53907 2007-01-13T18:40:33.521685Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ VersionId = Version.parse("dev-ruby/objective_command-0.1")
9
+
10
+ end # module ObjectiveCommand
@@ -0,0 +1,54 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command.rb 53907 2007-01-13T18:40:33.521685Z ertai $
5
+
6
+ require 'pathname'
7
+
8
+ lib = Pathname.new(__FILE__).dirname
9
+ vendor = lib.parent + 'vendor'
10
+ unless defined? CoreEx
11
+ $CORE_EX_VENDORS ||= []
12
+ $CORE_EX_VENDORS << vendor
13
+ file = vendor + 'core_ex' + 'lib' + 'core_ex'
14
+ if file.exist?
15
+ require file.to_s
16
+ else
17
+ require 'rubygems' unless ENV['NO_GEM']
18
+ require_gem 'core_ex'
19
+ require 'core_ex'
20
+ end
21
+ end
22
+ lib.load_path!
23
+
24
+ unless defined? RubyEx
25
+ module Abstract
26
+ end
27
+ module Concrete
28
+ end
29
+ end
30
+
31
+ # Provides an object oriented way to manage, combine and run your commands.
32
+ #
33
+ # Example:
34
+ # require 'rubygems' ; require_gem 'objective_command' ; require 'objective_command'
35
+ # ls, wc, out = 'ls'.to_ocmd, 'wc'.to_ocmd, 'out'.to_path
36
+ #
37
+ # data = ls.system # other runners exist (exec, fork, sh...)
38
+ #
39
+ # p data.status
40
+ # puts data.output.read
41
+ #
42
+ # (ls > STDOUT).system
43
+ #
44
+ # cmd = ls['*.rb'] | wc['-l'] > out
45
+ # cmd.system
46
+ #
47
+ # puts out.read
48
+ module ObjectiveCommand
49
+ end # module ObjectiveCommand
50
+
51
+ OCmd = ObjectiveCommand unless defined? OCmd and OCmd == ObjectiveCommand
52
+ Hooker.import!
53
+ OCmd::Helpers.import!
54
+
@@ -0,0 +1,10 @@
1
+ ---
2
+
3
+ ObjectiveCommand Main Test Suite: !S::Iterate
4
+
5
+ over: !pathlist <<pwd>>/(*-suite.yml)
6
+ iter: [it_file, it_name]
7
+
8
+ test:
9
+ <<it_name>>: !S::Import
10
+ import: <<it_file>>