<file_sep>require 'logger'

class NullLogger
  def method_missing(*); end
end

options = {logger: false}
logger = options.fetch(:logger){Logger.new($stdout)}
unless logger
  logger = NullLogger.new
end
logger
# => #<NullLogger:0x00000003b73858>

{}[:foo] || :default             # => :default
{foo: nil}[:foo] || :default     # => :default
{foo: false}[:foo] || :default   # => :default

{}.fetch(:foo){:default}             # => :default
{foo: nil}.fetch(:foo){:default}     # => nil
{foo: false}.fetch(:foo){:default}   # => false
<file_sep># Destructuring assignment is the process of assigning multiple variables at one time.
arr = [2, 3]
(a, b) = *arr
a # => 2
b # => 3

dep = {"hello" => ["hello.c", "foo.o", "bar.o"]} 
# The first file in the dependency is the primary source file. The others are supporting libraries.

# Breaking out the parts of this dependency by assigning one piece at a time:
dep.first                          # => ["hello", ["hello.c", "foo.o", "bar.o"]] # Individual hash entries are represented as two element arrays.
target = dep.first.first        # => "hello"
first_preq = dep.first.last.first # => "hello.c"
rest_preqs = dep.first.last[1..-1] # => ["foo.o", "bar.o"]

# A different approach:

dep = {"hello" => ["hello.c", "foo.o", "bar.o"]}

a = *dep                        # => [["hello", ["hello.c", "foo.o", "bar.o"]]] # We splat out the dependency into an array.

((target, (first_preq, *rest_preqs))) = *dep

target                          # => "hello"
first_preq                      # => "hello.c"
rest_preqs                      # => ["foo.o", "bar.o"]
<file_sep># a file called .netrc, which stores usernames and passwords for remote hosts.
machine rubytapas.com login avdi password <PASSWORD>
machine example.org login marvin password <PASSWORD>

# write our own parser for this simplified .netrc format:
open('.netrc').lines do |line|
  columns  = line.split
  machine  = columns[1]
  login    = columns[3]
  password = columns[5]
  puts "#{machine}: #{login} / #{password}"
end
# >> rubytapas.com: avdi / xyzzy
# >> example.org: marvin / plugh

# we can implicitly splat arrays into multiple variables on assignment.
open('.netrc').lines do |line|
  machinekey, machine, loginkey, login, passwordkey, password  = line.split
  puts "#{machine}: #{login} / #{password}"
end
# >> rubytapas.com: avdi / xyzzy
# >> example.org: marvin / plugh

# But now we have a bunch of useless variables ending in -key which exist simply to be placeholders. 
# We need to clarify that we don't care about any of those fields by using the variable name ignored for all of them:
open('.netrc').lines do |line|
  ignored, machine, ignored, login, ignored, password  = line.split
  puts "#{machine}: #{login} / #{password}"
end

# As a separate method:
# If we replace our ignored variable with a variable called _, Ruby relaxes its usual rules about duplicate argument names. 
def netrc_entries
  open('.netrc').lines do |line|
    yield(*line.split)
  end
end
 
netrc_entries do |_, machine, _, login, _, password|
  puts "#{machine}: #{login} / #{password}"
end                                                           
# >> rubytapas.com: avdi / xyzzy
# >> example.org: marvin / plugh<file_sep>   text = <<END
I'm your only friend
I'm not your only friend
But I'm a little glowing friend
But really I'm not actually your friend
But I am
END

word_count = Hash.new do |hash, missing_key|
  hash[missing_key] = 0
end

text.split.map(&:downcase).each do |word|
  word_count[word] += 1
end
word_count

h = Hash.new { |h, k| h[k] = [] } # !> shadowing outer local variable - h
h["IPAs"] << "Victory HopDevil"
h["IPAs"] << "Weyerbacher Double Simcoe"
h["Stouts"] << "Victory Storm King"
h["Stouts"]
# => ["Victory Storm King"]
# Hash uses the same default object everywhere. It doesn't duplicate it before use.
# when we use a default block instead of a default value, the block is executed every time a default value is needed,
# thus generating a new Array object every time.
<file_sep>def greet(params)
  name = user_name(params) rescue "Anonymous"
  puts "Hello, #{name}"
end
#if the username is missing; we'd like to just replace it with a placeholder and keep going.

greet({})
# >> Hello, Anonymous

#if we want to examine the exception before deciding to re-raise itץ
value_or_error = {}.fetch(:some_key) rescue $! #a reference to the currently-raised exception
value_or_error # => #<KeyError: key not found: :some_key>

#rescue is an excellent way to convert exceptions into return values.
<file_sep># in the absence of differing behavior, differentiated child classes aren't needed.
# transition to using different instances to represent different units, instead of different classes.

class Quantity
	attr_reader :magnitude, :unit

	def initialize(magnitude, unit)
		@magnitude = magnitude.to_f
		@unit      = unit
		freeze
	end
		
	def to_s
		"#{@magnitude} #{unit}"
	end


	def inspect
		"#<#{unit}:#{@magnitude}>"
	end

	def +(other)
		other = ensure_compatible(other) 
		self.class.new(@magnitude + other.to_f, unit)
	end

	def -(other)
		other = ensure_compatible(other) 
		self.class.new(@magnitude - other.to_f, unit)
	end

	def *(other)
		multiplicand = if other.is_a?(Numeric)
										other
									elsif other.is_a?(Quantity) && other.unit == unit
										other.to_f
									else
										fail TypeError, "Don't know how to multiply by #{other}"
									end
		self.class.new(@magnitude * multiplicand, unit)
	end

	def <=>(other)
		return nil unless other.is_a?(self.class) && other.unit == unit
		magnitude <=> other.to_f
	end

	def Feet(value)
		if value.is_a?(Quantity) && value.unit == :feet
			value
		else
			value = Float(value)
			Quantity.new(value, :feet)
		end
	end

	def Meters(value)
		if value.is_a?(Quantity) && value.unit == :meters
			value
		else
			value = Float(value)
			Quantity.new(value, :meters)
		end
	end

end

ConversionRatio.registry << 
ConversionRatio.new(:feet, :meters, 0.3048) <<
ConversionRatio.new(:meters, :feet, 3.28084)

# So long as some kind of object may have different sub-types, and those types affect the logic of a program,
# we need a way of representing that differentiation. The Ruby way to encode type is with a class (or module).<file_sep># It's the default return value for a Hash when the key is not found:
h = {}
h['fnord']                      # => nil

def empty
  # TODO
end
empty    

result = if (2 + 2) == 5
           "uh-oh"
         end
result                          # => nil

# for a case statement with no matched "when" clauses and no else:
type = case :foo
       when String then "string"
       when Integer then "integer"
       end
type                            # => nil   
 
if (2 + 2) == 5
  tip = "follow the white rabbit"
end
 
tip                             # => nil
 
# unset instance variables (f.e. typos):
@i_can_has_spelling = true
puts @i_can_haz_speling         # => nil

# many ruby methods return nil to indicate failure:
[1, 2, 3].detect{|n| n == 5}    # => nil


# Here's a method for fetching a password. When we call it, returns nil.
require 'yaml'
SECRETS = File.exist?('secrets.yml') && YAML.load_file('secrets.yml')
 
def get_password_for_user(username=ENV['USER'])
  secrets = SECRETS || @secrets
  entry = secrets && secrets.detect{|entry| entry['user'] == username}
  entry && entry['password']
end
 
get_password_for_user        # => nil

# And this is the fundamental problem with nil: it can mean many different things, but the meaning is always contextual.<file_sep># A doubled-up bang operator to force a value to be converted to a boolean.

code = <<EOF
bool = !!result
EOF

code.chars.chunk{|c|
  case c
  when /\n/ then :endline
  when /[[:alpha:]]/ then :identifier
  when /[\!\+\-\=\/\*]/ then :operator
  when /\d/ then :number
  end
}.to_a
# => [[:identifier, ["b", "o", "o", "l"]],
#     [:operator, ["="]],
#     [:operator, ["!", "!"]],
#     [:identifier, ["r", "e", "s", "u", "l", "t"]],
#     [:endline, ["\n"]]]

# A doubled-up bang shouldn't be treated as a single operator.
# Instead of "operator" we'll categorize these characters using the flag symbol :_alone.

code = <<EOF
bool = !!result
EOF

code.chars.chunk{|c|
  case c
  when /\n/ then :endline
  when /[[:alpha:]]/ then :identifier
  when /[\!\+\-\=\/\*]/ then :_alone
  when /\d/ then :number
  end
}.to_a
# => [[:identifier, ["b", "o", "o", "l"]],
#     [:_alone, ["="]],
#     [:_alone, ["!"]],
#     [:_alone, ["!"]],
#     [:identifier, ["r", "e", "s", "u", "l", "t"]],
#     [:endline, ["\n"]]]

# Now the operator characters are chunked with the symbol :_alone.

# Receiving input chunks as an array of lines.

require 'stringio'
data = "6\r\nHello!\r\nD\r\n How are\r\n you?\r\n0\r\n"
chunked_data = StringIO.new(data)

chunks = chunked_data
         .each_line("\r\n")
         .chunk({chunk_num: 0, chars_left: :unknown}){
  |line, state|
  line.chomp!("\r\n")
  if state[:chars_left] == :unknown
    state[:chars_left] = Integer(line, 16)
    :_separator
  elsif state[:chars_left] > 0
    state[:chars_left] -= line.size
    state[:chunk_num]
  else
    state[:chunk_num] += 1
    state[:chars_left] = :unknown
    redo
  end
}

chunks.next                     # => [0, ["Hello!"]]
chunks.next                     # => [1, [" How are", " you?"]]
<file_sep># We want to update the author with pen-name information from each of the stories. 
# when we follow the author association back from one of the stories,
# we get a different object than the author object we started with—the one we are saving back to the database.

author = AM.find(1)
update_pen_names(author)
AM.store(author)
AM.find(1).pen_names
# => nil

author.object_id                              # => 22795980
author.stories.first.author.__get__.object_id # => 22747020

# An identity map ensures that only one object corresponds to a given record in the database at a time.
ID_MAP = {}
AM = AuthorMapper.new(ID_MAP)
SM = StoryMapper.new(ID_MAP)

# 
class TeenyMapper
    # ...
    def initialize(id_map)
      @id_map = id_map
    end
  
    def store(object)
      data  = object.to_h
      store_row(object.class, data)
      object.id = data[:id]
      @id_map[[object.class, object.id]] = object #updates the identity map.
    end
  
    # ...
    #fetch returns a value from the hash for the given key.
    #Using an array as a Hash key shows off the fact that Ruby Hashes can accept any kind of object as a key.
    def load(type, data)
      @id_map.fetch([type, data[:id]]) do  # we use an array of object type and ID as the key.If the identity map already contains an object matching that key, it will be returned immediately.
        object = type.new #Otherwise, a new model object will be constructed, and added to the ID map before it is returned.
        data.each_with_object(object) { |(key, value), o|   
          o[key] = value
        }
        @id_map[type, object.id] = object
      end
    end
  end
  
author = AM.find(1)
author.object_id                              # => 15423800
author.stories.first.author.__get__.object_id # => 15423800
author = AM.find(1)
update_pen_names(author)
AM.store(author)
AM.find(1).pen_names
# => "<NAME>, <NAME>, <NAME>"

# we could set things up so that the identity map also functions as a cache,
# avoiding repeated database requests for objects which have already been loaded once.
before do
  RubyTapas.clear_id_map
  RubyTapas.base_url = Addressable::URI.parse(request.url).site.to_s
  self.current_user = load_user
end<file_sep>require 'set'
a = [:first, :second, :third, :fourth]
s = Set.new(a)
# => #<Set: {:first, :second, :third, :fourth}>
s.to_a                          # => [:first, :second, :third, :fourth]. when we substitute a Set for our array, the implicit splatting no longer works.
x, y, z = s
x                               # => #<Set: {:first, :second, :third, :fourth}>
y                               # => nil
z                               # => nil
# if we rely on implicit splatting, the input must be an actual Array or something very close to one.
x, y, z = *s
x                               # => :first
y                               # => :second
z                               # => :third
# in the block argument list, it causes the pair to be wrapped in a second array.
def yield_pair
  yield([:foo, :bar])
end

yield_pair do |*pair|
  puts pair.inspect
end
# >> [[:foo, :bar]]
# If we want to work with keys and values separately, we can provide a block that takes two separate arguments.
# But if we want to work with key/value pairs as a unit, we can supply just one block argument.
<file_sep>machine rubytapas.com
 login avdi
 password <PASSWORD>
machine example.org
 login marvin
 password <PASSWORD>

# With a Struct representing a .netrc entry, we can access the username and password through method calls, or using Hash-style notation.
class Netrc
  Entry = Struct.new(:login, :password) # an “entry” is a collection of unique attributes.
end
entry = Netrc::Entry.new('avdi', 'xyzzy') # implicit splatting.
entry.login                     # => "avdi"
entry.password                  # => "<PASSWORD>"
entry[:login]                   # => "avdi"
entry[:password]                # => "<PASSWORD>"
entry[0]                        # => "avdi"
entry[1]                        # => "xyzzy"
# implicit splatting only works on arrays and “array-like” objects.
# alias entry objects' #to_a method to #to_ary. Now, Entry objects can be implicitly splatted out just like arrays.
class Netrc
  Entry = Struct.new(:login, :password) do
    alias_method :to_ary, :to_a
  end
end
entry = Netrc::Entry.new('avdi', 'xyzzy')
login, password = entry
login                           # => "avdi"
password                        # => "<PASSWORD>"
# Now we have a class that really would make a good replacement for the old two-element-array return value.
# it adds new, meaningful accessor methods.
<file_sep>require 'open-uri'
require 'json'

def get_observation
  key  = ENV['WUNDERGROUND_KEY']
  url  = "http://api.wunderground.com/api/#{key}/conditions/q/PA/York.json"
  data = open(url).read
  JSON.parse(data)['current_observation']
end

def print_observation(observation)
  puts "Temperature: #{observation.temp_f}F"
  pressure_trend = observation.pressure_trend == "-" ? "falling" : "rising"
  puts "Pressure: #{observation.pressure_mb}mb and #{pressure_trend}"
  puts "Winds: #{observation.wind_string}"
end

require 'ostruct'
observation = {
  'temp_f'         => 49.0,
  'pressure_trend' => '-',
  'pressure_mb'    => 981,
  'wind_string'    => "From the North at 3.0 MPH Gusting to 7.0 MPH"
}
os = OpenStruct.new(observation) # What we get in return is an object that has a reader method for each key in the hash.
os.temp_f                       # => 49.0
os.wind_string                  # => "From the North at 3.0 MPH Gusting to 7.0 MPH"

print_observation(get_observation)

#differences:
require 'ostruct'
s  = Struct.new(:foo, :bar).new(42, 32)
os = OpenStruct.new(foo: 42, bar: 23)

s.members                       # => [:foo, :bar]
os.members                      # => nil
s.map {|value| value * 2}       # => [84, 64]
os.map {|value| value * 2}      # => nil
<file_sep>point = Class.new do
  attr_reader :x, :y
  def initialize(x, y)
    @x = x
    @y = y
  end
end

circle = Class.new(point) do # inherit from the new class by passing the parent class to Class.new
  attr_reader :radius
  def initialize(x, y, radius)
    super(x,y)
    @radius = radius
  end
end

c1 = circle.new(3,5,10)
# => #<#<Class:0x974c620>:0x974c5a8 @x=3, @y=5, @radius=10>

# when we name a class, we're simply assigning that class to a constant, just as we might assign a number or a string to a constant.
# functionally there's no difference between an all-caps constant and one that's camel-cased.
Point = Class.new do
  attr_reader :x, :y
  def initialize(x, y)
    @x = x
    @y = y
  end
end

# using the class keyword is pretty much just a shorthand for creating a new class object and assigning it to a constant.
<file_sep>expr = [:*, 3, [:+, 2, 5]]
op, f1, f2 = expr
inner_op, t1, t2 = f2
 
op                              # => :*
f1                              # => 3
inner_op                        # => :+
t1                              # => 2
t2                              # => 5

# By “grouping” arguments on the left side of the assignment, we can tell Ruby to assign elements of nested arrays directly to variables names. 
expr = [:*, 3, [:+, 2, 5]]
op, f1, (inner_op, t1, t2) = expr
 
op                              # => :*
f1                              # => 3
inner_op                        # => :+
t1                              # => 2
t2                              # => 5

# the inner addition expression has three terms. Instead of providing a variable for each term, we slurp them all up into a variable named ts. 
expr = [:*, 3, [:+, 2, 5, 7]]
op, f1, (inner_op, *ts) = expr
 
op                              # => :*
f1                              # => 3
inner_op                        # => :+
ts                              # => [2, 5, 7]    

# splatting all of the arguments into a single array and then inspecting that array:
menu = { 
  'Jacked Up Turkey'     => '$7.25',
  'New York Mikey'       => '$7.25',
  'Apple Grilled Cheese' => '$5.25' 
}
 
menu.each_with_index do |*args|
  puts args.inspect
end
# >> [["Jacked Up Turkey", "$7.25"], 0]
# >> [["New York Mikey", "$7.25"], 1]
# >> [["Apple Grilled Cheese", "$5.25"], 2]

# using an intermediate variable(the pair argument):
menu = { 
  'Jacked Up Turkey'     => '$7.25',
  'New York Mikey'       => '$7.25',
  'Apple Grilled Cheese' => '$5.25' 
}
 
menu.each_with_index do |pair, i|
  name, price = pair
  puts "#{i+1}: #{name} (#{price})"
end
# >> 1: Jacked Up Turkey ($7.25)
# >> 2: New York Mikey ($7.25)
# >> 3: Apple Grilled Cheese ($5.25

# any syntax we can use on the left side of an assignment, we can also use in an argument list. 
# Instead of an intermediate pair argument, let's put a group in the block argument list:
menu = { 
  'Jacked Up Turkey'     => '$7.25',
  'New York Mikey'       => '$7.25',
  'Apple Grilled Cheese' => '$5.25' 
}
 
menu.each_with_index do |(name, price), i|
  puts "#{i+1}: #{name} (#{price})"
end
# >> 1: Jacked Up Turkey ($7.25)
# >> 2: New York Mikey ($7.25)
# >> 3: Apple Grilled Cheese ($5.25)
 
# As a result we no longer have any need of an intermediate pair variable which exists only to be broken up. <file_sep>text = <<END
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec
hendrerit tempor <EMAIL> tellus. Donec pretium posuere
tellus. Proin quam nisl, tincidunt et, mattis eget, convallis nec,
purus. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur <EMAIL> ridiculus mus. Nulla posuere. Donec vitae
dolor. Nullam tristique <EMAIL> diam non turpis. Cras
placerat accumsan nulla. Nullam <EMAIL> rutrum. Nam
vestibulum accumsan nisl.
END
EMAIL_PATTERN = /\S+@\S+/i

addresses = []
while(match = EMAIL_PATTERN.match(text))
  addresses << match[0]
  text = match.post_match
end
addresses

# We can use the #scan method on String. This method finds every match for a given regular expression.
addresses = text.scan(EMAIL_PATTERN)

# The block will be called for each match, with the matched string as the block argument.
text.scan(EMAIL_PATTERN) do |address|
  puts address
end
<file_sep>class Parent
  def hello(subject="World")
    puts "Hello, #{subject}"
    if block_given?
      yield
      puts "Well, nice seeing you!"
    end
  end
end

class Child < Parent
  def hello(subject=:default)
    if subject == :default
      super(&nil)
      puts "How are you today?"
    else
      super(subject, &nil)
      puts "How are you today?"
    end
  end
end

Child.new.hello(:default) do
  puts "Hi there, Child"
end
 
#In order to suppress the block being passed through, we have to use the special argument &nil.
<file_sep># The string 'cherry' is being modified in-place by the #print_pie method.
def print_pie(filling)
  puts filling << ' pie'
end

fruit = 'cherry'
print_pie(fruit)
fruit # => "cherry pie"

# We can clone it and pass the clone around instead.
fruit = 'cherry'
cloned_fruit = fruit.clone
print_pie(cloned_fruit)
fruit # => "cherry" # The original value remains unchanged.

# Freezing the value, getting an exception if we try to modify it:
fruit = 'cherry'
frozen_fruit = fruit.freeze
print_pie(frozen_fruit)
fruit # =>
# ~> -:2:in `print_pie': can't modify frozen String (RuntimeError)
# ~>  from -:7:in `<main>'

# The simplest way to make an immutable collection is to call #freeze on an existing array:
fruits = %w(apple banana cherry damson elderberry)
fruits.freeze
fruits << 'fig' # =>
# ~> -:3:in `<main>': can't modify frozen Array (RuntimeError)

# A naturally immutable collection, using the #to_enum method to make an immutable collection:
fruits = %w(apple banana cherry damson elderberry).to_enum # enum lets us iterate over the underlying collection, but not modify it.
fruits.entries # => ["apple", "banana", "cherry", "damson", "elderberry"]
fruits << 'fig' # =>
# ~> -:3:in `<main>': undefined method `<<' for #<Enumerator> (NoMethodError)

# Making an enum from scratch:
fruits = Enumerator.new do |yielder|
  yielder.yield 'apple'
  yielder.yield 'banana'
  yielder.yield 'cherry'
  yielder.yield 'damson'
  yielder.yield 'elderberry'
end
fruits.entries # => ["apple", "banana", "cherry", "damson", "elderberry"]

# Creating a new collection by changing the contents of the initial one:
fruits.class # => Enumerator
fruits.map(&:upcase) # => ["APPLE", "BANANA", "CHERRY", "DAMSON", "ELDERBERRY"] # => Array
fruits.select { |fruit| fruit.length == 6 } # => ["banana", "cherry", "damson"] # => Array

# Adding an element:
more_fruits = Enumerator.new do |yielder| # Making a modified copy of an immutable collection.
  fruits.each do |fruit|
    yielder.yield fruit
  end

  yielder.yield 'fig'
end
more_fruits.entries # => ["apple", "banana", "cherry", "damson", "elderberry"]
fruits.include?('fig') # => false
more_fruits.include?('fig') # => true

# Removing an element:
fewer_fruits = Enumerator.new do |yielder|
  fruits.each do |fruit|
    yielder.yield fruit unless fruit == 'cherry'
  end
end
fewer_fruits.entries # => ["apple", "banana", "damson", "elderberry"]
fruits.include?('cherry') # => true
fewer_fruits.include?('cherry') # => false

# An infinite collection of even numbers:
even_numbers = Enumerator.new do |yielder|
  n = 2

  loop do
    yielder.yield n
    n += 2
  end
end
even_numbers.next # => 2
even_numbers.next # => 4

even_numbers.take 10 # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] # The enum generates more elements as they're needed.

even_or_unlucky_numbers = Enumerator.new do |yielder|
  even_numbers.each do |n|
    yielder.yield n
    yielder.yield 13 if n == 12
  end
end
even_or_unlucky_numbers.take 10 # => [2, 4, 6, 8, 10, 12, 13, 14, 16, 18]

# With cloning and freezing an Array, we can still modify the string objects it contains:
fruits = %w(apple banana cherry damson elderberry)
cloned_fruits = fruits.clone # Same with #freeze.
cloned_fruits.first.prepend 'pine'
fruits # => ["pineapple", "banana", "cherry", "damson", "elderberry"]

# An enum is regenerated every time we iterate over it:
fruits = Enumerator.new do |yielder|
  yielder.yield 'apple'
  yielder.yield 'banana'
  yielder.yield 'cherry'
  yielder.yield 'damson'
  yielder.yield 'elderberry'
end

fruits.first.prepend 'pine'
fruits.entries # => ["apple", "banana", "cherry", "damson", "elderberry"]<file_sep># Numbers are immutable: they cannot be changed. 
class Feet
  attr_accessor :magnitude

  def initialize(magnitude)
    @magnitude = magnitude.to_f
  end

  def to_s
    "#{@magnitude} feet"
  end

  def +(other)
    Feet.new(@magnitude + other.magnitude)
  end
end

class Altimeter
  def initialize(value)
    raise TypeError unless Feet === value
    @value_in_feet = value
  end

  def change_by(change_amount)
    raise TypeError unless Feet === change_amount
    old_value = @value_in_feet
    @value_in_feet.magnitude += change_amount.magnitude  # the Feet class is mutable.
    puts "Altitude changed from #{old_value} to #{@value_in_feet}"
  end
end

require "./feet"
require "./altimeter2"

START_ALTITUDE = Feet.new(10_000) # holds a default starting altitude.

alt = Altimeter.new(START_ALTITUDE)
alt.change_by(Feet.new(500))

START_ALTITUDE                  # => #<Feet:0x000000017e0e90 @magnitude=10500.0>
# >> Altitude changed from 10500.0 feet to 10500.0 feet      unwanted behavior, the constant's value has changed.

# Making the Feet class immutable:
class Feet
  attr_reader :magnitude             #
 
  def initialize(magnitude)
    @magnitude = magnitude.to_f
    freeze                           # This tells ruby to make the object immutable.
  end
 
  def to_s
    "#{@magnitude} feet"
  end
 
  def +(other)
    Feet.new(@magnitude + other.magnitude)
  end

  def positive?  # leaving a method which unintentionally updates the value in-place whenever it is called.
    @magnitude = 0.0
  end
end

f = Feet.new(30_000)
f.positive?                     # => 
# ~> -:18:in `positive?': can't modify frozen Feet (RuntimeError)
# ~>    from -:23:in `<main>'

# We now have a class which ensures that we can't circumvent immutability, even accidentally.<file_sep># Returning a special string whenever the input is blank, using next:
# The argument to next becomes the return value of the current invocation of a block(instead of nil).

objects = ["house", "mouse", "", "mush", "",
"little old lady whispering 'hush'"]

result = objects.map do |o|
next "Goodnight, Moon" if o.empty? # supplying an argument to next.
"Goodnight, #{o}"
end
result.compact
# => ["Goodnight, house",
#     "Goodnight, mouse",
#     "Goodnight, Moon",
#     "Goodnight, mush",
#     "Goodnight, Moon",
#     "Goodnight, little old lady whispering 'hush'"]

# A long list of filenames. We want to get all of our rules for inclusion or exclusion in one place.
# To do that, we use a series of next statements.

Dir["../**/*.mp4"].select { |f|
next false unless File.file?(f) # we skip the remaining checks using next with a false argument and it'll return false. 
next false unless File.readable?(f) # skips forward if the file isn't readable.
next true if f =~ /078b-java-dregs\.mp4/ # next with a true argument skips all remaining tests and tells #select to include this entry in the results.
next false if File.size(f) == 0
next true if File.basename(f) =~ /^\d\d\d-/ # includes files matching a particular naming scheme.
}

# A method that accepts a block. It yields to the block twice, logging before and after each yield.

def yieldtwice
  puts "Before first yield"
  yield
  puts "Before second yield"
  yield
  puts "After last yield"
end

yieldtwice do
  puts "About to invoke next"
  next                         # This behaves like an early return, except for a block instead of a method.  
  puts "Can never get here"
end
puts "After method call"

# >> Before first yield
# >> About to invoke next
# >> Before second yield
# >> About to invoke next
# >> After last yield
# >> After method call

# Using break instead of next:

def yieldtwice
  puts "Before first yield"
  yield
  puts "Before second yield"
  yield
  puts "After last yield"
end

yieldtwice do
  puts "About to invoke break"
  break
  puts "Can never get here"
end
puts "After method call"

# >> Before first yield
# >> About to invoke break
# >> After method call

# Unlike next, break doesn't just bring a yield to an early end. 
# It cancels the execution of the whole method that triggered the yield.<file_sep># At this point, most of the Ruby world has embraced #raise over #fail.
# use raise when re-raising an exception.
# That way, the choice of raise instead of fail provides an extra cue to the reader that something out of the ordinary is going on.
['--require', '-r MODULE',
  "Require MODULE before executing rakefile.",
  lambda { |value|
    begin
      require value
    rescue LoadError => ex
      begin
        rake_require value
      rescue LoadError
        raise ex
      end
    end
  }
],
# In the specific case where doing an ordinary require raises a LoadError,
# this code rescues the error and then tries again to require the file using the special rake_require method. 
# If that too raises a LoadError, there are no options left. And so it re-raises the exception.

# begin/raise/rescue is used for errors, and nothing else. <file_sep># This syntax doesn't always play well with larger expressions.
1..10.include?(5)               # =>
# ~> -:1:in `<main>': undefined method `include?' for 10:Fixnum (NoMethodError)
# Ruby parsed the expression like this: 1..(10.include?(5)). Because of these parsing issues, we commonly see ranges included in parentheses.

# Inclusive range
(1..10).include?(10)            # => true 
# Exclusive range
(1...10).include?(10)           # => false
# #member is the alias
(1..10).member?(10)             # => true
# The threequals operator performs the same operation.
(1..10) === 5                   # => true

case spaceball_one_speed
when 0...299_792_458
  puts "sublight speed"
when 299_792_458
  puts "light speed"
when 299_792_459...1_000_000_000
  puts "ridiculous speed"
when 1_000_000_000...10_000_000_000
  puts "ludicrous speed"
end

# Filtering out readings using grep.
readings = [26, 72, 9000, 8, 17, -3400]
readings.grep(0..100)
# => [26, 72, 8, 17]

# Ranges are not limited to using numbers.
("a".."z").include?("x")        # => true

this_week = Time.new(2014, 7, 20)...Time.new(2014, 7, 27)
# Asking if it includes today.
this_week.include?(Time.new(2014, 7, 22))
  # =>
# ~> -:2:in `each': can't iterate from Time (TypeError)    # This means it has to know how to increment the start value.
# ~>    from -:2:in `include?'
# ~>    from -:2:in `include?'
# ~>    from -:2:in `<main>'
1.succ                          # => 2
"a".succ                        # => "b"
Time.now.succ                   # => 2014-07-22 11:50:03 -0400 # !> Time#succ is obsolete; use time + 1

# Using #cover instead.
this_week = Time.new(2014, 7, 20)...Time.new(2014, 7, 27)
this_week.cover?(Time.new(2014, 7, 22))
  # => true

# Selecting the entries for this week.
marvin_calendar = {
  Time.new(2014, 7, 20) => "Mope",
  Time.new(2014, 7, 22) => "Rust",
  Time.new(2014, 7, 28) => "Write sad poem"
}

this_week = Time.new(2014, 7, 20)...Time.new(2014, 7, 27)

marvin_calendar.select{|date, _| this_week.cover?(date) }.values
# => ["Mope", "Rust"]

# For ranges that can be iterated, Ruby provides an #each method, along with the usual Enumerable methods.
(0..10).each do |n|
  puts n
end

("a".."z").to_a

# Iterating over a range by an increment of 2, using #step (passing each (2nd) element to the block).
(0..10).step(2) do |n|
  puts n
end
# >> 0
# >> 2
# >> 4
# >> 6
# >> 8
# >> 10

# Without a block, this returns an enumerator.
(0..10).step(2).to_a
# => [0, 2, 4, 6, 8, 10]
<file_sep>def hello(name)
  puts "Hello, #{name}"
end

code = '
  def goodbye(name)
   puts "Goodbye, #{name}"
  end
'

eval code
goodbye("Crow")
# >> Goodbye, Crow

# To load code more portably and robustly, we need some kind of search path of places to look for code.
# it's a global variable named $LOAD_PATH. 

def try_load_file(file) # a helper method named #try_load_file.
  if File.file?(file)
    puts "LOAD #{file}"
    eval File.read(file)
    return true
  else
    return false
  end
end

def load_lib(name) #  It will take a filename as an argument.
  return true if try_load_file(name) # Finds and loads the file in the current directory.

  $LOAD_PATH.each do |dir|  # This global variable is pre-loaded with a number of default system directories.
    file = File.join(dir, name)
    return if try_load_file(file)
  end

  fail LoadError, "Library not found: #{name}"
end

# Loading up our own library files. Expanding the path one level up from the file. 
my_lib_dir = File.expand_path("..", __FILE__)
# => "/home/avdi/Dropbox/rubytapas/235-require"

# $LOAD_PATH << my_lib_dir
$LOAD_PATH.unshift(my_lib_dir) # Prepending to an array.<file_sep>class Feet; end
class Meters; end

ConversionRatio = Struct.new(:from, :to, :number) do
  def self.registry
    @registry ||= []
  end

  def self.find(from, to)
    registry.detect{|ratio| ratio.from == from && ratio.to == to}
  end
end

ConversionRatio.registry << 
  ConversionRatio.new(Feet, Meters, 0.3048) <<
  ConversionRatio.new(Meters, Feet, 3.28084)

def convert_to(target_type)
  ratio = ConversionRatio.find(self.class, target_type) or    # asking, not telling.
    fail TypeError, "Can't convert #{self.class} to #{target_type}"
  target_type.new(magnitude * ratio.number)
end

# we should tell objects what to do, rather than asking them about themselves.
class Feet; end
class Meters; end

UnitConversion = Struct.new(:from, :to) do
  def self.registry
    @registry ||= []
  end

  def self.find(from, to)
    registry.detect{|ratio| ratio.from == from && ratio.to == to}
  end

  def call(from_value) # expected to be implemented in derived classes.
    raise NotImplementedError
  end
end

class RatioConversion < UnitConversion # adds a number and overrides #call.
  attr_reader :number
  def initialize(from, to, number)
    super(from, to)
    @number = number
  end

  def call(from_value)
    from_value * number
  end
end

UnitConversion.registry << 
  RatioConversion.new(Feet, Meters, 0.3048) <<
  RatioConversion.new(Meters, Feet, 3.28084)


def convert_to(target_type)
  conversion = UnitConversion.find(self.class, target_type) or 
    fail TypeError, "Can't convert #{self.class} to #{target_type}"
  target_type.new(conversion.call(magnitude)) # instead of reaching into the resulting object, it simply tells that object to perform its conversion.
end
# Now that we've switched from asking to telling, we easily add code to deal with temperature conversions.
require "./conversion"

class Celsius; end
class Fahrenheit; end

class BlockConversion < UnitConversion
  def initialize(from, to, &block)
    super(from, to)
    @block = block
  end

  def call(from_value)
    @block.call(from_value)
  end
end

UnitConversion.registry << BlockConversion.new(Celsius, Fahrenheit) { 
  |from_value|
  ((from_value * 9) / 5) + 32
}

UnitConversion.find(Celsius, Fahrenheit).call(32)
# => 89
<file_sep>module LiveCell
  def self.to_s() 'o' end

  def self.next_generation(x, y, board)
    case board.neighbors(x,y).count(LiveCell)
    when 2..3 then self
    else DeadCell
    end
  end
end

module DeadCell
  def self.to_s() '.' end

  def self.next_generation(x, y, board)
    case board.neighbors(x,y).count(LiveCell)
    when 3 then LiveCell
    else self
    end
  end
end

[
 [DeadCell, LiveCell, LiveCell, DeadCell],
 # ...
]

# since this is a stateless implementation, there is no need to have individual LiveCell objects for every live cell on the board. 
# And the same goes for dead cells.
<file_sep># The IO class is the basis for all input and output in Ruby.
# An IO object is effectively a wrapper around the operating systems concept of a filehandle.
# Like the File class, the Socket library subclasses from IO (such as TCPSocket or UDPSocket).

open("/dev/urandom")            # => #<File:/dev/urandom>
File.superclass                 # => IO

require "socket"

TCPSocket.new "google.com", 80
# => #<TCPSocket:fd 7>

TCPSocket.ancestors
# => [TCPSocket, IPSocket, BasicSocket, IO, File::Constants, Enumerable, Object, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]

# Tempfile is what is known as an IO-like object.

require "tempfile"

temp = Tempfile.new                    # => #<Tempfile:/tmp/20160316-13069-134v9lj>
temp.write "Hello"
temp.close
temp.open
temp.read                       # => "Hello"

Tempfile.ancestors
# => [Tempfile, #<Class:0x0055cfc0f224d0>, Delegator, #<Module:0x0055cfc117fe08>, BasicObject]
<file_sep># DateTime.strptime normally takes two arguments: a time string to parse, and a format specification.
# Time.strftime is the method used to convert times into strings. 
require 'date'

print_format = '%-m/%-d/%Y %k:%M'
Time.new(2013, 4, 28, 9, 0).strftime(print_format)
# => "4/28/2013  9:00"

# In order to convert it to a valid strptime format to parse the same style, we only need to remove the padding modifiers from the format.
format = '%m/%d/%Y %k:%M'
DateTime.strptime('4/28/2013 9:00', format).to_time # DateTime.strptime, given no explicit time zone to parse, assumed the time was UTC. 
# => 2013-04-28 05:00:00 -0400

# The sibling method called _strptime returns a hash of time components.
format = '%m/%d/%Y %k:%M'
time_parts = DateTime._strptime('4/28/2013 9:00', format)
# => {:mon=>4, :mday=>28, :year=>2013, :hour=>9, :min=>0}

# We can convert the time string to a locally-zoned Time object by breaking the string up into parts, then feeding them into Time.local: 
format = '%m/%d/%Y %k:%M'
time_parts = DateTime._strptime('4/28/2013 9:00', format)
time = Time.local(
  time_parts[:year],
  time_parts[:mon],
  time_parts[:mday],
  time_parts[:hour],
  time_parts[:min])
time # => 2013-04-28 09:00:00 -0400

# A gem called "chronic" figures out what time string means and gives us a Time object back:
require 'chronic'
 
time = Chronic.parse('4/28/2013 9:00')
time # => 2013-04-28 09:00:00 -0400<file_sep>require 'logger'

class Picard
  def make_it_so(log=Logger.new($stdout))
    log.info "I have instructed engineering to fix my tea kettle"
    Geordi.new(log).fix_it
  end
end

class Geordi
  def initialize(log)
    @log = log
  end

  def fix_it
    @log.info "Reversing the flux phase capacitance!"
    @log.info "Bounding a tachyon particle beam off of Data's cat!"
    Barclay.new(@log).monitor_sensors
  end
end

class Barclay
  def initialize(log)
    @log = log
  end

  def monitor_sensors
    @log.warn "Warning, bogon levels are rising!"
  end
end

Picard.new.make_it_so
# >> I, [2013-06-04T16:10:03.056063 #11351]  INFO -- : I have instructed engineering to fix my tea kettle
# >> I, [2013-06-04T16:10:03.056286 #11351]  INFO -- : Reversing the flux phase capacitance!
# >> I, [2013-06-04T16:10:03.056336 #11351]  INFO -- : Bounding a tachyon particle beam off of Data's cat!
# >> W, [2013-06-04T16:10:03.056393 #11351]  WARN -- : Warning, bogon levels are rising!

class Picard
  def make_it_so(log=Logger.new($stdout))
    log.info "I have instructed engineering to fix my tea kettle"
    Geordi.new(log, quiet: true).fix_it
  end
end
 
class Geordi
  def initialize(log, quiet: true)
    @log = log
  end

# This device mimics the protocols of our usual ship's log subsystem, but simply discards its input unused. 
class NullLogger
    def debug(*); end
    def info(*); end
    def warn(*); end
    def error(*); end
    def fatal(*); end
  end
  
  log = NullLogger.new
  
  puts "before"
  Picard.new.make_it_so(log)
  puts "after"
  # >> before
  # >> after
  
<file_sep># One way to be kind to users of your code is to include “executable documentation” of these abstract methods using stubs that raise NotImplementedError. 
# LogicalCondition is an abstract class: that is, a class that must be subclassed in order to be used. 
class SpaceAvailableCondition < LogicalCondition
  private
  def condition_holds?
    !client.full?
  end
end
 
class ItemAvailableCondition < LogicalCondition
  private
  def condition_holds?
    !client.empty?
  end
end
# NotImplementedError inherits from ScriptError, which in turn inherits directly from Exception.
begin
    raise NotImplementedError
  rescue
    puts "Rescued error"
  end

def condition_holds?
  raise NotImplementedError, 
        "You must implement a #condition_holds? predicate that "
        "tests whether the condition is currently true"
end
# Now if we try to use a LogicalCondition without subclassing and overriding #predicate_holds?, we get a helpful message telling us what we did wrong.
# users of the class can also read through the class source code and easily see the methods which are required but not provided.<file_sep># This line now does three things: it reads up to 1k of the file.
# Then it assigns the resulting string (or nil value) to the chunk variable.
book = open('../../books/confident-ruby/confident-ruby.org')
lines = 0
while chunk = book.read(1024)
  lines += chunk.count("\n")
end
puts lines
# the use of the chunk variable is neatly contained within the loop it pertains to.
# If we were to ever remove the loop, we wouldn't be leaving a dangling variable behind.

# A convention that some Ruby programmers use to avoid this confusion is to always
# surround loop conditions containing inline assignment with a set of parentheses.
while(chunk = book.read(1024))
  lines += chunk.count("\n")
end

# inline assignment in tests:
class SiteVisit
  attr_reader :timestamp
  def initialize
    @timestamp = Time.now
  end
end
# require 'rspec/autorun'
# describe SiteVisit do
#   it 'sets timestamp to the current time' do
#     expected_time = Time.new(2013, 1, 1)
#     Time.stub(now: expected_time)
#     visit = SiteVisit.new
#     visit.timestamp.should eq(expected_time)
#   end
# end
# We can save some typing in this test by inlining the assignment of the expected_time into the definition of the Time.now stub:
require 'rspec/autorun'
describe SiteVisit do
  it 'sets timestamp to the current time' do
    Time.stub(now: expected_time = Time.new(2013, 1, 1))
    visit = SiteVisit.new
    visit.timestamp.should eq(expected_time)
  end
end
# for quickly naming the return value of one stubbed method, this idiom is convenient.
<file_sep>open("jabberwocky.txt").each_line.grep(/Jabberwock/) # the File#each_line method returns an enumerator over a file's lines. we pass a regex.
# => ["\"Beware the Jabberwock, my son!\n",
#     "The Jabberwock, with eyes of flame,\n",
#     "\"And hast thou slain the Jabberwock?\n"]

# passing a block to #grep:
open("jabberwocky.txt").each_line.grep(/Jabberwock/) do |line|
  puts "MATCH: #{line}"
end
# >> MATCH: "Beware the Jabberwock, my son!
# >> MATCH: The Jabberwock, with eyes of flame,
# >> MATCH: "And hast thou slain the Jabberwock?

# we can break out early, without the expense of processing all of the elements.
open("jabberwocky.txt").each_line.grep(/Jabberwock/) do |line|
  break if line =~ /slain/
  puts "MATCH: #{line}"
end
# >> MATCH: "Beware the Jabberwock, my son!
# >> MATCH: The Jabberwock, with eyes of flame,

# grep can be used to match any kind of object in a collection
# it makes use of Ruby's “case-equality”, or “threequals” operator. 
case object
when 23 then "the number 23" # matches an object based on value
when /foo/ then "contains foo" # a matching regex
when Float then "a floating-point number" # the class
when /2..10/ then "between 2 and 10" # a range of values
end

# comparing the argument against the collection's elements using the threequals operator:
[87, 23, 15, 74, 62, 42, 91].grep(0..50)
# => [23, 15, 42]
(0..50) === 23                    # => true
(0..50) === 87                    # => false

# inventing our own pattern objects for matching, since #grep implements the threequals:
# we want to find ratios based on their from and to properties.
class Feet; end
class Meters; end

ConversionRatio = Struct.new(:from, :to, :number) do
  def self.registry
    @registry ||= []
  end

  def self.find(from, to)                                                 # one way: passing a block to #detect.
    registry.detect{|ratio| ratio.from == from && ratio.to == to} 
  end
end

ConversionRatio.registry << 
  ConversionRatio.new(Feet, Meters, 0.3048) <<
  ConversionRatio.new(Meters, Feet, 3.28084)


require "./ratio"

RatioPattern = Struct.new(:from, :to) do
  def ===(other)
    from == other.from && to == other.to
  end
end

ConversionRatio.registry.grep(RatioPattern.new(Feet, Meters))             # second way: grep with an instance of this object.
# => [#<struct ConversionRatio from=Feet, to=Meters, number=0.3048>]

# third way : set up a lambda that lookds for what we want, passing it to #grep:
require "./ratio"

pattern = ->(ratio) { ratio.from == Meters && ratio.to == Feet }
ConversionRatio.registry.grep(pattern)                            # Ruby Proc objects alias threequals to the #call method (the pattern variable.
# => [#<struct ConversionRatio from=Meters, to=Feet, number=3.28084>]
# pattern === ConversionRatio.new(Meters, Feet, 3.28084) # => true














# with #grep we pass the pattern as an argument<file_sep># Ruby provides a shortcut for reading a file into memory and dividing it into lines all at once. It's called File.readlines.
lines = File.readlines("mail.txt", "\r\n") # Filename and an optional delimeter string that indicates linebreaks.
lines
# => ["MIME-Version: 1.0\r\n",
#     "Received: by 10.112.223.164 with HTTP; Tue, 2 Sep 2014 15:17:21 -0700 (PDT)\r\n",
#     "Date: Tue, 2 Sep 2014 18:17:21 -0400\r\n",
#     "Delivered-To: <EMAIL>\r\n",
#     "Message-ID: <<EMAIL>>\r\n",
#     "Subject: TPS Reports\r\n",
#     "From: <NAME> <<EMAIL>>\r\n",
#     "To: <NAME> <<EMAIL>>\r\n",
#     "Content-Type: text/plain; charset=UTF-8\r\n",
#     "\r\n",
#     "Yeah... if you could just fill out your TPS reports... that'd be great...\r\n"]

lines = File.readlines("mail.txt", "\r\n")
line = lines.shift until line == "\r\n" # removes first element of the array.
lines.join
# => "Yeah... if you could just fill out your TPS reports... that'd be great...\r\n"


# In a single line of chained message sends:
# drop_while takes a block. The block receives one line at a time, and functions as a predicate.
# The method drops items, until it finds one that fails the predicate.
# By contrast, the version using #drop_while leaves the list of lines untouched
File.readlines("mail.txt", "\r\n").drop_while{|l| l != "\r\n"}
# => ["\r\n",
#     "Yeah... if you could just fill out your TPS reports... that'd be great...\r\n"]

File.readlines("mail.txt", "\r\n").drop_while{|l| l != "\r\n"}.drop(1) # #drop drops however many elements are requested.
# => ["Yeah... if you could just fill out your TPS reports... that'd be great...\r\n"]


File.readlines("mail.txt", "\r\n").drop_while{|l| l != "\r\n"}.drop(1).join
# => "Yeah... if you could just fill out your TPS reports... that'd be great...\r\n"<file_sep>class Shopper
  def initialize(list)
    @list = list
  end

  attr_accessor :list
end

shared_list = ["bread", "milk", "granola"]
stacey = Shopper.new(shared_list)
avdi   = Shopper.new(shared_list)
stacey.list.concat(["swiss", "brie", "cheddar"])
stacey.list                     # => ["bread", "milk", "granola", "swiss", "brie", "cheddar"]
avdi.list                       # => ["bread", "milk", "granola", "swiss", "brie", "cheddar"]


# When we send the message #concat to the shared list, with the array of new items as an argument, the target array is updated in-place.
# We get the behavior we expect, with both shopper attributes reflecting the new contents.
# Unless you specifically want to create a new combined array rather than append to an existing one, prefer Array#concat over +=.
<file_sep>point = Struct.new(:x, :y)
point # => #<Class:0x00000004da22e0>
point.class # => Class
point.name  # => nil

Point = point
Point # => Point
point # => Point
point.class # => Class
point.name  # => "Point"  #Ruby sets the name of the class or module to the name of the constant. 

Point = Struct.new(:x, :y)
Point.new                       # => #<struct Point x=nil, y=nil>
Point.new(23)                   # => #<struct Point x=23, y=nil>
Point.new(5,7)

p = Point.new(4,5)
p[:x]                           # => 4
p["y"]                          # => 5
p[:x] = 13
p.x                             # => 13
<file_sep>def names
  yield "Ylva"
  yield "Brighid"
  yield "Shifra"
  yield "Yesamin"
end

# break can take an optional argument.
result = names do |name|
  puts name
  break name if name =~ /^S/
end
result
# Shifra
# by passing the matching name to break, we forced the names method to return that string instead of a nil.


f = open('071-break-with-value.org')
f.lines.detect do |line|
  if f.lineno >= 100
    break "<Not Found (Stopped at #{f.lineno}: '#{line.chomp}')>"
  end
  line =~ /banana/
end
# break can not only force a method to return early, it can also override the return value of the method in the process. 
<file_sep># It's not a good idea to load files full of Ruby code more than once if we can avoid it. 
# Where load re-evaluates a file every time it is invoked, require keeps a global list of all the files it has already processed.
# When we require some library in a Ruby program, we don't require a specific filename. We require a feature by name.

require "bigdecimal"            # => true
require "bigdecimal"            # => false # If it has already been loaded, require returns false.

require "bigdecimal" # If we don't require the library first, the result is false.
feature = "bigdecimal"
 
load_path = $LOAD_PATH.dup
if feature[0] == "."
  load_path.unshift(".")
end
globs = load_path.map{|base_dir| # get a set of file glob patterns by mapping over the load path.
  File.expand_path("#{feature}.*", base_dir) # .* appended, which is a file glob pattern that should match any file extension.
}
globs

files = Dir.glob(globs)
# => ["/home/avdi/.rubies/ruby-2.1.2/lib/ruby/2.1.0/x86_64-linux/bigdecimal.so"]
 
library = files.first
 
$LOADED_FEATURES
# => ["enumerator.so",

$LOADED_FEATURES.include?(library)
# => true<file_sep>objects = ["house", "mouse", "", "mush", "",
"little old lady whispering 'hush'"]

objects.each do |o|
puts "Goodnight, #{o}"
end
# >> Goodnight, house
# >> Goodnight, mouse
# >> Goodnight,
# >> Goodnight, mush
# >> Goodnight,
# >> Goodnight, little old lady whispering 'hush'

# A conditional statement around the puts:

objects.each do |o|
unless o.empty?
puts "Goodnight, #{o}"
end
end
# >> Goodnight, house
# >> Goodnight, mouse
# >> Goodnight, mush
# >> Goodnight, little old lady whispering 'hush'

# Using the next keyword to tell Ruby to skip to the next iteration:

objects.each do |o|
next if o.empty?
puts "Goodnight, #{o}"
end
# >> Goodnight, house
# >> Goodnight, mouse
# >> Goodnight, mush
# >> Goodnight, little old lady whispering 'hush'

# next skips to the next iteration, whereas break breaks completely out of the method
# that the block has been passed into (in this case: each).


# As a variable, using map and without next: 

objects = ["house", "mouse", "", "mush", "",
"little old lady whispering 'hush'"]

result = objects.map do |o|
"Goodnight, #{o}"
end

# an array of strings
result 
# => ["Goodnight, house",
#     "Goodnight, mouse",
#     "Goodnight, ",
#     "Goodnight, mush",
#     "Goodnight, ",
#     "Goodnight, little old lady whispering 'hush'"]

# Using next:

result = objects.map do |o|
next if o.empty?
"Goodnight, #{o}"
end

result
# => ["Goodnight, house",
#     "Goodnight, mouse",
#     nil,
#     "Goodnight, mush",
#     nil,
#     "Goodnight, little old lady whispering 'hush'"]

# We now know that the return value of a block invocation which is skipped by next is nil.
# Using compact to filter out all the nil entries:

result = objects.map do |o|
next if o.empty?
"Goodnight, #{o}"
end

result.compact
# => ["Goodnight, house",
#     "Goodnight, mouse",
#     "Goodnight, mush",
#     "Goodnight, little old lady whispering 'hush'"]<file_sep># The __FILE__ variable always contains the absolute path of the file it is found in.
# The first argument to File.expand_path is the path to be expanded, and the second is the base path to start from. 
__FILE__
# => /myapp/bin/hello
 
File.expand_path "..", __FILE__
# => /myapp/bin
 
File.expand_path "../..", __FILE__
# => /myapp
 
File.expand_path "../../cow_helpers", __FILE__
# => /myapp/cow_helpers
 
require File.expand_path("../../cow_helpers", __FILE__)
 
print CowHelpers.moo "Hello, world"<file_sep>class Point1
  def self.my_new(*args, &block)
    instance = allocate
    instance.my_initialize(*args, &block)
    instance
  end

  def my_initialize(x,y)
    @x = x
    @y = y
  end
end

p = Point1.my_new(3,5)

class Point2
  def self.new_cartesian(x, y)
    instance = allocate
    instance.initialize_cartesian(x, y)
    instance
  end

  def self.new_polar(distance, angle)
    instance = allocate
    instance.initialize_cartesian(polar_to_cartesian(distance, angle))
    instance
  end
  # ...
end

class Snowflake
  class << self
    private :new
  end

  def self.instance
    @instance ||= new
  end
end

Snowflake.instance # => #<Snowflake:0x00000004af4db8>
Snowflake.instance # => #<Snowflake:0x00000004af4db8>

Snowflake.new # =>
# ~> -:14:in `<main>': private method `new' called for Snowflake:Class (NoMethodError)

class RpsMove
 def self.new(move)
   @cache ||= {}
   @cache[move] ||= super(move)
 end

 def initialize(move)
   @move = move
 end
end

RpsMove.new(:rock) # => #<RpsMove:0x00000004967428 @move=:rock>
RpsMove.new(:rock) # => #<RpsMove:0x00000004967428 @move=:rock>
<file_sep>width  = 960
height = 600
recording_options = %W[-f x11grab -s #{width}x#{height} -i 0:0+800,300 -r 30]
misc_options      = %W[-sameq -threads 6]
output_options    = %W[screencast.mp4]

ffmpeg_flags =
    recording_options +
    misc_options +
    output_options

system "ffmpeg", *ffmpeg_flags
<file_sep># Our deprecation warnings shouldn't be going to standard output; they should be going to the standard error stream.
def old_and_busted
  $stderr.puts "#old_and_busted is deprecated. Use #new_hotness instead." # sending the puts message to the $stderr global.
  puts "Hello, world"
end

def new_hotness
  puts "Salutations, universe!"
end
# The warn method is like puts, only instead of defaulting to standard output, it uses $stderr.
def old_and_busted
  warn "#old_and_busted is deprecated. Use #new_hotness instead."
  puts "Hello, world"
end<file_sep> class PersonalAccount
  def display(r)
    r.name("#{first_name} #{last_name}")
    r.email(email)
  end
end

class CorporateAccount
  def display(r)
    r.name(company_name)
    r.email(email)
    r.tax_id(tax_id)
  end
end

class TrialAccount
  def display(r)
    r.name("Trial Account User")
    r.email(email)
  end
end
# renderers
class CsvRenderer
  def initialize(destination)
    @csv = CSV.new(destination)
  end

  def method_missing(name, value=nil)
    @csv << [name, value]
  end
end

class HtmlAccountRenderer
  def method_missing(name, value=nil)
    instance_variable_set("@#{name}", value)
  end

  def render
    <<"END"
<div class="account vcard">
  <p>
    Account details for:
    <span class="email">#{@email}</span>
  </p>
  <p class="fn">#{@name}</p>
</div>
END
  end
end

pa = PersonalAccount.new("Tom", "Servo", "<EMAIL>")

ca = CorporateAccount.new(
  "Yoyodyne",
  "<EMAIL>")

ta = TrialAccount.new("<EMAIL>")
# using the renderer
puts "Personal Account:"
renderer = HtmlAccountRenderer.new
pa.display(renderer)
puts renderer.render

puts "\nCorporate Account:"
renderer = HtmlAccountRenderer.new
ca.display(renderer)
puts renderer.render

puts "\nTrial Account:"
renderer = HtmlAccountRenderer.new
ta.display(renderer)
puts renderer.render
<file_sep>require 'delegate'
class AuditedAccount < SimpleDelegator # SimpleDelegator enables us to augment the methods we care about, and ignore all the others.
  def initialize(account, audit_log)
    super(account) #
    @audit_log = audit_log
  end

  def deposit(amount)
    super
    @audit_log.record(number, :deposit, amount, balance_cents)
  end

  def withdraw(amount)
    super
    @audit_log.record(number, :withdraw, amount, balance_cents)
  end
end
# Thnaks to the delegate library, if we compare the raw account and the decorated account, the result is true.
# This helps ensure that delegator objects are usable as drop-in replacements for the raw object in as many contexts as possible.

require "./bank_account"
require "./audit_log"
require "./audited_account"

account = BankAccount.new(123456)
log = AuditLog.new

aa = AuditedAccount.new(account, log)

account.number                  # => 123456
aa.number                       # => 123456

aa == account                   # => true

# Defining a variant of AuditedAccount using DelegateClass(invoking a global method):

require "./bank_account"
require "delegate"

DelegateClass(BankAccount) # Providing the name of the class we intend to decorate(generates a new base class at runtime).
# => #<Class:0x007f9daf5f9c50>

require "delegate"
require "./bank_account"

class AuditedAccount2 < DelegateClass(BankAccount) # Instances of this class will respond to the number attribute(because it generates proxy methods ahead of time).
  def initialize(account, audit_log)
    super(account)
    @audit_log = audit_log
  end

  def deposit(amount)
    super
    @audit_log.record(number, :deposit, amount, balance_cents)
  end

  def withdraw(amount)
    super
    @audit_log.record(number, :withdraw, amount, balance_cents)
  end
end

require "./bank_account"
require "./audit_log"
require "./audited_account"
require "./audited_account2"

account = BankAccount.new(123456)
log = AuditLog.new

aa1 = AuditedAccount.new(account, log)
aa2 = AuditedAccount2.new(account, log)

aa1.number                      # => 123456
aa2.number                      # => 123456

AuditedAccount.instance_methods.include?(:number)
# => false

AuditedAccount2.instance_methods.include?(:number)
# => true

require "./bank_account.rb"

class InterestAccount < BankAccount
  def interest_rate
    1.3
  end
end

require "./interest_account"
require "./audit_log"
require "./audited_account2"

account = InterestAccount.new(123456)
aa = AuditedAccount2.new(account, AuditLog.new) # DelegateClass-generated classes just fall back to dynamic method discovery when forwarding to a method they don't know about.

account.interest_rate           # => 1.3
aa.interest_rate                # => 1.3

# If we know exactly the class we plan on wrapping, we might as well use DelegateClass (better performance and introspection).
# To minimize dependencies or to decorate a range of similar classes, SimpleDelegator is an easy choice.<file_sep>a1 = [:first, :second, :third, :fourth]
a2 = [:before, a1, :after]
a2.flatten
# => [:before, :first, :second, :third, :fourth, :after]
a2 = [:before, *a1, :after]
# => [:before, :first, :second, :third, :fourth, :after]

# We prefix a1 with an asterisk, telling Ruby to “splat it out” into its component elements rather than inserting the array object.
a1 = [:first, :second, :third, :fourth]
x, y, z = *a1
x                               # => :first
y                               # => :second
z                               # => :third

a1 = [:first, :second, :third, :fourth]
*x, y, z = *a1
x                               # => [:first, :second]
y                               # => :third
z                               # => :fourth

a1 = [:first, :second, :third, :fourth]
first, *rest = *a1

first                           # => :first
rest                            # => [:second, :third, :fourth]
# with methods:
def sum3(x, y, z)
  x + y + z
end

triangle = [90, 30, 60]
sum3(*triangle)                 # => 180

def random_draw(num_times, num_draws)
  num_times.times do
    draws = num_draws.times.map { rand(10) }
    yield(*draws)
  end
end

random_draw(5, 3) do |first, second, third| # five times, 3 numbers.
  puts "#{first} #{second} #{third}"
end
# >> 9 5 3
# >> 3 8 1
# >> 4 7 6
# >> 2 1 3
# >> 8 3 3

# By applying a splat to the last parameter, we force it to “soak up” all remaining arguments (if any) into a new array.
def random_draw(num_times, num_draws)
  num_times.times do
    draws = num_draws.times.map { rand(10) }
    yield(*draws)
  end
end

random_draw(5, 3) do |first, *rest|
  puts "#{first}; #{rest.inspect}"
end
# >> 7; [7, 0]
# >> 6; [6, 9]
# >> 6; [6, 2]
# >> 2; [2, 3]
# >> 3; [2, 2]
<file_sep>
puts "__FILE__: #{__FILE__}"
puts "expand_path: #{File.expand_path("..", __FILE__)}"
puts "__dir__: #{__dir__}"

# Moving the file to a subdirectory and then running it:

$ mkdir foo
$ mv whereami.rb foo
$ ruby foo/whereami.rb
__FILE__: foo/whereami.rb
expand_path: /home/avdi/Dropbox/rubytapas/245-current-dir/foo
__dir__: /home/avdi/Dropbox/rubytapas/245-current-dir/foo


# Evaluating from inside another Ruby program:
# The expand_path version winds up showing the current working directory, rather than the location of the source file.
# __dir__ has a nil value when Ruby doesn't know what file the current code is from.

eval File.read("foo/whereami.rb")
# >> __FILE__: (eval)
# >> expand_path: /home/avdi/Dropbox/rubytapas/245-current-dir
# >> __dir__:

# __dir__ is more honest, while the expand_path version is misleading.<file_sep>@names = %w[<NAME>]

def names
  yield @names.shift # shift returns the first element of self and removes it.
  yield @names.shift
  yield @names.shift
  yield @names.shift
end

enum = to_enum(:names)
@names = %w[<NAME>]
enum.rewind
enum.next
# we can drive the method's execution forward as needed by calling #next on the Enumerator.

enum.with_index do |name, index|
  puts "#{index}: #{name}"
end
# An Enumerator takes any method that yields values to a block, and turns it into a lazy, iterable object
# which supports all the convenient methods of Enumerable.
<file_sep># This gives us a Proc object, which we can then assign to variables and pass around.
# When we want the code to execute, we send it the #call method.
greeter = Proc.new do |name|
  puts "Hello, #{name}"
end
greeter                       # => #<Proc:0x0000000410cd00@-:1>
greeter.call("Ylva")
# >> Hello, Ylva
greeter["Kashti"]
greeter.("Josh")

# the lambda version adds the word “lambda” when inspected. They both execute when called.
# One difference is that the lambda version is pickier about arguments.
# The basic Proc just throws away extra arguments, whereas the lambda version reports an error.
greeter_p = proc do |name|
  puts "Hello, #{name}"
end
greeter_l = lambda do |name|
  puts "Hello, #{name}"
end

greeter_p                       # => #<Proc:0x0000000338efe8@-:1>
greeter_l                       # => #<Proc:0x0000000338efc0@-:4 (lambda)>
greeter_p.call("Lily")
greeter_l.call("Stacey")

# There is also an extra short form for writing lambdas, which is sometimes referred to as “stabby lambda” syntax.
# method-style parentheses, instead of vertical pipes.
greeter_l = ->(name) {
  puts "Hello, #{name}"
}

greeter_l                       # => #<Proc:0x000000031fba50@-:1 (lambda)>

#Every Ruby method can implicitly receive a proc argument, which is called using the yield keyword.
def each_child
  yield "Lily"
  yield "Josh"
  yield "Kashti"
  yield "Ebba"
  yield "Ylva"
end

each_child do |name|
  puts "Hello, #{name}!"
end
# >> Hello, Lily!
# >> Hello, Josh!
# >> Hello, Kashti!
# >> Hello, Ebba!
# >> Hello, Ylva!
<file_sep># We use the Hash#fetch method to get the value or provide a default if it is not present.
def order_burger(customer_name, options={})
has_cheese = options.fetch(:cheese)  # This line will raise a KeyError if no :cheese option is specified. 
toppings = []
toppings << :onions if options.fetch(:onions) { true }
toppings << :bacon  if options.fetch(:bacon)  { false  }
patty_type = options.fetch(:patty)  { :beef }

print "That's one #{patty_type} #{has_cheese && "cheese"}burger"
print " with #{toppings.join(', ')}"
print " for #{customer_name}.\n"
end

order_burger("Grimm", cheese: true, bacon: true, onions: false)
# >> That's one beef cheeseburger with bacon for Grimm.
# Ruby lets us omit the braces around a Hash argument if it's the last argument passed to a method. keyword-style arguments.

def order_burger(customer_name, options={})
patty_type = options.delete(:patty)  { :beef } # checks that only known options are specified.
has_cheese = options.delete(:cheese)
toppings = []
toppings << :onions if options.delete(:onions) { true }
toppings << :bacon  if options.delete(:bacon)  { false  }
if options.any?                                             # checks if there are any options left in the hash.    
  raise ArgumentError, "Unrecognized option(s): #{options}"
end

print "That's one #{patty_type} #{has_cheese && "cheese"}burger"
print " with #{toppings.join(', ')}"
print " for #{customer_name}.\n"
end

order_burger("Grimm", cheese: true, bacon: true, onion: false)
# ~> -:8:in `order_burger': Unrecognized option(s): {:onion=>false} (ArgumentError)

# the cheese keyword is a required option, so we don't supply a default for it. 
def order_burger(customer_name, patty: :beef, cheese:, onions: true, bacon: false)
  toppings = []
  toppings << :onions if onions
  toppings << :bacon  if bacon
 
  print "That's one #{patty} #{cheese ? "cheese" : ""}burger"
  print " with #{toppings.join(', ')}"
  print " for #{customer_name}.\n"
end

# With just a “cheese” option, it supplies the defaults for patty type and toppings. 
order_burger("Grimm", cheese: true)
# >> That's one beef cheeseburger with onions for Grimm.<file_sep># exceptions for flow control? That's where code raises an exception, not to signal an error,
# but in order to make an early escape from a deeply nested chain of method calls.
class ExcerptParser < Nokogiri::XML::SAX::Document
    
      class DoneException < StandardError; end
    
      # ...
    
      def self.get_excerpt(html, length, options)
        me = self.new(length,options)
        parser = Nokogiri::HTML::SAX::Parser.new(me)
        begin
          parser.parse(html) unless html.nil?
        rescue DoneException                           #
          # we are done
        end
        me.excerpt
      end
    
      # ...
    
      def characters(string, truncate = true, count_it = true, encode = true)
        return if @in_quote
        encode = encode ? lambda{|s| ERB::Util.html_escape(s)} : lambda {|s| s}
        if count_it && @current_length + string.length > @length
          length = [0, @length - @current_length - 1].max
          @excerpt << encode.call(string[0..length]) if truncate
          @excerpt << "…"
          @excerpt << "</a>" if @in_a
          raise DoneException.new
        end
        @excerpt << encode.call(string)
        @current_length += string.length if count_it
      end
end

# in order to get a page excerpt, the ExcerptParser only needs to collect text from the HTML page until it reaches the desired excerpt length.
# this class needs to be able to “break out” of the parser and signal the code that started the parse that it has all it needs (by raising an exception).

class ExcerptParser < Nokogiri::XML::SAX::Document
 
  # ...
 
  def self.get_excerpt(html, length, options)
    me = self.new(length,options)
    parser = Nokogiri::HTML::SAX::Parser.new(me)
    catch(:done) do   #If at any point code executed within this block “throws” the symbol :done, catch will do exactly what it sounds like – catch the symbol.
      parser.parse(html) unless html.nil? #Execution will then proceed onward from the end of the catch block.
    end
    me.excerpt
  end
 
  # ...
 
  def characters(string, truncate = true, count_it = true, encode = true)
    return if @in_quote
    encode = encode ? lambda{|s| ERB::Util.html_escape(s)} : lambda {|s| s}
    if count_it && @current_length + string.length > @length
      length = [0, @length - @current_length - 1].max
      @excerpt << encode.call(string[0..length]) if truncate
      @excerpt << "…"
      @excerpt << "</a>" if @in_a
      throw :done  #We change the raise to a throw. When the ExcerptParser finds it has enough text for an excerpt, it “throws” the :done symbol.
    end
    @excerpt << encode.call(string)
    @current_length += string.length if count_it
  end
end

# the code no longer suggests an error condition where there actually is none.
# By contrast, with a begin/rescue/end block we have to skip down to the end of code in question to see what errors might occur.
# This is fine for errors, but less fine for perfectly normal early returns.<file_sep>require 'pp'
[0,1,2,3,4,5,6,7,8,9].each_slice(2) do |slice|
  pp slice
end
# >> [0, 1]
# >> [2, 3]
# >> [4, 5]
# >> [6, 7]
# >> [8, 9]

# But if we call it without a block, it returns an Enumerator.
# chaining enumerable operations:
require 'pp'
sums = [0,1,2,3,4,5,6,7,8,9].each_slice(2).map do |slice|
 slice.reduce(:+)
end
sums # => [1, 5, 9, 13, 17]

# how to duplicate this behavior in our own methods:
def names
  return to_enum(:names) unless block_given? # return to_enum(__callee__) to ensure that if we ever change the name of the method the call to #to_enum will continue to work.
  yield "Ylva"
  yield "Brighid"
  yield "Shifra"
  yield "Yesamin"
end

names                           # => #<Enumerator: main:names>
names.to_a                      # => ["Ylva", "Brighid", "Shifra", "Yesamin"]
<file_sep>headers = <<END
Accept: */*
Set-Cookie: foo=42
Set-Cookie: bar=23
END

def parse_headers(headers)
  headers.lines.reduce({}) do |result, line|
    name, value = line.split(":")
    result.merge(name.strip => value.strip)
  end
end

  p parse_headers(headers)

# A better implementation might collect value of repeated headers into an array.
# We can supply an optional block to the #merge method. When there's a key collision, this block will be used to determine how to resolve it.

def parse_headers(headers)
  headers.lines.reduce({}) do |result, line|
    name, value = line.split(":")
    result.merge(name.strip => value.strip) {
      |key, left, right|                              #
      Array(left) + Array(right)
    }
  end
end
 
p parse_headers(headers)


accounting = {
    "burger" => 3,
    "cheesesteak" => 1,
    "veggie wrap" => 2
  }
  
  engineering = {
    "burger" => 2,
    "gyro" => 3
  }
  
  marketing = {
    "burger" => 1,
    "veggie wrap" => 2,
    "gyro" => 1
  }
  
order = [accounting, engineering, marketing].reduce({}) {
    |result, dept|
    result.merge(dept) {
        |key, left, right|
        left + right
    }
}
order
# => {"burger"=>6, "cheesesteak"=>1, "veggie wrap"=>4, "gyro"=>4}
  
#In the block we just ignore the right-hand value entirely(trance), and always use the left-hand one(drum&bass).
options = { genre: "drum&bass" }
full_options = options.merge(genre: "trance", bpm: 140){|_, left, _| left}
full_options
# => {:genre=>"drum&bass", :bpm=>140}

#  by passing a block to #merge, we can easily achieve any Hash-merging strategy we can think up.<file_sep>def names
  yield "Ylva"
  yield "Brighid"
  yield "Shifra"
  yield "Yesamin"
ensure
  puts "Grimm"
end

names do |name|
  puts name
  break if name =~ /^S/
end

# Ylva
# Brighid
# Shifra
# Grimm

# break is not just for loops and iteration. It can force an early return from any method that yields.
# While break can end a method's execution early, it still respects ensure blocks.
