# Notes on working with IO objects

require 'pp'

<<-MD
  # IO

  The basis for all input and output in Ruby (and computers).

  Types of IO devices:
    - Keyboards
    - Mic/Speakers/Video
    - USB devices
    - Files

  Data is moved between devices and programs in the form of bytes.

  The IO class will convert pathnames between different OS conventions, if possible.

  ## Methods of Interest

  * .binread
  * .binwrite
  * .copy_stream
  * .new
  * .open
  * .pipe
  * .read
  * .readlines
  * .write
  * #chars
  * #close
  * #each, #each_byte, #each_char, #each_line
  * #eof
  * #lines
  * #readbyte, #readchar, #readline, #readlines
  * #rewind
  * #to_i
  * #to_io
  * #write
MD

# writing to a file with the IO class
#  - create a "file descriptor" object, and then create a new I/O stream with it
#  - IO objects can also be created with the `BasicSocket` and `File` classes
filename = "./junk"
file_descriptor = IO.sysopen(filename, "w")
io_stream = IO.new(file_descriptor)
io_stream.puts "Hello, Richard"
io_stream.close

# reading from a file with the IO class
file_descriptor = IO.sysopen(filename)
io_stream = IO.new(file_descriptor)
io_stream.gets
io_stream.pos # => 15
io_stream.eof? # => true
io_stream.close

# the STDOUT, STDIN, and, STDERR constants are IO objects pointing to your
# program's input, output, and error streams
puts $stdin.object_id == STDIN

# you can capture and of these streams by reassigning their global variable
stderr = StringIO.new
$stderr = stderr

# set things back when you are finished capturing a stream
$stderr = STDERR

<<-MD
  # File

  Subclass of IO

  ## Methods of Interest

  * .path
  * #chmod
  * #size
MD

# write to file
filename = "todo.txt"
# file = File.open(filename, "w") # or
file = open(filename, "w")
file.puts "Wash dishes"
file.puts "Take a walk"
file.puts "Create hardware startup"
file.close

# write to file - block notation
filename = "groceries.txt"
File.open(filename, "w") do |file|
  file.puts "hummus"
  file.puts "carrots"
  file.puts "avocados"
end

# read from file - block notation
puts "#{filename} contains:"
File.open(filename, "r") do |file|
  puts file.read
end

# read from file - lines into array
lines = File.open(filename, "r").readlines
puts "Reading #{filename} with the #readlines method returns:"
PP.pp lines

# checking for existence
file_check = File.exists?(filename)
puts "Does #{filename} exist? #{file_check ? 'yes' : 'no'}"

# getting the path of a the current file
path = File.dirname(__FILE__)
puts "The file executing this code is located at #{path}"


<<-MD
  # Dir

  "Directory streams representing directories in the filesystem."

  ## Methods of Interest

  * Dir[string] - same as Dir.glob(string)
  * .delete
  * .exists?
  * .foreach
  * .home
  * #path
  * #read
  * #rewind
MD

# creating a directory
Dir.mkdir("temp") unless File.exists?("temp")

# file count
home = Dir.home
file_count = Dir.glob("#{home}/*").length
puts "There are #{file_count} files in the root of your home directory"

# recursive file count
file_count = Dir.glob("#{home}/**/*").length
puts "There are #{file_count} files within your home directory"

# file count by type
file_count = Dir.glob("#{home}/**/*.{pdf,PDF}").size
puts "There are #{file_count} PDFs within your home directory"


<<-MD

  # Sockets

  All of the following classes inherit from the IO class.

  - TCPSocket
  - UDPSocket
  - UNIXSocket
  - Socket

MD

# making a HTTP request
require "socket"
tcp_socket = TCPSocket.new("localhost", 3000)
tcp_socket.puts("GET / HTTP/1.1\r\n")
tcp_socket.puts("\r\n")
tcp_socket.gets  # => "HTTP/1.1 302 Found \r\n"

<<-MD
  # Resources

  * [ruby-doc.org](http://ruby-doc.org/core/IO.html)
  * [Streams - RubyMonk](https://rubymonk.com/learning/books/1-ruby-primer/chapters/42-introduction-to-i-o/lessons/89-streams)
  * [IO in Ruby - thoughtbot](https://robots.thoughtbot.com/io-in-ruby)
  * [Input & Output - readruby.io](http://web.archive.org/web/20150101172349/http://readruby.io/io)
  * [Text processing and I/O programming fundamentals](https://github.com/elm-city-craftworks/course-001)
MD