sfl 1.2 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/CHANGELOG.md +41 -0
  2. data/README.md +1 -0
  3. data/Rakefile +16 -0
  4. data/lib/sfl.rb +56 -29
  5. data/sfl.gemspec +28 -0
  6. data/spec/sfl_spec.rb +177 -0
  7. metadata +36 -8
@@ -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
@@ -32,6 +32,7 @@ If your ruby is 1.9, `require 'sfl'` doesn't do anything. If your ruby is 1.8, t
32
32
 
33
33
  ## Supports
34
34
 
35
+ * (On MacOS) MRI 1.8.6, 1.8.7, 1.9.1, 1.9.2-rc2
35
36
  * (On UNIX) MRI 1.8.6, 1.8.7, 1.9.1, 1.9.2pre
36
37
  * (On Windows) MRI 1.9.1, 1.9.2pre
37
38
 
@@ -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
- right =
78
- case v
79
- when Symbol # :out or :err
80
- mapping[v]
81
- when String # filename
82
- [File, :open, v, 'w']
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| mapping[i] }
95
- [
96
- [left1, :reopen, right],
97
- [left2, :reopen, left1],
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
- def spawn(*x)
153
- SFL.new(*x).run
154
- end
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
- SFL.new(*x).run
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'
@@ -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
@@ -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
- version: "1.2"
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: 2010-03-11 00:00:00 -08:00
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"