Class: Rubysh::Redirect
- Inherits:
-
BaseDirective
- Object
- BaseDirective
- Rubysh::Redirect
- Defined in:
- lib/rubysh/redirect.rb
Overview
Note that in bash, the semantics of redirection appear to be following (tested empirically, rather than reading a spec):
- a<&b
-
and [a>&b] mean the same thing: copy FD b to a
(try ‘echo test 3>/tmp/testing.txt 1<&3’)
- a<&a
-
appears to be a no-op: ls /dev/fd 9<&9
-
If b != a is an invalid file descriptor, then [a>&b] throws an error.
-
Pathnames can only be on the right-hand side of a redirect.
Constant Summary collapse
- VALID_DIRECTIONS =
['<', '>', '>>']
Instance Attribute Summary collapse
-
#direction ⇒ Object
Returns the value of attribute direction.
-
#source ⇒ Object
Returns the value of attribute source.
-
#target ⇒ Object
Returns the value of attribute target.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #apply!(runner) ⇒ Object
-
#apply_parent!(runner) ⇒ Object
E.g.
-
#initialize(source, direction, target, opts = nil) ⇒ Redirect
constructor
A new instance of Redirect.
- #named_target? ⇒ Boolean
- #prepare!(runner) ⇒ Object
- #prepare_target(runner) ⇒ Object
- #printable_source ⇒ Object
- #printable_target ⇒ Object
- #reading? ⇒ Boolean
-
#stringify ⇒ Object
TODO: support files.
- #target_name ⇒ Object
- #target_reading? ⇒ Boolean
- #target_writing? ⇒ Boolean
- #to_s ⇒ Object
- #truncate? ⇒ Boolean
- #writing? ⇒ Boolean
Methods inherited from BaseDirective
Constructor Details
#initialize(source, direction, target, opts = nil) ⇒ Redirect
Returns a new instance of Redirect.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/rubysh/redirect.rb', line 18 def initialize(source, direction, target, opts=nil) unless VALID_DIRECTIONS.include?(direction) raise Rubysh::Error::BaseError.new("Direction must be one of #{VALID_DIRECTIONS.join(', ')}, not #{direction.inspect}") end unless source.kind_of?(IO) || source.kind_of?(FD) || source.kind_of?(Integer) raise Rubysh::Error::BaseError.new("Invalid source: #{source.inspect}. Source must be an IO, a Rubysh::FD, or an Integer.") end unless target.respond_to?(:fileno) || target.kind_of?(Integer) || target.kind_of?(String) || target.kind_of?(Symbol) raise Rubysh::Error::BaseError.new("Invalid target: #{target.inspect}. Target must respond to :fileno or be an Integer, a String, or a Symbol.") end @source = source @target = target @direction = direction @opts = opts || {} end |
Instance Attribute Details
#direction ⇒ Object
Returns the value of attribute direction.
16 17 18 |
# File 'lib/rubysh/redirect.rb', line 16 def direction @direction end |
#source ⇒ Object
Returns the value of attribute source.
16 17 18 |
# File 'lib/rubysh/redirect.rb', line 16 def source @source end |
#target ⇒ Object
Returns the value of attribute target.
16 17 18 |
# File 'lib/rubysh/redirect.rb', line 16 def target @target end |
Instance Method Details
#==(other) ⇒ Object
73 74 75 76 77 |
# File 'lib/rubysh/redirect.rb', line 73 def ==(other) self.class == other.class && self.printable_source == other.printable_source && self.printable_target == other.printable_target end |
#apply!(runner) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/rubysh/redirect.rb', line 142 def apply!(runner) Rubysh.log.info("About to apply #{self} for #{$$}") # Open the target target_io = file_as_io(runner, target) target_fd = Util.to_fileno(target_io) source_fd = Util.to_fileno(source) # Copy target -> source Util.dup2(target_fd, source_fd) Util.set_cloexec(source_fd, false) end |
#apply_parent!(runner) ⇒ Object
E.g. Rubysh.stdin < :stdin
136 137 138 139 140 |
# File 'lib/rubysh/redirect.rb', line 136 def apply_parent!(runner) return unless named_target? target_state = runner.target_state(target_name) target_state[:complement].close end |
#named_target? ⇒ Boolean
99 100 101 |
# File 'lib/rubysh/redirect.rb', line 99 def named_target? target.kind_of?(Symbol) end |
#prepare!(runner) ⇒ Object
108 109 110 |
# File 'lib/rubysh/redirect.rb', line 108 def prepare!(runner) prepare_target(runner) end |
#prepare_target(runner) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/rubysh/redirect.rb', line 112 def prepare_target(runner) return unless named_target? targets = runner.targets if targets.include?(target_name) raise Rubysh::Error::BaseError.new("#{runner} already has a named target: #{target_name.inspect}") end pipe = Subprocess::PipeWrapper.new targets[target_name] = { :target_reading? => target_reading?, :target => target_reading? ? pipe.reader : pipe.writer, :complement => target_reading? ? pipe.writer : pipe.reader, :buffer => StringIO.new, :target_name => target_name, :read_pos => 0, :subprocess_fd_number => Util.to_fileno(source), :tee => @opts[:tee], :on_read => @opts[:on_read], :on_write => @opts[:on_write], } end |
#printable_source ⇒ Object
37 38 39 |
# File 'lib/rubysh/redirect.rb', line 37 def printable_source Util.to_fileno(source) end |
#printable_target ⇒ Object
41 42 43 44 45 46 47 48 |
# File 'lib/rubysh/redirect.rb', line 41 def printable_target case target when Symbol target.inspect else Util.to_fileno(target) end end |
#reading? ⇒ Boolean
79 80 81 |
# File 'lib/rubysh/redirect.rb', line 79 def reading? direction == '<' end |
#stringify ⇒ Object
TODO: support files
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rubysh/redirect.rb', line 51 def stringify source_file = printable_source target_file = printable_target case direction when '<', '>>' source_file = nil if source_file == 0 when '>' source_file = nil if source_file == 1 else raise Rubysh::Error::BaseError.new("Unrecognized direction: #{direction.inspect}") end ampersand = target_file.kind_of?(Integer) ? '&' : nil "#{source_file}#{direction}#{ampersand}#{target_file}" end |
#target_name ⇒ Object
103 104 105 106 |
# File 'lib/rubysh/redirect.rb', line 103 def target_name raise Rubysh::Error::BaseError.new("Not a named target") unless named_target? target end |
#target_reading? ⇒ Boolean
83 84 85 |
# File 'lib/rubysh/redirect.rb', line 83 def target_reading? !reading? end |
#target_writing? ⇒ Boolean
91 92 93 |
# File 'lib/rubysh/redirect.rb', line 91 def target_writing? !writing? end |
#to_s ⇒ Object
69 70 71 |
# File 'lib/rubysh/redirect.rb', line 69 def to_s "Redirect: #{stringify}" end |
#truncate? ⇒ Boolean
95 96 97 |
# File 'lib/rubysh/redirect.rb', line 95 def truncate? direction == '>' end |
#writing? ⇒ Boolean
87 88 89 |
# File 'lib/rubysh/redirect.rb', line 87 def writing? !reading? end |