sfl 1.2 → 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/CHANGELOG.md +41 -0
- data/README.md +1 -0
- data/Rakefile +16 -0
- data/lib/sfl.rb +56 -29
- data/sfl.gemspec +28 -0
- data/spec/sfl_spec.rb +177 -0
- metadata +36 -8
data/CHANGELOG.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# 2.0
|
2
|
+
|
3
|
+
Version 2.0 is done completely by Bernard Lambeau. Thanks!
|
4
|
+
|
5
|
+
* Enhancements
|
6
|
+
|
7
|
+
* Implemented :in redirection, i.e. spawn("...", :in => ...)
|
8
|
+
* Implemented :close redirection, i.e. spawn("...", :out/err/in => :close)
|
9
|
+
* Removed spawn override if ruby version is >= 1.9
|
10
|
+
* Project structure enhanced with Rakefile and SFL::VERSION
|
11
|
+
* Spec suite runs against Kernel.spawn to ensure comptability with native spawn in 1.9
|
12
|
+
|
13
|
+
* Bugfixes
|
14
|
+
|
15
|
+
* Fix the spec suite for ruby version 1.9.2
|
16
|
+
|
17
|
+
* Known bugs
|
18
|
+
|
19
|
+
* The spec suite may fail under ruby 1.9.1, due to ruby bugs on some spawn redirect options
|
20
|
+
|
21
|
+
# 1.2
|
22
|
+
|
23
|
+
* Enhancements
|
24
|
+
|
25
|
+
* Added support for quoted command arguments and spaces
|
26
|
+
* Defined spawn even if the ruby version is 1.9
|
27
|
+
|
28
|
+
# 1.1
|
29
|
+
|
30
|
+
* Enhancements
|
31
|
+
|
32
|
+
* Added Process.spawn in addition to Kernel.spawn
|
33
|
+
* Added support for Ruby 1.8.6
|
34
|
+
|
35
|
+
# 1.0
|
36
|
+
|
37
|
+
* Enhancements
|
38
|
+
|
39
|
+
* Birthday
|
40
|
+
|
41
|
+
|
data/README.md
CHANGED
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rspec/core/rake_task"
|
2
|
+
require "rake/gempackagetask"
|
3
|
+
|
4
|
+
task :default => :spec
|
5
|
+
|
6
|
+
desc "Run all examples"
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
t.rspec_opts = %w[--color]
|
9
|
+
t.verbose = false
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Create the .gem package"
|
13
|
+
$gemspec = eval("#{File.read('sfl.gemspec')}")
|
14
|
+
Rake::GemPackageTask.new($gemspec) do |pkg|
|
15
|
+
pkg.need_tar = true
|
16
|
+
end
|
data/lib/sfl.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
class SFL
|
2
|
+
VERSION = "2.0".freeze
|
3
|
+
|
2
4
|
attr_reader :command, :environment, :argument, :option
|
3
5
|
|
4
6
|
# SFL.new('ls', '-a') becomes
|
@@ -63,39 +65,62 @@ class SFL
|
|
63
65
|
end
|
64
66
|
|
65
67
|
class << self
|
68
|
+
REDIRECTION_MAPPING = {
|
69
|
+
:in => STDIN,
|
70
|
+
:out => STDOUT,
|
71
|
+
:err => STDERR,
|
72
|
+
}
|
73
|
+
|
74
|
+
def redirection_ast(v, what_for = :out)
|
75
|
+
case v
|
76
|
+
when Integer
|
77
|
+
raise NotImplementedError, "Redirection to integer FD not yet implemented"
|
78
|
+
when :close
|
79
|
+
nil
|
80
|
+
when :in, :out, :err
|
81
|
+
REDIRECTION_MAPPING[v]
|
82
|
+
when String # filename
|
83
|
+
[File, :open, v, (what_for == :in ? 'r' : 'w')]
|
84
|
+
when Array # filename with option
|
85
|
+
[File, :open, v[0], v[1]]
|
86
|
+
when IO
|
87
|
+
v
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
66
91
|
def option_parser(hash)
|
67
|
-
mapping = {
|
68
|
-
:out => STDOUT,
|
69
|
-
:err => STDERR,
|
70
|
-
}
|
71
92
|
result = []
|
93
|
+
|
94
|
+
# changing dir has high priority
|
72
95
|
chdir = hash.delete(:chdir)
|
73
96
|
if chdir
|
74
97
|
result[0] = [Dir, :chdir, chdir]
|
75
98
|
end
|
99
|
+
|
100
|
+
# other options
|
76
101
|
result += hash.map {|k, v|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
[
|
83
|
-
when Array # filename with option
|
84
|
-
[File, :open, v[0], v[1]]
|
85
|
-
when IO
|
86
|
-
v
|
102
|
+
case k
|
103
|
+
when :in, :out, :err
|
104
|
+
if right = redirection_ast(v, k)
|
105
|
+
[[REDIRECTION_MAPPING[k], :reopen, right]]
|
106
|
+
else
|
107
|
+
[[REDIRECTION_MAPPING[k], :close]]
|
87
108
|
end
|
88
|
-
|
89
|
-
if Symbol === k
|
90
|
-
[[mapping[k], :reopen, right]]
|
91
|
-
else
|
109
|
+
when Array
|
92
110
|
# assuming k is like [:out, :err]
|
93
|
-
raise if k.size > 2
|
94
|
-
left1, left2 = *k.map {|i|
|
95
|
-
|
96
|
-
[
|
97
|
-
|
98
|
-
|
111
|
+
raise NotImplementedError if k.size > 2
|
112
|
+
left1, left2 = *k.map {|i| REDIRECTION_MAPPING[i] }
|
113
|
+
if right = redirection_ast(v)
|
114
|
+
[
|
115
|
+
[left1, :reopen, right],
|
116
|
+
[left2, :reopen, left1],
|
117
|
+
]
|
118
|
+
else
|
119
|
+
[
|
120
|
+
[left1, :close],
|
121
|
+
[left2, :close],
|
122
|
+
]
|
123
|
+
end
|
99
124
|
end
|
100
125
|
}.flatten(1)
|
101
126
|
result
|
@@ -149,12 +174,14 @@ class SFL
|
|
149
174
|
end
|
150
175
|
end
|
151
176
|
|
152
|
-
|
153
|
-
|
154
|
-
|
177
|
+
if RUBY_VERSION <= "1.9"
|
178
|
+
def Kernel.spawn(*x)
|
179
|
+
SFL.new(*x).run
|
180
|
+
end
|
155
181
|
|
156
|
-
def Process.spawn(*x)
|
157
|
-
|
182
|
+
def Process.spawn(*x)
|
183
|
+
SFL.new(*x).run
|
184
|
+
end
|
158
185
|
end
|
159
186
|
|
160
187
|
if RUBY_VERSION <= '1.8.6'
|
data/sfl.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path('../lib/sfl', __FILE__)
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = %q{sfl}
|
4
|
+
s.version = SFL::VERSION.dup
|
5
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
6
|
+
|
7
|
+
s.summary = %q{Spawn For Ruby 1.8}
|
8
|
+
s.description = %q{Spawn For Ruby 1.8}
|
9
|
+
|
10
|
+
s.author = 'ujihisa'
|
11
|
+
s.email = %q{ujihisa at gmail.com}
|
12
|
+
|
13
|
+
s.files =
|
14
|
+
Dir['lib/**/*'] +
|
15
|
+
Dir['spec/**/*'] +
|
16
|
+
%w{ sfl.gemspec Rakefile README.md CHANGELOG.md }
|
17
|
+
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.executables = []
|
20
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
21
|
+
|
22
|
+
s.homepage = %q{https://github.com/ujihisa/spawn-for-legacy}
|
23
|
+
|
24
|
+
s.extra_rdoc_files = %w< README.md >
|
25
|
+
|
26
|
+
s.add_development_dependency('rake')
|
27
|
+
s.add_development_dependency('rspec', ">= 2.4.0")
|
28
|
+
end
|
data/spec/sfl_spec.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'sfl'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
describe 'SFL.new' do
|
6
|
+
context 'with argument "ls", "."' do
|
7
|
+
subject { SFL.new('ls', '.') }
|
8
|
+
it { should == SFL.new('ls', '.') }
|
9
|
+
it { should == SFL.new(['ls', 'ls'], '.') }
|
10
|
+
it { should_not == SFL.new('ls', 'aaaaa') }
|
11
|
+
it { should == SFL.new({}, 'ls', '.') }
|
12
|
+
it { should == SFL.new({}, 'ls', '.', {}) }
|
13
|
+
it { should_not == SFL.new({1=>2}, 'ls', '.', {}) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with argument {"A" => "1"}, ["ls", "dir"]' do
|
17
|
+
subject { SFL.new({"A" => "1"}, ['ls', 'dir']) }
|
18
|
+
it { should == SFL.new({"A" => "1"}, ['ls', 'dir']) }
|
19
|
+
it { should == SFL.new({"A" => "1"}, ['ls', 'dir'], {}) }
|
20
|
+
it { should_not == SFL.new({"A" => "1"}, 'ls', 'dir', {}) }
|
21
|
+
it { should_not == SFL.new(['ls', 'ls']) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with argument {"A" => "a"}, "ls", ".", {:out => :err}' do
|
25
|
+
subject { SFL.new({"A" => "a"}, "ls", ".", {:out => :err}) }
|
26
|
+
it { should == SFL.new({"A" => "a"}, ['ls', 'ls'], '.', {:out => :err}) }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with argument "ls ."' do
|
30
|
+
subject { SFL.new('ls .') }
|
31
|
+
it { should == SFL.new('ls .') }
|
32
|
+
it { should == SFL.new('ls', '.') }
|
33
|
+
it { should == SFL.new(['ls', 'ls'], '.') }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'Kernel.spawn' do
|
38
|
+
def mocker(code)
|
39
|
+
sfl_expanded = File.expand_path('../../lib/sfl', __FILE__)
|
40
|
+
rubyfile = File.expand_path('../mocker.rb', __FILE__) # Tempfile.new('-').path
|
41
|
+
File.open(rubyfile, 'w') {|io| io.puts <<-"EOF"
|
42
|
+
require '#{sfl_expanded}'
|
43
|
+
#{code}
|
44
|
+
EOF
|
45
|
+
}
|
46
|
+
resultfile = File.expand_path('../mocker_output.txt', __FILE__) # Tempfile.new('-').path
|
47
|
+
system "ruby #{rubyfile} > #{resultfile}"
|
48
|
+
File.read(resultfile)
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with command "ls", "."' do
|
52
|
+
it 'outputs the result of "ls ." on stdout' do
|
53
|
+
mocker(%q|
|
54
|
+
pid = Kernel.spawn('ls', '.')
|
55
|
+
Process.wait(pid)
|
56
|
+
|).should == `ls .`
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The following test is unsound and lead to spec
|
61
|
+
# failures under specific rubies...
|
62
|
+
#
|
63
|
+
# it 'is asynchronous' do
|
64
|
+
# mocker(%q|
|
65
|
+
# Kernel.spawn('sh', '-c', 'echo 1; sleep 1; echo 2')
|
66
|
+
# sleep 0.1
|
67
|
+
# |).should == "1\n"
|
68
|
+
# end
|
69
|
+
|
70
|
+
context 'with environment {"A" => "1"}' do
|
71
|
+
it 'outputs with given ENV "1"' do
|
72
|
+
mocker(%q|
|
73
|
+
pid = Kernel.spawn({'A' => 'a'}, 'ruby', '-e', 'p ENV["A"]')
|
74
|
+
Process.wait(pid)
|
75
|
+
|).should == "a".inspect + "\n"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with option {:err => :out}' do
|
80
|
+
it 'outputs with given ENV "1"' do
|
81
|
+
mocker(
|
82
|
+
%q|
|
83
|
+
pid = Kernel.spawn('ls', 'nonexistfile', {:err => :out})
|
84
|
+
Process.wait(pid)
|
85
|
+
|).should =~ /^ls:/
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with option {:out => "/tmp/aaaaaaa.txt"}' do
|
90
|
+
it 'outputs with given ENV "1"' do
|
91
|
+
mocker(
|
92
|
+
%q|
|
93
|
+
pid = Kernel.spawn('echo', '123', {:out => "/tmp/aaaaaaa.txt"})
|
94
|
+
Process.wait(pid)
|
95
|
+
|).should == ""
|
96
|
+
File.read('/tmp/aaaaaaa.txt').should == "123\n"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with option {:out => :close, :err => :close}' do
|
101
|
+
it 'outputs nothing at all' do
|
102
|
+
mocker(
|
103
|
+
%q|
|
104
|
+
pid = Kernel.spawn('echo', '123', {:out => :close, :err => :close})
|
105
|
+
Process.wait(pid)
|
106
|
+
|).should == ""
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with option {[:out, :err] => :close}' do
|
111
|
+
it 'outputs nothing at all' do
|
112
|
+
mocker(
|
113
|
+
%q|
|
114
|
+
pid = Kernel.spawn('echo', '123', {[:out, :err] => :close})
|
115
|
+
Process.wait(pid)
|
116
|
+
|).should == ""
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with option {:in => "README.md"}' do
|
121
|
+
it 'outputs README.md' do
|
122
|
+
mocker(
|
123
|
+
%q|
|
124
|
+
pid = Kernel.spawn('cat', {:in => File.expand_path('../../README.md', __FILE__)})
|
125
|
+
Process.wait(pid)
|
126
|
+
|).should =~ /Spawn for Legacy/
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'SFL.option_parser' do
|
132
|
+
it 'with symbol arguments' do
|
133
|
+
SFL.option_parser({:err => :out}).
|
134
|
+
should == [[STDERR, :reopen, STDOUT]]
|
135
|
+
|
136
|
+
SFL.option_parser({:err => 'filename'}).
|
137
|
+
should == [[STDERR, :reopen, [File, :open, 'filename', 'w']]]
|
138
|
+
|
139
|
+
o = File.open('/dev/null', 'w')
|
140
|
+
SFL.option_parser({:out => o}).
|
141
|
+
should == [[STDOUT, :reopen, o]]
|
142
|
+
|
143
|
+
SFL.option_parser({[:out, :err] => 'filename'}).
|
144
|
+
should == [
|
145
|
+
[STDOUT, :reopen, [File, :open, 'filename', 'w'] ],
|
146
|
+
[STDERR, :reopen, STDOUT]
|
147
|
+
]
|
148
|
+
|
149
|
+
SFL.option_parser({:chdir => 'aaa'}).
|
150
|
+
should == [[Dir, :chdir, 'aaa']]
|
151
|
+
|
152
|
+
SFL.option_parser({:err => :out, :chdir => 'aaa'}).
|
153
|
+
should == [
|
154
|
+
[Dir, :chdir, 'aaa'],
|
155
|
+
[STDERR, :reopen, STDOUT]
|
156
|
+
]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'SFL.parse_command_with_arg' do
|
161
|
+
context 'ls .' do
|
162
|
+
subject { SFL.parse_command_with_arg('ls .') }
|
163
|
+
it { should == ['ls', '.'] }
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'ls " "' do
|
167
|
+
subject { SFL.parse_command_with_arg('ls " "') }
|
168
|
+
it { should == ['ls', ' '] }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe 'spawn()' do
|
173
|
+
it 'exists' do
|
174
|
+
Kernel.should be_respond_to(:spawn, true)
|
175
|
+
Process.should be_respond_to(:spawn, true)
|
176
|
+
end
|
177
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sfl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 11
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
|
-
- 1
|
8
6
|
- 2
|
9
|
-
|
7
|
+
- 0
|
8
|
+
version: "2.0"
|
10
9
|
platform: ruby
|
11
10
|
authors:
|
12
11
|
- ujihisa
|
@@ -14,10 +13,37 @@ autorequire:
|
|
14
13
|
bindir: bin
|
15
14
|
cert_chain: []
|
16
15
|
|
17
|
-
date:
|
16
|
+
date: 2011-01-19 00:00:00 -08:00
|
18
17
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: rake
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rspec
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 2
|
42
|
+
- 4
|
43
|
+
- 0
|
44
|
+
version: 2.4.0
|
45
|
+
type: :development
|
46
|
+
version_requirements: *id002
|
21
47
|
description: Spawn For Ruby 1.8
|
22
48
|
email: ujihisa at gmail.com
|
23
49
|
executables: []
|
@@ -28,7 +54,11 @@ extra_rdoc_files:
|
|
28
54
|
- README.md
|
29
55
|
files:
|
30
56
|
- lib/sfl.rb
|
57
|
+
- spec/sfl_spec.rb
|
58
|
+
- sfl.gemspec
|
59
|
+
- Rakefile
|
31
60
|
- README.md
|
61
|
+
- CHANGELOG.md
|
32
62
|
has_rdoc: true
|
33
63
|
homepage: https://github.com/ujihisa/spawn-for-legacy
|
34
64
|
licenses: []
|
@@ -43,7 +73,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
73
|
requirements:
|
44
74
|
- - ">="
|
45
75
|
- !ruby/object:Gem::Version
|
46
|
-
hash: 3
|
47
76
|
segments:
|
48
77
|
- 0
|
49
78
|
version: "0"
|
@@ -52,7 +81,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
81
|
requirements:
|
53
82
|
- - ">="
|
54
83
|
- !ruby/object:Gem::Version
|
55
|
-
hash: 3
|
56
84
|
segments:
|
57
85
|
- 0
|
58
86
|
version: "0"
|