shellany 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 68dc8a476d023b6991ff72a15f075abfc03ed915
4
+ data.tar.gz: 56aa1c504f9fce4486a246188b24122910129fe6
5
+ SHA512:
6
+ metadata.gz: 195ad943cf64c1c16071ebc9ec28f58fca1d5aaf88f7b0f672ee2d1f0a7863147c31abaa67b1ae1bcc6e28c6843e02cacf7dcea39adbe7231fd318bc8d02f512
7
+ data.tar.gz: 896b8ff16cb676c696e173fbe2bf950004b6fd44a51aa1d97e974401e5195742d8b034adcfeae7b8c82e936362428aa8c5046a1827f5350d3f098ebc5190d3cf
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ bundler_args: --without development
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.5
7
+ - ruby-head
8
+ - jruby
9
+ - rbx-2
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: rbx
13
+ - rvm: jruby
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in shellany.gemspec
4
+ gemspec development_group: :gem_build_tools
5
+
6
+ gem "rake", "~> 10.0"
7
+ gem 'nenv', "~> 0.1"
8
+
9
+ group :test do
10
+ gem "rspec", "~> 3.1"
11
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Cezary Baginski
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # Shellany
2
+
3
+ Shellany captures command output.
4
+
5
+ ## Features:
6
+
7
+ - portability (should work on recent JRuby versions)
8
+ - capturing stdout, stderr in a convenient way
9
+ - returning the result in a convenient way
10
+ - detecting if a shell is needed (though incomplete/primitive implementation)
11
+ - prevents running the same command multiple times
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'shellany'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install shellany
28
+
29
+ ## Usage
30
+
31
+ Basic usage:
32
+
33
+ ```ruby
34
+ require 'shellany/sheller'
35
+
36
+ Shellany::Sheller.stdout("echo abc") # => "abc"
37
+ Shellany::Sheller.stderr("touch /foo") # => "touch: cannot touch ‘/aef’: Permission denied
38
+ Shellany::Sheller.run("false") # => false
39
+ Shellany::Sheller.system("clear") # => clears screen (no capture done)
40
+ ```
41
+
42
+ Using Sheller object:
43
+
44
+ ```ruby
45
+ require 'shellany/sheller'
46
+
47
+ sh = Shellany::Sheller.new('grep /etc/passed|tail -n 1') # does nothing
48
+
49
+ sh.stdout # shows output (runs the command since it wasn't run)
50
+ sh.stderr # shows stderr (does not run the command)
51
+ sh.ok? # returns true if exit code was zero (does not run the command)
52
+ ```
53
+
54
+ ## Project status
55
+
56
+ Only developed enough for Guard to run, though pull requests are more than welcome.
57
+
58
+ Especially for:
59
+
60
+ - better API
61
+ - better shell detection code
62
+ - better support for various system() arguments
63
+ - better support for redireciton handling
64
+ - better support for shell detection (e.g. Windows)
65
+
66
+ ## Contributing
67
+
68
+ 1. Fork it ( https://github.com/[my-github-username]/shellany/fork )
69
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
70
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 4. Push to the branch (`git push origin my-new-feature`)
72
+ 5. Create a new Pull Request
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'nenv'
4
+
5
+ default_tasks = []
6
+
7
+ require 'rspec/core/rake_task'
8
+ default_tasks << RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.verbose = Nenv.ci?
10
+ end
11
+
12
+ task default: default_tasks.map(&:name)
13
+
@@ -0,0 +1,5 @@
1
+ require "shellany/version"
2
+
3
+ module Shellany
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,144 @@
1
+ require "open3"
2
+
3
+ module Shellany
4
+ # The Guard sheller abstract the actual subshell
5
+ # calls and allow easier stubbing.
6
+ #
7
+ class Sheller
8
+ attr_reader :status
9
+
10
+ # Creates a new Guard::Sheller object.
11
+ #
12
+ # @param [String] args a command to run in a subshell
13
+ # @param [Array<String>] args an array of command parts to run in a subshell
14
+ # @param [*String] args a list of command parts to run in a subshell
15
+ #
16
+ def initialize(*args)
17
+ fail ArgumentError, "no command given" if args.empty?
18
+ @command = args
19
+ @ran = false
20
+ end
21
+
22
+ # Shortcut for new(command).run
23
+ #
24
+ def self.run(*args)
25
+ new(*args).run
26
+ end
27
+
28
+ # Shortcut for new(command).run.stdout
29
+ #
30
+ def self.stdout(*args)
31
+ new(*args).stdout
32
+ end
33
+
34
+ # Shortcut for new(command).run.stderr
35
+ #
36
+ def self.stderr(*args)
37
+ new(*args).stderr
38
+ end
39
+
40
+ # Runs the command.
41
+ #
42
+ # @return [Boolean] whether or not the command succeeded.
43
+ #
44
+ def run
45
+ unless ran?
46
+ status, output, errors = self.class._system_with_capture(*@command)
47
+ @ran = true
48
+ @stdout = output
49
+ @stderr = errors
50
+ @status = status
51
+ end
52
+
53
+ ok?
54
+ end
55
+
56
+ # Returns true if the command has already been run, false otherwise.
57
+ #
58
+ # @return [Boolean] whether or not the command has already been run
59
+ #
60
+ def ran?
61
+ @ran
62
+ end
63
+
64
+ # Returns true if the command succeeded, false otherwise.
65
+ #
66
+ # @return [Boolean] whether or not the command succeeded
67
+ #
68
+ def ok?
69
+ run unless ran?
70
+
71
+ @status && @status.success?
72
+ end
73
+
74
+ # Returns the command's output.
75
+ #
76
+ # @return [String] the command output
77
+ #
78
+ def stdout
79
+ run unless ran?
80
+
81
+ @stdout
82
+ end
83
+
84
+ # Returns the command's error output.
85
+ #
86
+ # @return [String] the command output
87
+ #
88
+ def stderr
89
+ run unless ran?
90
+
91
+ @stderr
92
+ end
93
+
94
+ # No output capturing
95
+ #
96
+ # NOTE: `$stdout.puts system('cls')` on Windows won't work like
97
+ # it does for on systems with ansi terminals, so we need to be
98
+ # able to call Kernel.system directly.
99
+ def self.system(*args)
100
+ _system_with_no_capture(*args)
101
+ end
102
+
103
+ def self._system_with_no_capture(*args)
104
+ Kernel.system(*args)
105
+ result = $?
106
+ errors = (result == 0) || "Guard failed to run: #{args.inspect}"
107
+ [result, nil, errors]
108
+ end
109
+
110
+ def self._system_with_capture(*args)
111
+ # We use popen3, because it started working on recent versions
112
+ # of JRuby, while JRuby doesn't handle options to Kernel.system
113
+ args = _shellize_if_needed(args)
114
+
115
+ stdout, stderr, status = nil
116
+ Open3.popen3(*args) do |_stdin, _stdout, _stderr, _thr|
117
+ stdout = _stdout.read
118
+ stderr = _stderr.read
119
+ status = _thr.value
120
+ end
121
+
122
+ [status, stdout, stderr]
123
+ rescue Errno::ENOENT, IOError => e
124
+ [nil, nil, "Guard::Sheller failed (#{e.inspect})"]
125
+ end
126
+
127
+ # Only needed on JRUBY, because MRI properly detects ';' and metachars
128
+ def self._shellize_if_needed(args)
129
+ return args unless RUBY_PLATFORM == "java"
130
+ return args unless args.size == 1
131
+ return args unless /[;<>]/ =~ args.first
132
+
133
+ # NOTE: Sheller was originally meant for Guard (which basically only uses
134
+ # UNIX commands anyway) and JRuby doesn't support options to
135
+ # Kernel.system (and doesn't automatically shell when there's a
136
+ # metacharacter in the command).
137
+ #
138
+ # So ... I'm assuming /bin/sh exists - if not, PRs are welcome,
139
+ # because I have no clue what to do if /bin/sh doesn't exist.
140
+ # (use ENV["RUBYSHELL"] ? Detect cmd.exe ?)
141
+ ["/bin/sh", "-c", args.first]
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,3 @@
1
+ module Shellany
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'shellany/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "shellany"
8
+ spec.version = Shellany::VERSION
9
+ spec.authors = ["Cezary Baginski"]
10
+ spec.email = ["cezary@chronomantic.net"]
11
+ spec.summary = %q{Simple, somewhat portable command capturing}
12
+ spec.description = %q{MRI+JRuby compatible command output capturing}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ end
@@ -0,0 +1,141 @@
1
+ require "shellany/sheller"
2
+
3
+ RSpec.describe Shellany::Sheller, :sheller_specs do
4
+ before do
5
+ allow(Kernel).to receive(:system) do |args|
6
+ fail "Stub called with: #{args.inspect}"
7
+ end
8
+ end
9
+
10
+ subject { described_class }
11
+
12
+ context "without a command" do
13
+ [:new, :run, :stdout, :stderr].each do |meth|
14
+ describe ".#{meth}" do
15
+ specify do
16
+ expect { subject.send(meth) }.
17
+ to raise_error ArgumentError, "no command given"
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ context "with shell (string) cmd returning success" do
24
+ let(:cmd) { "ls -l" }
25
+ let(:output) { "foo.rb\n" }
26
+ let(:errors) { "" }
27
+ let(:result) do
28
+ [instance_double(Process::Status, success?: true), output, errors]
29
+ end
30
+
31
+ context "when constructed with a cmd" do
32
+ subject { described_class.new(cmd) }
33
+
34
+ describe "#run" do
35
+ it "runs the command given to constructor" do
36
+ expect(described_class).to receive(:_system_with_capture).
37
+ with(cmd).and_return(result)
38
+ subject.run
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ context "with array cmd returning success" do
45
+ let(:cmd) { %w(ls -l) }
46
+ let(:output) { "foo.rb\n" }
47
+ let(:errors) { "" }
48
+ let(:result) do
49
+ [instance_double(Process::Status, success?: true), output, errors]
50
+ end
51
+
52
+ describe "when used as class" do
53
+ describe ".run" do
54
+ it "runs the given command" do
55
+ expect(described_class).to receive(:_system_with_capture).
56
+ with(*cmd) { result }
57
+ subject.run(*cmd)
58
+ end
59
+ end
60
+
61
+ describe ".new" do
62
+ it "does not run anything" do
63
+ expect(described_class).to_not receive(:_system_with_capture)
64
+ subject
65
+ end
66
+ end
67
+
68
+ describe ".stdout" do
69
+ before do
70
+ allow(described_class).to receive(:_system_with_capture).
71
+ with(*cmd) { result }
72
+ end
73
+
74
+ it "runs command and returns output" do
75
+ expect(subject.stdout(*cmd)).to eq "foo.rb\n"
76
+ end
77
+ end
78
+
79
+ describe ".stderr" do
80
+ before do
81
+ allow(described_class).to receive(:_system_with_capture).
82
+ with(*cmd) { result }
83
+ end
84
+
85
+ it "runs command and returns errors" do
86
+ expect(subject.stderr(*cmd)).to eq ""
87
+ end
88
+ end
89
+ end
90
+
91
+ context "when constructed with a cmd" do
92
+ subject { described_class.new(*cmd) }
93
+
94
+ it "does not run anything" do
95
+ expect(described_class).to_not receive(:_system_with_capture)
96
+ subject
97
+ end
98
+
99
+ describe "#run" do
100
+ it "runs the command given to constructor" do
101
+ expect(described_class).to receive(:_system_with_capture).
102
+ with(*cmd) { result }
103
+ subject.run
104
+ end
105
+ end
106
+
107
+ describe "#stdout" do
108
+ before do
109
+ allow(described_class).to receive(:_system_with_capture).
110
+ with(*cmd) { result }
111
+ end
112
+
113
+ it "runs command and returns output" do
114
+ expect(subject.stdout).to eq "foo.rb\n"
115
+ end
116
+ end
117
+
118
+ describe "#stderr" do
119
+ before do
120
+ allow(described_class).to receive(:_system_with_capture).
121
+ with(*cmd) { result }
122
+ end
123
+
124
+ it "runs command and returns output" do
125
+ expect(subject.stderr).to eq ""
126
+ end
127
+ end
128
+
129
+ describe "#ok?" do
130
+ before do
131
+ allow(described_class).to receive(:_system_with_capture).
132
+ with(*cmd) { result }
133
+ end
134
+
135
+ it "runs command and returns output" do
136
+ expect(subject).to be_ok
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.describe Shellany do
2
+ it 'has a version number' do
3
+ expect(Shellany::VERSION).not_to be nil
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4
+ end
5
+
6
+ config.mock_with :rspec do |mocks|
7
+ mocks.verify_partial_doubles = true
8
+ end
9
+
10
+ config.filter_run :focus
11
+ config.run_all_when_everything_filtered = true
12
+
13
+ config.disable_monkey_patching!
14
+
15
+ config.warnings = true
16
+
17
+ config.default_formatter = 'doc' if config.files_to_run.one?
18
+
19
+ # config.profile_examples = 10
20
+
21
+ config.order = :random
22
+
23
+ Kernel.srand config.seed
24
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shellany
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Cezary Baginski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ description: MRI+JRuby compatible command output capturing
28
+ email:
29
+ - cezary@chronomantic.net
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".travis.yml"
37
+ - Gemfile
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ - lib/shellany.rb
42
+ - lib/shellany/sheller.rb
43
+ - lib/shellany/version.rb
44
+ - shellany.gemspec
45
+ - spec/lib/shellany/sheller_spec.rb
46
+ - spec/shellany_spec.rb
47
+ - spec/spec_helper.rb
48
+ homepage: ''
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.3
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Simple, somewhat portable command capturing
72
+ test_files:
73
+ - spec/lib/shellany/sheller_spec.rb
74
+ - spec/shellany_spec.rb
75
+ - spec/spec_helper.rb