Bloki ir ļoti vērtīga un ērta lieta, ko piedāvā Ruby. Parasti izmantojot blokus Ruby vai Ruby on Rails, visierastākais veids ir izsaukt metodi ar bloku un atpakaļ padot bloka mainīgos. Šoreiz gribu parādīt veidu kā izsaukt citu bloku nevis to kas ir palaists.

Ierastais veids kā parasti tiek saukti bloki iekš RoR

Ierastais bloku izsaukums ar metodi un mainīgo atgriešanu. Piemērs rāda, logout pogas attēlošanu.

def logout_link(user)
    if user.sign_in?
        yield
    end
end

Iekš view tas varētu izskatīties apmēram šādi.

<% logout_link(user) do %>
    <%= link_to "Logout", user_logout_path %>
<% end %>

Veids kā izsaukt citu bloku padotā vietā

Piemērs gan nav RoR bet tikai Ruby bet būtību tas nemaina, vai tas tiek saukt no view, vai helper vai vienalga no kurienes. Ideja ir šāda:

  • ir cilvēku klase
  • cilvēkiem ir šāds vai savādāks prāta stāvoklis (state)
  • cilvēki var tikt atapzīti (pieņemsim, ka no citu cilvēku puses), uz ko katrs var reaģēt individuāli, bet tas kurš veic atpazīšanu gaida kādu noteiktu reakciju.
  • ja cilvēkam nav sava individuālā reakcija tad viņš atbild tā kā atpazinējs ir gaidījis
  • ja ir cita reakcija, tad reaģē sev individuālā veidā

 

Vispirms es izveidoju Human klasi

class Human
  attr_accessor :reaction

  def initialize(state)
    @state=state
  end

  def acts_on_recognition_by &individual_reaction
    self.reaction=individual_reaction
  end

  def show_face
    "I show my face because I'm #{@state}"
  end

  def hide_face
    "I hide my face because I'm #{@state}"
  end

  def recognize person, &default_reaction
    if person.reaction
      person.reaction.call(person)
    else 
      default_reaction.call(person)
    end
  end

end

Tātad kas ir klasē, principā viss tas, ko jau iepriekš minēju. Katram cilvēkam ir noteikts stāvoklis (state). Katrs var reaģēt citādi uz atpazīšanu, un katrs cilvēks var atpazīt kādu citu cilvēku. Un vēl esmu pielicis divas metodes, kas atgriež kaut kādu informāciju ( hide_face, show_face).

Izveidoju trīs veida cilvēkus.

normal_person=Human.new("guiltless")
policeman=Human.new("fearless")
criminal=Human.new("guilty")

Normālo cilvēku, kurš ir “nevainīgs”, policistu, kurš ir “bezbailīgs” un noziedznieku, kurš ir “vainīgs”. Tā kā noziedzieks ir vainīgs viņš negrib tikt atpazīts.

criminal.acts_on_recognition_by do |person|
  person.hide_face
end

Tāpēc, ja kāds mēģina viņu atpazīts, tad šī persona slēpj savu seju.

Tālāk policists šīs abas personas mēģina atpazīt un reakcija ko viņš sagaida ir seja parādīšana.

normal_person_reaction=policeman.recognize(normal_person){|person|
  person.show_face
}

criminal_reaction=policeman.recognize(criminal){|person|
  person.show_face
}
puts normal_person_reaction
puts criminal_reaction

Un rezultātā mēs varam redzēt, kā reaģēt katrs no cilvēkiem.

I show my face because I'm guiltless
I hide my face because I'm guilty

Kas šeit notiek?

Metode recognize tiek izsaukta ar bloku, kas ir jāizsauc tikai tad ja personai nav savas reakcijas, tā kānormla_person tādas nav, tad tiek izpildīts padotais bloks un persona parāda seju. Bet tā kā criminal ir individuāla reakcija uz atpazīšanu, tad šai personai tiek izsaukts bloks, kas ir iepriekš definēts ar metodiacts_on_recognition_by. Un rezultātā viena bloka vietā tiek izsaukts cits. Kāds ir ieguvums? Ir iespējams izveidot HTML wrapperus, kas vienu bloku aizvieto ar citu vai papildināt bloku ar ko citu. Piemēram, vienmēr iekš form_for, beigās parādīt savas pogas, vai tamlīdzīgi. Atšķirībā no yield, kas vienmēr atgriežas pie padotā bloka, šajā gadījumā var atgriezties pie cita bloka.

Varbūt esmu palaidis ko garām vai ir kādas kļūdas, droši dodiet ziņu komentāros. Ceru, ka kādam šis noderēs!