Learn Ruby the Hard Way ex40

cities = {'CA' => 'San Francisco',
      'ML' => 'Detroit',
      'FL' => 'Jacksonville'}
   
cities['NY'] = 'New York'
cities['OR'] = 'Portland'
    
def find_city(map, state)
    if map.include? state
       return map[state]
   else
      return "Not Found"
   end
 end

#ok pay attention!
cities[:find]= method(:find_city)

while true
  print "State? (Enter to quit) "
  state = gets.chomp
  break if state.empty?
  #this line is the most impotant ever! study!
  puts cities[:find].call(cities, state)
end

Witam jestem tu nowy :slight_smile: Zacząłem swoją naukę z Ruby od LRtHW miesiąc temu, doszedłem do tego zadania i padłem.

Co rozumiem,…

Cities to tablica alokacyjna (hash) ktora za klucz przyjmuje skrót stanu, by wypisać miasto (wartość)

Następnie definiowana jest funkcja find_city która przyjmuje 2 argumenty, (map i state) choć te nazwy są mało istotne. Łapie że pierwszy argument to nazwa tablicy w której będzie szukać klucza, czyli drugiego argumentu i jeżeli go znajdzie zwraca wartość tego klucza (return map[state]) w przeciwnym wypadku wypisuje “Not found”. To jeszcze rozumiem ale…

cities[:find]= method(:find_city)

Tego nie rozumiem, to jest przypisanie hashu do funkcji find city ? Dlaczego symbole? (ma to pewnie jakis zwiazek z tym że symbole stosowane sa jako klucze w hashu)

Dalej…

while true
  print "State? (Enter to quit) "
  state = gets.chomp
  break if state.empty?
  puts cities[:find].call(cities, state)
end

Pętla while, będzie wykonywać się do momentu aż state==nil. Użytkownik podaje nazwę stanu i co dalej … jak state trafia do funkcji find_city? Z ostatniej linii kodu rozumiem że cities[:find] wywołuje (.call) funkcje find_city i podaje wymagane argumenty. Ale jest to wszystko dla mnie mocno mgliste… Może ktoś pomorze i wyjaśni czy właściwie rozumiem lub co było by bardzo miłe, trochę naświetli mi co tu się dzieje :grin:

cities[:find]=method(:find_city)

Podstawia Ci do istniejącego hasha cities, pod kluczem :find, obiekt reprezentujący metodę find_city.
Taki obiekt jest klasy Method (tu masz api dla ruby 2.0 http://ruby-doc.org/core-2.0.0/Method.html ), między innymi ma metodę call, która dla tej instancji Method wywołuje find_city.

1 Like

Mazowsze tutaj :smile:

Szczerze mówiąc, to ten przykład jest mocno z czapy i niczemu nie służy, oprócz pokazania, że takie zachowanie występuje w Rubym. Już bardziej jasnym przykładem byłoby:

cities = {'CA' => 'San Francisco',
          'ML' => 'Detroit',
          'FL' => 'Jacksonville'}

cities['NY'] = 'New York'
cities['OR'] = 'Portland'

cities.instance_eval do
  # find_city jest definiowane "w locie" jako metoda instancji cities
  def find_city(state)
    if self.include?(state)
      return self[state]
    else
      return "Not Found"
    end
  end

  # to wszystko można również zapisać jako
  def find_city2(state)
    self.fetch(state, "Not found")
  end
end

# przypisujesz metodę find_city instancji cities do lokalnej zmiennej
# zauważ, że ona wciąż ma informacje o swoim "rodzicu", czyli również o 
# trzymanym hashu
find_city = cities.method(:find_city)
# ewentualnie:
#find_city = cities.method(:find_city2)

while true
  print "State? (Enter to quit) "
  state = gets.chomp
  break if state.empty?

  #this line is the most impotant ever! study!
  puts find_city.call(state)
end

Btw. empty? Nie sprawdza czy jest nil. Zależy od klasy obiektu. Pusty string nie jest nilem, ale jest empty. Tak samo pusta tablica. Nie myl tego później, bo można się przejechać :wink:

1 Like

Dzięki za wyjaśnienie tego problemu żarówki płoną pełną mocą… plus dzięki za wypomnienie błędu różnicy nil i empty :smiley: na początku najłatwiej łapać błędy.

Jako że jesteście tacy pomocni dla nowicjuszy programowania. Ostrzegam że będę męczył Was częściej :grin: