• Главная
  • Карта сайта
Не найдено

Ruby / Методика самопізнання

  1. Методика самопізнання [ правити ] Ruby дуже динамічний мову програмування, а це значить, що з...
  2. Якого класу належить об'єкт? [ правити ]
  3. Від якого класу успадкований цей клас? [ правити ]
  4. Які класи / модулі використовувалися цим класом? [ правити ]
  5. Як отримати список домішок класу? [ правити ]
  6. Як отримати список всіх батьківських класів? [ правити ]
  7. Чи є даний об'єкт екземпляром цього класу? [ правити ]
  8. А як порівнювати класи між собою? [ правити ]
  9. Які константи доступні? [ правити ]
  10. Ця константа оголошена? [ правити ]
  11. Як на ім'я константи отримати її значення? [ правити ]
  12. Які класи доступні для використання? [ правити ]
  13. Як змінити значення константи? [ правити ]
  14. Які змінні доступні? [ правити ]
  15. Які глобальні змінні доступні? [ правити ]
  16. Які локальні змінні доступні? [ правити ]
  17. Яку інформацію можна отримати про змінних екземпляра? [ правити ]
  18. Яку інформацію можна отримати про змінних класу? [ правити ]
  19. Які методи доступні? [ правити ]
  20. Чи можна викликати цей метод? [ правити ]

Методика самопізнання [ правити ]

Ruby дуже динамічний мову програмування, а це значить, що з ходом виконання програми стан / структура об'єктів / класів може змінюватися до невпізнання. Здавалося б, програмісти на Ruby - справжнісінькі мазохісти . Можливо це і так, але не через те, що вони програмують на Ruby, так як в нього вбудовано чималі розвинені засоби самопізнання (успадковані від мови Smalltalk ).

Що таке самопізнання? [ правити ]

Якщо мова Ruby настільки динамічний, то як же визначити поточний стан об'єкта або класу? Відповідь очевидна - нам потрібні методи, які дозволять дізнатися всю таємницю про поточний стан об'єкта або класу. Саме ці методи ми і будемо називати методами самопізнання.

Відразу після того, як ми дізналися інформацію про поточний стан, у нас може виникнути непереборне бажання цю інформацію використовувати в своїх цілях. Саме тому ми розглянемо не тільки методи самопізнання, а й методи самомодіфікаціі. Переносити їх в окремий розділ особливого сенсу не має (так як їх дуже мало) і тому вони будуть розглянуті попутно, як би мимохідь.

Методами самомодіфікаціі ми будемо називати такі, які дозволяють змінювати об'єкт або клас на підставі інформації про його поточний стан

Кожен з методів самопізнання відповідає на те чи інше питання про поточний стан. Саме тому всі подальші заголовки будуть виглядати як питання.

Якого класу належить об'єкт? [ правити ]

Мова програмування Ruby є строго типізований (як і більшість інших мов), тобто ніколи не існує невизначеності з приводу класу того чи іншого об'єкта. Довгий час Ruby вважали не строго універсальна мова, але це помилка, яка виникла з динамічної структури мови: клас змінної визначається об'єктом, на який посилається ця змінна і разом зі зміною об'єкта може помінятися і клас змінної.

Довгий час Ruby вважали не строго універсальна мова, але це помилка, яка виникла з динамічної структури мови: клас змінної визначається об'єктом, на який посилається ця змінна і разом зі зміною об'єкта може помінятися і клас змінної

Автори дають невірну інтерпретацію поняття "строго типізований"

Виходячи з вищевикладеного, ми можемо опинитися в ситуації, коли необхідно дізнатися, який клас зберігається в тій чи іншій змінної (або повертається якихось методом). Для цієї мети служить метод .class ( "несподівано", правда?), Який повертає клас, якому належить даний об'єкт.

"Типова рядок". class # -> String 0xface. class # -> Fixnum 9876543210. class # -> Bignum 1234. class. class # -> Class Fixnum. class # -> Class

Зверніть увагу, що метод .class повертає об'єкт класу Class (чергова несподіванка). А чому ж не рядок? Справа в тому, що від класу можна відразу ж викликати методи цього класу. Наприклад, потрібно створити об'єкт точно такого ж класу, як і у змінної my_variable. Тоді ваш код може виглядати наступним чином:

my_variable = [1, 2, 3, 4] my_variable. class # -> Array my_variable. class. new # -> [] Array. new # -> []

Думаю, що нікому не треба пояснювати, яку міць дає подібний механізм. Наприклад, у своїй діяльності мені не раз доводилося створювати масив класів, від кожного з яких викликалися одні і ті ж методи.

У методу .class є синонім .type, але останні версії інтерпретатора видаютьПопередження, що метод .type застарів і надалі зникне з мови

Від якого класу успадкований цей клас? [ правити ]

Іншим інструментом дослідження класової ієрархії є метод .superclass, який призначений для отримання класу батька. Зауважимо, що метод .superclass можна викликати тільки для об'єкта класу Class, який, в свою чергу, можна отримати за допомогою методу .class. Якесь складне визначення вийшло, але давайте розглянемо роботу методу .superclass на прикладі:

Integer. superclass # -> Numeric 123. class. superclass # -> Integer 123. class. superclass. superclass # -> Numeric Numeric. superclass # -> Object Object. superclass # -> nil

З прикладу видно, що за допомогою послідовного виклику методу .superclass можна дізнатися про всю ієрархії успадкування будь-якого класу.

Які класи / модулі використовувалися цим класом? [ правити ]

На перший погляд може здатися дивним таке питання, так як ми вже знаємо метод superclass, що дає нам можливість отримати достовірну інформацію про ієрархії батьківських класів. Справа в тому, що в мові Ruby відсутня множинне спадкування , Яке компенсується механізмом домішок . Ось для того, щоб отримати масив всіх класів / модулів, які відносяться до даного класу і існує метод .ancestors. Подивимося його в справі:

Fixnum. ancestors # -> [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel] Fixnum

Відповідно до негласним правилом, методи, імена яких закінчуються на s повертають масив. Це правило отримало свій подальший розвиток в Ruby on Rails і його слід дотримуватися всім розробникам на Ruby

Зверніть увагу, що поточний клас розташовується нульовим елементом в масиві, а всі інші класи розташовані в порядку спадкування / примешивания.

Як отримати список домішок класу? [ правити ]

Попрацювавши з методом .ancestors може виникнути резонне питання, а що якщо потрібно отримати тільки список домішок без батьківських класів? В принципі, для цього треба знати тільки те, що всі домішки мають клас Module. Дізнатися це можна, якщо виконати простеньку програму:

[Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]. map {| c | c. class} # -> [Class, Class, Module, Class, Module, Class, Module]

Тому, для того, щоб отримати список домішок класу, можна скористатися наступною програмою:

Fixnum. ancestors. select {| c | c. class == Module} # -> [Precision, Comparable, Kernel]

Але навіщо писати більше, якщо для цього є спеціальний метод .included_modules, який повертає список підключених домішок.

Fixnum. included_modules # -> [Precision, Comparable, Kernel]

Ну, а якщо результат однаковий, то для вирішення цього завдання краще викликати один метод .included_modules замість двох (ancestors і .select).

Як отримати список всіх батьківських класів? [ правити ]

Хочу відразу Вас засмутити, що для вирішення цього завдання спеціального методу не існує, а це значить, що завдання будемо вирішувати через уже відомі.

my_variable = 123 class_array = my_variable. class. ancestors - my_variable. class. included_modules # -> [Fixnum, Integer, Numeric, Object] class_array. join ( "<") # -> "Fixnum <Integer <Numeric <Object"

Останній рядок прикладу мені особливо подобається. У ній наочно представлена ​​вся ієрархія наслідування для класу Fixnum. Дуже дивно, що таке питання досить часто виникає, а спеціального методу для його вирішення - немає. Непорядок!

class Class def hierarchy ancestors - included_modules end end Fixnum. hierarchy. join ( "<") # -> "Fixnum <Integer <Numeric <Object"

Щоб знайти списки всіх батьківських класів ми створили метод .hierarchy в класі Class. Батьківські класи повертаються у вигляді масиву об'єктів класу Class. Ось тепер порядок!

Ось тепер порядок

Слід пам'ятати, що підключені домішки і використовувані класи - це поняття, які дійсні тільки для класів (тобто об'єктів класу Class)

Чи є даний об'єкт екземпляром цього класу? [ правити ]

Питання безглуздий, але тим не менш варто того, щоб його освітили. Чому безглуздий? Та тому, що ми запросто можемо дізнатися клас об'єкта за допомогою методу .class і порівняти два класи за допомогою методів == і! =.

Fixnum == 5. class # -> true []. class! = Array # -> false String == Array # -> false

Для подібної ж мети придуманий спеціальний метод .instance_of ?, який дозволяє замінити зв'язку методів .class і ==.

5. instance_of? (Fixnum) # -> true 5. instance_of? (Integer) # -> false []. instance_of? (Array) # -> true String. instance_of? (Array) # -> false String. instance_of? (Class) # -> true 5

Метод .instance_of? можна перекласти російською, як питання "чи є екземпляром класу?"

Зверніть увагу, що число п'ять хоч і є цілим, але метод .instance_of? не визнає його примірників класу Integer. В принципі він має рацію: число п'ять є екземпляром класу Fixnum, а не Integer. Це означає, що метод .instance_of? занадто суворий.

І що ж нам робити, якщо ця строгість нам ні до чого? Для цього можна скористатися методами .class, .ancestors і .include ?, які будуть враховувати не тільки поточний клас, але і його батьківські класи з домішками.

my_number = 5 my_number. class. ancestors. include? (Fixnum) # -> true my_number. class. ancestors. include? (Integer) # -> true my_number. class. ancestors. include? (Enumerable) # -> false my_number. class. ancestors. include? (Comparable) # -> true

Подібний код чудово вирішує поставлене нами завдання, але виглядає громіздким. Не дивно, що для такого завдання застосовується спеціальний метод .is_a? (І його менш популярний псевдонім .kind_of?).

my_number = 5 my_number. is_a? (Fixnum) # -> true my_number. is_a? (Integer) # -> true my_number. is_a? (Enumerable) # -> false my_number. is_a? (Comparable) # -> true

Результати прикладу слід інтерпретувати так: число п'ять є цілим (клас Integer), але не надто великим (клас Fixnum); при цьому, елементи цього типу можна порівнювати між собою (домішка Comparable), але перелічуваних безліччю вони не є (домішка Enumerable).

А як порівнювати класи між собою? [ правити ]

Порівнянням класів ми займалися і раніше, але використовували тільки методи! = І ==. Крім них, можна використовувати і всі інші:>, <,> =, <= і навіть <=>.

Крім них, можна використовувати і всі інші:>, <,> =, <= і навіть <=>

Подібне різноманітність методів порівняння пов'язано з тим, що в клас Class включили домішка Comparable, тобто зробили об'єкти класу Class порівнянними між собою

Для того, щоб розібратися в роботі методів порівняння, розглянемо кілька прикладів, а потім детально розберемо їх результати.

Fixnum <Numeric # -> true Object> Integer # -> true Float <Integer # -> nil IO <= File # -> false

Метод "менше" сприймається Ruby, як питання "чи є нащадком?", Тобто перший приклад можна розцінити як питання виду: "клас Fixnum є нащадком класу Numeric?" Якщо ми поглянемо на ієрархію спадкування чисел, то побачимо, що ствердну відповідь (true) на це питання цілком виправданий.

Слідуючи тій же логіці, метод "більше" сприймається як питання "чи є батьком?", Тобто другий приклад можна розцінити як питання виду: "клас Object є батьком класу Integer?" Так як всі класи успадковані від класу Object (крім самого Object), то ствердну відповідь (true) не повинен нас сильно здивувати.

Третій приклад нам демонструє одну цікаву особливість методів порівняння: якщо класи не перебувають у відносинах "батько-нащадок", то вони є високими порівняно і тому метод порівняння відреагував на цю ситуацію поверненням nil.

Нагадаємо, що в логічному контексті об'єкт nil рівносильний об'єкту false (тобто вони є взаємозамінними)

Останній приклад демонструє роботу методу "менше або дорівнює". Він поєднує в собі методи "менше" і "дорівнює", тобто сприймається як питання виду: "чи є клас IO класом File або його нащадком?" Виходячи з того, що клас File є нащадком класу IO, а не навпаки, відповідь на це питання негативна (false).

Які константи доступні? [ правити ]

Щоб дізнатися які константи оголошені в тому чи іншому класі / модулі необхідно викликати метод .constants (ще одна "несподіванка") від цього класу / модуля.

class MyClass MY_CONST = "все одно яке значення" end MyClass. constants # -> [ "MY_CONST"] Math. constants # -> [ "E", "PI"] Math :: E # -> 2.71828182845905 Math :: PI # -> 3.14159265358979 MyClass :: MY_CONST # -> "все одно яке значення"

Ця константа оголошена? [ правити ]

З висоти отриманих раніше знань, ми можемо вирішити цю задачу в такий спосіб:

Math. constants. include? ( "Pi") # -> false Math. constants. include? ( "PI") # -> true

Для вирішення завдання використовувалася комбінація методів .constants і .include ?, що не зовсім раціонально, так як метод .constants повертає масив, що містить список всіх констант модуля або класу. У нашому випадку це не зовсім критично, але існують класи (на кшталт Object), де кількість констант може становити десятки, а то і сотні. Тому, правильніше буде використовувати спеціальний метод .const_defined ?, який зробить те ж саме, але без проміжного масиву (чим заощадить нам масу найцінніших мікросекунд і байт пам'яті).

Math. const_defined? ( "Pi") # -> false Math. const_defined? ( "PI") # -> true

Цей же метод добре використовувати для перевірки доступності того чи іншого класу, так як практично всі класи являють собою константи класу Object.

Цей же метод добре використовувати для перевірки доступності того чи іншого класу, так як практично всі класи являють собою константи класу Object

Існує спосіб створити клас, але не привласнювати йому ім'я. Тільки цей спосіб ми поки розглядати не будемо

Object. const_defined? ( "Math") # -> true Object. const_defined? ( "Complex") # -> false

З прикладу випливає, що модуль Math з математичними методами доступний, а ось класу комплексних чисел пощастило менше.

Як на ім'я константи отримати її значення? [ правити ]

Давайте ще раз подивимося на приклад отримання доступних констант:

Math. constants # -> [ "E", "PI"]

Ми лише дізналися імена констант, але їх значення нам поки не доступні. Для того, щоб отримати значення константи існує метод .const_get (який також слід викликати від конкретного класу або модуля). Для прикладу, давайте замінимо імена констант з попереднього прикладу на їх значення:

Math. constants. map {| const_name | Math. const_get (const_name)} # -> [2.71828182845905, 3.14159265358979] Math. const_get ( "PI") # -> 3.14159265358979 Math :: PI # -> 3.14159265358979 Math

Зверніть увагу, що всередині ітератора .map нам доводиться вказувати конкретний модуль (Math), щоб метод .const_get нормально працював. Інакше виникне помилка виду NoMethodError

Які класи доступні для використання? [ правити ]

Так як імена всіх класів є константами, то зведемо задачу до попередньої - знайдемо всі константи класу Object (він є базовим для всіх інших класів), які є об'єктами класу Class:

classes = Object. constants. select {| const_name | Object. const_get (const_name). is_a? Class}. sort # -> [ "ArgumentError", "Array", ..., "ZeroDivisionError"] classes. size # -> 79

Остання сортування (метод .sort) потрібна для краси, так як в вихідному масиві (який повернув итератор .select) імена констант не впорядковані.

select) імена констант не впорядковані

Всі помилки мають свій власний клас. Зроблено це для того, щоб можна було обробку помилок налаштовувати на конкретний клас помилок. Імена таких класів завжди закінчуються на слово Error

Все б добре, але майже вісімдесят класів - це перебір. Треба б видалити класи, які є класами помилок, так як вони не дуже нам цікаві. Для цього треба позбутися класів, імена яких закінчуються на слово Error. Щоб це здійснити, необхідно додати до попереднього прикладу наступний код:

without_error = classes. select {| class_name | ! class_name [/ Error $ /]} # -> [ "Array", "BasicSocket", ..., "UnboundMethod"] without_error. size # -> 54

Ті читачі, яким цікаві тільки класи помилок, можуть використовувати наступний код:

classes - without_error # -> [ "ArgumentError", ..., "ZeroDivisionError"]

Впорядкованість результату в останньому прикладі успадкована від впорядкованості масиву classes.

Як змінити значення константи? [ правити ]

Ви самі хоч зрозуміли, що запитали? Константа тому і константа, що її значення незмінно. Ситуацій, коли необхідно змінити значення константи просто не повинно виникати!

Ситуацій, коли необхідно змінити значення константи просто не повинно виникати

Будь-які спроби змінити значення константи будуть викликати бурхливу реакцію з боку інтерпретатора. Він буде видавати попередження виду: "значення цієї константи вже присвоєно"

Проте, існує спосіб створити нову константу. Зробити це можна за допомогою методу присвоєння.

Pi = 3. 14 Pi # -> 3.14 Math :: Pi = 3. +1415 Math :: Pi # -> 3.1415 Pi = 3

Створювати нову константу можна не тільки для кореневого класу (Object), але і для будь-якого іншого модуля або класу (ім'я якого необхідно вказати перед викликом методу)

Все це чудово, але що робити якщо задано тільки ім'я константи у вигляді рядка? Для цих цілей використовується метод .const_set, який потрібно викликати від класу, в який слід додати нову константу. Давайте перепишемо попередній приклад з тим припущенням, що ім'я константи нам задано у вигляді рядка.

Object. const_set ( "Pi", 3. 14) Pi # -> 3.14 Object. const_get ( "Pi") # -> 3.14 Math. const_set ( "Pi", 3. 1415) Math :: Pi # -> 3.1415 Math. const_get ( "Pi") # -> 3.1415 Object

Нагадуємо, що для отримання значення константи, заданої тільки своїм ім'ям, здійснюється методом .const_get

Ще трошки ускладнити завдання. Нехай тепер у вигляді рядка задано не тільки ім'я константи, а й ім'я класу. Тоді рішення може виглядати наступним чином:

Object. const_get ( "Math"). const_set ( "Pi", 3. 1415) Object. const_get ( "Math"). const_get ( "Pi") # -> 3.1415 Object. const_get ( "Math"). const_get ( "PI") # -> 3.14159265358979 Object

Весь цей час ми створювали константу Pi в модулі Math. Майте на увазі, що в реальності це не потрібно, так як в цьому самому модулі вже задана константа PI, яка має досить точне значення числа Пі

Виходить досить довге вираження, але іноді у програміста просто немає можливості його скоротити.

Які змінні доступні? [ правити ]

Змінні бувають наступних видів: примірника, класу, локальні і глобальні. Перші два види змінних ще називають атрибутами і вони мають дуже важливе значення для самопізнання. Проте, ми спочатку розглянемо методи самопізнання для останніх двох видів змінних, так як робота з ними найбільш проста і нехитра.

Які глобальні змінні доступні? [ правити ]

Для того, щоб отримати список глобальних змінних треба викликати метод global_variables (який слід викликати без вказівки класу, так як він є закритим ).

global_variables # -> [ "$ -v", "$ FILENAME", ..., "$ KCODE"] global_variables. include? ( "$ A") # -> false $ a = 1 global_variables. include? ( "$ A") # -> true

Метод .include? застосований для того, щоб читачеві не довелося переглядати весь список глобальних змінних в пошуках $ a.

застосований для того, щоб читачеві не довелося переглядати весь список глобальних змінних в пошуках $ a

Імена глобальних змінних завжди мають префікс $. Змінні називаються глобальними тому, що їх область видимості поширюється на всю програму, а не тільки на якийсь конкретний клас, об'єкт або метод

Які локальні змінні доступні? [ правити ]

Список локальних змінних доступний за допомогою виклику методу local_variables (який також слід викликати без вказівки класу, так як він теж є закритим ).

local_variables # -> [] a = 1 local_variables # -> [ "a"] local_variables # -> [] a = 1 local_variables # -> [ a]

Імена всіх локальних змінних починаються з малої latinskoi 'букви або знака _. Локальними вони називаються тому, що їх область видимості поширюється тільки на конкретний блок або метод

Чому глобальні та Локальні змінні вважаються цікавімі з точки зору самопізнання? Справа в тому, что значення ціх змінніх лишь непрямим чином вплівають на поточний стан класів або об'єктів. Саме тому, серед методів самопізнання відсутні ті, які дозволили б отримати або змінити поточний стан глобальної або локальної змінної.

Яку інформацію можна отримати про змінних екземпляра? [ правити ]

Тепер перейдемо до більш корисним і затребуваних видів змінних: примірника (об'єкта) і класу. Почнемо по-порядку, з змінних екземпляра.

Метод отримання масиву імен змінних екземпляра називається .instance_variables (префікс instance_ практично завжди вказує на приналежність до примірника).

class Sample def initialize @ variable_1, @ variable_2 = 1, "а можна не тільки число" end end my_object = Sample. new my_object. instance_variables # -> [ "@ variable_1", "@ variable_2"]

В даному прикладі ми придумали клас Sample і створили конструктор цього класу .initialize, який викликали за допомогою звернення Sample.new. Конструктор повернув нам екземпляр класу Sample, від якого ми і викликали метод .instance_variables.

Тепер ми можемо отримати значення будь-який з цих змінних за допомогою виклику методу .instance_variable_get:

my_object. instance_variable_get ( "@ variable_1") # -> 1 my_object. instance_variable_get ( "@ variable_2") # -> "а можна не тільки число"

У змінних екземпляра можна не тільки дізнатися значення, але і поміняти його. Здійснити це можна за допомогою методу .instance_variable_set

my_object. instance_variable_set ( "@ variable_1", 2) my_object. instance_variable_get ( "@ variable_1") # -> 2

Крім розглянутих методів отримання / зміни, є ще і метод видалення змінної примірника .remove_instance_variable, тобто можна в будь-який момент часу видалити змінну примірника. Давайте розглянемо, що з цього вийде:

class Sample def initialize @ variable_1, @ variable_2 = 1, "а можна і число" end def remove (name) remove_instance_variable (name) end end my_object = Sample. new my_object. instance_variables # -> [ "@ variable_1", "@ variable_2"] my_object. remove ( "@ variable_1") my_object. instance_variables # -> [ "@ variable_2"]

Створювати додатковий метод .remove в класі Sample довелося тому, що метод .remove_instance_variable є закритим , Тобто він може бути використаний тільки всередині методу примірника. Якщо створення додаткового методу не потрібно, то можна використовувати метод .instance_eval, який виконує будь-який програмний код в контексті примірника. Перепишемо наш приклад з використанням цього методу.

Перепишемо наш приклад з використанням цього методу

Блок методу .class_eval може мати параметр - поточний екземпляр (він же self), в контексті якого виконується блок

class Sample def initialize @ variable_1, @ variable_2 = 1, "а можна і число" end end my_object = Sample. new my_object. instance_variables # -> [ "@ variable_1", "@ variable_2"] my_object. instance_eval {remove_instance_variable ( "@ variable_1")} my_object. instance_variables # -> [ "@ variable_2"] my_object. instance_eval {remove_instance_variable ( "@ variable_2")} my_object. instance_variables # -> []

До речі, метод .instance_eval можна використовувати для отримання значення змінної примірника. Наприклад ось так:

Sample. new. instance_eval {@ variable_1} # -> 1

Яку інформацію можна отримати про змінних класу? [ правити ]

Робота зі змінними класу здійснюється практично також, як і зі змінними примірника. З тією лише різницею, що в назві методів замість слова instance_ треба писати class_. На цьому можна було б і закінчити, але давайте все таки розглянемо приклади застосування цих методів.

Відповідно до вищевикладеного правилом, замінюємо в назві методу .instance_variable слово instance_ на class_ і отримуємо назву методу, який отримує масив імен змінних класу.

class Sample @@ variable_1, @@ variable_2 = 1, "а можна і число" end Sample. class_variables # -> [ "@@ variable_2", "@@ variable_1"]

Як і раніше, ми створили клас Sample, але на цей раз не стали реалізовувати конструктор .initialize, так як для роботи з класом зовсім не обов'язково створювати його примірник (методом .new).

Настав час розглянути методи отримання і зміни значення змінної класу. У прикладі ми змінимо значення змінної класу (методом class_variable_set) і відразу ж отримаємо її нове значення (методом class_variable_get). Основна проблема полягає в тому, що обидва методи є закритими . Тому їх виклик можливий тільки в контексті методу класу. Для вирішення цієї проблеми ми створимо метод Sample.change, який буде змінювати змінну і повертати її нове значення в якості свого результату.

class Sample def Sample. change (name, value) class_variable_set (name, value) class_variable_get (name) end end Sample. change ( "@@ variable_1", 2) # -> 2

Чесно кажучи, ідея створювати метод класу для того, щоб змінити змінну класу - не найкраща ідея. Проблема полягає в тому, що ми породжуємо нову сутність, яка може нам і не знадобитися. Якраз для того, щоб виконати потрібні нам закриті методи без створення ще одного і існує метод .class_eval. Він дозволяє виконувати довільний програмний код в контексті класу, а в якості параметра приймає блок коду, який необхідно виконати в потрібному контексті. Перепишемо наш приклад із застосуванням методу .class_eval:

Sample. class_eval {class_variable_set ( "@@ variable_1", 2) class_variable_get ( "@@ variable_1")} # -> 2 Sample

Блок методу .class_eval може мати параметр - клас (об'єкт класу Class), в контексті якого виконується блок. У нашому випадку він абсолютно даремний, але можливо, що комусь і стане в нагоді (наприклад, якщо клас, від якого викликається метод .class_eval - невідомий)

Ну і наостанок розглянемо захоплюючий процес видалення змінних класу. Робиться це за допомогою методу remove_class_variable і за допомогою вже відомого нам методу .class_eval (так як метод remove_class_variable є закритим ).

class Sample @@ variable_1, @@ variable_2 = 1, "а можна і число" end Sample. class_variables # -> [ "@@ variable_1", "@@ variable_2"] Sample. class_eval {remove_class_variable ( "@@ variable_1")} Sample. class_variables # -> [ "@@ variable_2"] Sample. class_eval {remove_class_variable ( "@@ variable_2")} Sample. class_variables # -> [] class Sample @@ variable_1, @@ variable_2 = 1, а можна і число end Sample

Отримати значення змінної класу без допомоги методу class_variable_get (тільки за допомогою .class_eval) у мене не вийшло. Можливо, що це вийде у вас

Які методи доступні? [ правити ]

Подивитися список доступних методів викликавши .methods При цьому необхідно враховувати, що коли ми виробляємо виклик методу для класу, там не будуть міститися методи, визначені в ньому (і доступні для реалізації відповідного класу). Так наприклад

class Sample def method1 puts '1st method' end def method2 '2nd method' end end a = Sample. new puts Sample. methods. include? (: Method1) puts a. methods. include? (: Method1)

для першого випадку поверне false, в той час, як при перевірці наявності методу method1 в екземплярі (a) класу (Simple) поверне true

Чи можна викликати цей метод? [ правити ]

Для перевірки цього використовується метод .respond_to? . Цей метод повертає, чи відповідає клас на виклик переданого в .respond_to? параметри (імені методу) За аналогією з попереднім прикладом

class Sample def method1 puts '1st method' end def method2 '2nd method' end end a = Sample. new puts Sample. respond_to? (: Method1) puts a. respond_to? (: Method1)

поверне

так само ви можете телефонувати, коли методом передаються не символи, а стоку - ім'я перевіряється методу:

puts Sample. respond_to? ( 'Method1') puts a. respond_to? ( 'Method1')

Якого класу належить об'єкт?
Що таке самопізнання?
Якого класу належить об'єкт?
Несподівано", правда?
А чому ж не рядок?
Які класи / модулі використовувалися цим класом?
Як отримати список домішок класу?
Ancestors може виникнути резонне питання, а що якщо потрібно отримати тільки список домішок без батьківських класів?
Як отримати список всіх батьківських класів?
Чому безглуздий?
Провайдеры:
  • 08.09.2015

    Batyevka.NET предоставляет услуги доступа к сети Интернет на территории Соломенского района г. Киева.Наша миссия —... 
    Читать полностью

  • 08.09.2015
    IPNET

    Компания IPNET — это крупнейший оператор и технологический лидер на рынке телекоммуникаций Киева. Мы предоставляем... 
    Читать полностью

  • 08.09.2015
    Boryspil.Net

    Интернет-провайдер «Boryspil.net» начал свою работу в 2008 году и на данный момент является одним из крупнейших поставщиков... 
    Читать полностью

  • 08.09.2015
    4OKNET

    Наша компания работает в сфере телекоммуникационных услуг, а именно — предоставлении доступа в сеть интернет.Уже... 
    Читать полностью

  • 08.09.2015
    Телегруп

    ДП «Телегруп-Украина» – IT-компания с 15-летним опытом работы на рынке телекоммуникационных услуг, а также официальный... 
    Читать полностью

  • 08.09.2015
    Софтлинк

    Высокая скоростьМы являемся участником Украинского центра обмена трафиком (UA — IX) с включением 10 Гбит / сек... 
    Читать полностью