An przegląd kontekstu wykonania bloków
W tym artykule będziemy badać następujące tematy:
- zakresy i bloki
- flat scope guard w klasie/module
Na początek zapraszam do przejrzenia artykułu Scope Gates in Ruby: Part II article.
Zanim zaczniemy
Jestem zachwycony mogąc podzielić się z Tobą naszym najnowszym projektem: Fun Facts about Ruby – Volume 1
Please feel free to spread the word and share this link! 🙏
Dziękuję za Twój czas!
W Rubim, blok może uzyskać dostęp do zewnętrznego zakresu
W tym przykładzie, możemy uzyskać dostęp do zmiennej outer_scope_variable
wewnątrz naszego bloku. Nasz blok uzyskuje dostęp do tej zmiennej, mimo że zmienna jest zadeklarowana w zakresie poziomu main
. W tym przypadku mówimy, że blok spłaszcza zakresy. Dlatego też potocznie nazywamy ten mechanizm: Flat Scope.
Z drugiej strony, blok tworzy izolowany zakres – nawet jeśli wartość self
w obrębie bloku pozostaje obiektem main
.
Nie mamy więc dostępu do zmiennych lokalnych zdefiniowanych w obrębie bloku
Tutaj nie mamy dostępu do block_variable
z zewnętrznego zakresu. Teraz, gdy jesteśmy bardziej zaznajomieni z pojęciem płaskiego zakresu w Rubim, zobaczmy czy to pojęcie ma wpływ na definicję klasy.
Klasa, moduł i blok
W Rubim, to co powszechnie nazywamy klasą jest, za sceną, instancją klasy Class
Tutaj tworzymy klasy Hello
i Greeting
na dwa różne sposoby:
- używając słowa kluczowego
class
- przypisując instancję klasy
Class
do stałejGreeting
Zauważ, że przekazujemy blok do metody Class.new
. Blok ten zostanie zinterpretowany jako zawartość klasy. Normalnie klasa nie może mieć dostępu do zmiennych zdefiniowanych w zewnętrznym zakresie – ponieważ słowo kluczowe class
zmienia wartość self
i tworzy izolowany zakres.
Więc, skoro używamy bloku do stworzenia naszej klasy Greeting
to powinniśmy móc korzystać z mechanizmu płaskiego zakresu. Naprawdę?
W tym miejscu widzimy, że wartość self
zmienia się, gdy używamy class
lub Class.new
.
Ale nasz blok Class#message
jest nadal odizolowany od obiektu main
z powodu użycia słowa kluczowego def
. W istocie, ponieważ nasz blok jest wykonywany w kontekście metody, wtedy blok spłaszcza zakres w obrębie tego danego obiektu – a nie z wyższym zakresem jak obiekt main
.
Dlatego nie mamy dostępu do outer_variable
w obrębie message
.
Ale jeśli użyjemy define_method
do zdefiniowania message
to zakres jest spłaszczony
Tutaj, ponieważ define_method(:message)
przyjmuje blok jako argument, zakres tego bloku jest spłaszczony i ta metoda ma dostęp do outer_variable
.
Voilà!
.