Class: Shellany::Sheller

Inherits:
Object
  • Object
show all
Defined in:
lib/shellany/sheller.rb

Overview

Sheller abstracts the actual subshell calls and allow easier stubbing.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Sheller

Creates a new Shellany::Sheller object.


16
17
18
19
20
# File 'lib/shellany/sheller.rb', line 16

def initialize(*args)
  fail ArgumentError, "no command given" if args.empty?
  @command = args
  @ran = false
end

Instance Attribute Details

#statusObject (readonly)

Returns the value of attribute status


8
9
10
# File 'lib/shellany/sheller.rb', line 8

def status
  @status
end

Class Method Details

._shellize_if_needed(args) ⇒ Object

Only needed on JRUBY, because MRI properly detects ';' and metachars


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/shellany/sheller.rb', line 125

def self._shellize_if_needed(args)
  return args unless RUBY_PLATFORM == "java"
  return args unless args.size == 1
  return args unless /[;<>]/ =~ args.first

  # NOTE: Sheller was originally meant for Guard (which basically only uses
  # UNIX commands anyway) and JRuby doesn't support options to
  # Kernel.system (and doesn't automatically shell when there's a
  # metacharacter in the command).
  #
  # So ... I'm assuming /bin/sh exists - if not, PRs are welcome,
  # because I have no clue what to do if /bin/sh doesn't exist.
  # (use ENV["RUBYSHELL"] ? Detect cmd.exe ?)
  ["/bin/sh", "-c", args.first]
end

._system_with_capture(*args) ⇒ Object


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/shellany/sheller.rb', line 107

def self._system_with_capture(*args)
  # We use popen3, because it started working on recent versions
  # of JRuby, while JRuby doesn't handle options to Kernel.system
  args = _shellize_if_needed(args)

  stdout, stderr, status = nil
  Open3.popen3(*args) do |_stdin, _stdout, _stderr, _thr|
    stdout = _stdout.read
    stderr = _stderr.read
    status = _thr.value
  end

  [status, stdout, stderr]
rescue Errno::ENOENT, IOError => e
  [nil, nil, "Shellany::Sheller failed (#{e.inspect})"]
end

._system_with_no_capture(*args) ⇒ Object


100
101
102
103
104
105
# File 'lib/shellany/sheller.rb', line 100

def self._system_with_no_capture(*args)
  Kernel.system(*args)
  result = $?
  errors = (result == 0) || "Shellany::Sheller failed to run: #{args.inspect}"
  [result, nil, errors]
end

.run(*args) ⇒ Object

Shortcut for new(command).run


24
25
26
# File 'lib/shellany/sheller.rb', line 24

def self.run(*args)
  new(*args).run
end

.stderr(*args) ⇒ Object

Shortcut for new(command).run.stderr


36
37
38
# File 'lib/shellany/sheller.rb', line 36

def self.stderr(*args)
  new(*args).stderr
end

.stdout(*args) ⇒ Object

Shortcut for new(command).run.stdout


30
31
32
# File 'lib/shellany/sheller.rb', line 30

def self.stdout(*args)
  new(*args).stdout
end

.system(*args) ⇒ Object

No output capturing

NOTE: `$stdout.puts system('cls')` on Windows won't work like it does for on systems with ansi terminals, so we need to be able to call Kernel.system directly.


96
97
98
# File 'lib/shellany/sheller.rb', line 96

def self.system(*args)
  _system_with_no_capture(*args)
end

Instance Method Details

#ok?Boolean

Returns true if the command succeeded, false otherwise.


65
66
67
68
69
# File 'lib/shellany/sheller.rb', line 65

def ok?
  run unless ran?

  @status && @status.success?
end

#ran?Boolean

Returns true if the command has already been run, false otherwise.


57
58
59
# File 'lib/shellany/sheller.rb', line 57

def ran?
  @ran
end

#runBoolean

Runs the command.


44
45
46
47
48
49
50
51
# File 'lib/shellany/sheller.rb', line 44

def run
  unless ran?
    @status, @stdout, @stderr = self.class._system_with_capture(*@command)
    @ran = true
  end

  ok?
end

#stderrString

Returns the command's error output.


85
86
87
88
89
# File 'lib/shellany/sheller.rb', line 85

def stderr
  run unless ran?

  @stderr
end

#stdoutString

Returns the command's output.


75
76
77
78
79
# File 'lib/shellany/sheller.rb', line 75

def stdout
  run unless ran?

  @stdout
end