07. Класовете и константи, case, require, Enumerator

07. Класовете и константи, case, require, Enumerator

07. Класовете и константи, case, require, Enumerator

29 октомври 2014

Днес

Трета задача

OpenFest

Напомняме отново

Въпрос 1

Какво прави alias?

class Something
  def name() 'baba' end
  alias relative name
  def name() 'dyado' end
end

p Something.new.relative

Прави копие на метода

Въпрос 2

Каква е разликата между alias и alias_method?

alias_method е метод, докато alias е синтаксис

class Something
  1.upto(5).each do |index|
    alias_method "to_s_#{index}", :to_s
  end
end

Въпрос 3

Какво ще се случи след изпълнение на примерния код по-долу – грешка, или конкретна оценка? Каква?

module Outer
  class String
    def the_answer() '42' end
  end

  module Inner
    String.new.the_answer
  end
end

Кодът по-горе се оценява на низа '42'. Причината е, че "вътрешната" константа String "засенчва" глобалната такава. Допълнително, оценката на кода е последно изпълненият ред, който е String.new.the_answer.

Въпрос 4

В следния примерен код, по какви начини бихме могли да достъпим константата TREASURE от мястото, отбелязано с коментар?

module Deep
  module Down
    module Below
      TREASURE = 'Ya fools.'
    end
  end

  # =>
end

Поне по следните начини:

Down::Below::TREASURE
Deep::Down::Below::TREASURE
Object::Deep::Down::Below::TREASURE
::Deep::Down::Below::TREASURE
::Object::Deep::Down::Below::TREASURE

Call for speakers

Подиумът на този курс е и ваш

Класовете като обекти

Класовете като обекти (2)

Долното работи:

a_hash_class = Hash
a_hash_class.new # {}

Класовете като обекти (3)

anonymous_class = Class.new
anonymous_class.new # #<#<Class:0x424a7684>:0x424a7648>
Class.new.new       # #<#<Class:0x424a73f0>:0x424a73c8>
Module.new          # #<Module:0x424a7224>

Класовете като обекти (4)

Можем да подадем блок на Class.new:

duck = Class.new do
  def quack_to(creature_name)
    "Quack, #{creature_name}, quack!"
  end
end

duck.new.quack_to("swan") # "Quack, swan, quack!"

Обектите тип "клас" и константи

class Person
end

Класове и константи

Когато присвоим анонимен клас на константа, попадаме в специален случай:

Person = Class.new
Class.new           # #<Class:0x42702a8c>
Person = Class.new  # Person

Module.new          # #<Module:0x42702690>
Larodi = Module.new # Larodi

Root scope на константи - Object

Влагане на константи

именовани пространства

Таблици с константи

Таблици с константи (2)

Можете да видите тази "таблица" през constants:

module MyLibrary
  class Object
  end
end

MyLibrary.constants         # [:Object]
MyLibrary::Object == Object # false

Quine

програма, принтираща кода си

->_{_%_}["->_{_%%_}[%p]"]

Quine

to the eleven

v=0000;eval$s=%q~d=%!^Lcf<LK8,                  _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC       "%.#%  :::##"       97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B     "##%      ::##########"     O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y?    "##:         ###############"    g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W    "#            #.   .####:#######"    lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<.   "              ##### # :############"   R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5   "              #######################"   00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ   "              ############:####  %#####"   EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q   "              .#############:##%   .##  ."   /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!;  " %%            .################.     #.   "  ;s="v=%04o;ev"%
(;v=(v-($*+[45,  ":####:          :##############%       :   "  ])[n=0].to_i;)%
360)+"al$s=%q#{  "%######.              #########            "  ;;"%c"%126+$s<<
126}";d.gsub!(/  "##########.           #######%             "  |\s|".*"/,"");;
require"zlib"||  "###########           :######.             "  ;d=d.unpack"C*"
d.map{|c|n=(n||  ":#########:           .######: .           "  )*90+(c-2)%91};
e=["%x"%n].pack   " :#######%           :###### #:          "   &&"H*";e=Zlib::
Inflate.inflate(   "  ######%           .####% ::          "   &&e).unpack("b*"
)[0];22.times{|y|   "  ####%             %###             "   ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(;   " .###:             .#%             "   ;2))*23).floor;(w*
2-1).times{|x|u=(e+    " %##                           "    )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[(    " #.                        "    ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count((     " .                   "     ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ (       "#  :#######"       ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe                  Copyright(C).Yusuke Endoh, 2010

Quine

Може да пуснете quine-а от предния слайд като го запазите във файл quine.rb и ползвате това скриптче:

#!/bin/sh

while true
do
  ruby quine.rb | tee quine_result
  mv quine_result quine.rb
  sleep 0.2
done

Hash#to_proc

слайдове от бонус нивото

Да кажем, че имаме следния код:

CURRENCY_NAMES = {
  BGN: 'Bulgarian lev',
  EUR: 'Euro',
  USD: 'United States dollar',
  CHF: 'Swiss frank',
}.freeze

[:BGN, :CHF, :EUR].map { |currency_code| CURRENCY_NAMES[currency_code] }
# => ["Bulgarian lev", "Swiss frank", "Euro"]

Hash#to_proc

алтернативна имплементация

Нека предположим, че имаме следната имплементация на Hash#to_proc:

class Hash
  def to_proc
    proc { |key| self[key] }
  end
end

Hash#to_proc

алтернативна имплементация

Тогава можем да направим следното:

CURRENCY_NAMES = {
  BGN: 'Bulgarian lev',
  EUR: 'Euro',
  USD: 'United States dollar',
  CHF: 'Swiss frank',
}.freeze

[:BGN, :CHF, :EUR].map &CURRENCY_NAMES
# => ["Bulgarian lev", "Swiss frank", "Euro"]

Hash#to_proc

още приложения на горното

Удобни изглеждат и следните хипотетични употреби:

VALID_CURRENCIES = {
  BGN: true,
  EUR: true,
  USD: true,
  CHF: true,
}.freeze

valid_currencies = [:BGN, :CHF, :EUR].select(&VALID_CURRENCIES)

# Or:
if currencies.any? &VALID_CURRENCIES
end

# Or:
words.reject(&FORBIDDEN_WORDS)

Текущ scope при търсене на константи

class Foo::Bar
  # In the Bar scope, but not in the Foo scope
end

Текущ scope при търсене на константи (2)

В този пример:

class Foo::Bar
  Larodi
end

Търсене на константи

module A::B
  module C::D
    Foo # Where does Ruby look for Foo?
  end
end
  1. В таблицата на D
  2. В таблицата на B
  3. В root scope-а (т.е. в таблицата на Object)

Constant Autoloading in Rails

Въпроси по константи и scope-ове

Имате ли въпроси?

case

В Ruby има "switch". Казва се case.

def quote(name)
  case name
    when 'Yoda'
      puts 'Do or do not. There is no try.'
    when 'Darth Vader'
      puts 'The Force is strong with this one.'
    when 'R2-D2'
      puts 'Beep. Beep. Beep.'
    else
      puts 'Dunno what to say'
  end
end

case

особености

case

алтернативен синтаксис

case operation
  when :& then puts 'And?'
  when :| then puts 'Or...'
  when :! then puts 'Not!'
  else         puts 'WAT?'
end

case

връщана стойност

На какво ще се оцени следният код?

case 'Wat?'
  when 'watnot' then puts "I'm on a horse."
end

Ако няма else и никой when не match-не, се връща nil.

case

стойности

case не сравнява с ==. Може да напишете следното:

def qualify(age)
  case age
    when 0..12
      'still very young'
    when 13..19
      'a teenager! oh no!'
    when 33
      'the age of jesus'
    when 90..200
      'wow. that is old!'
    else
      'not very interesting'
    end
end

case

Object#===

case сравнява с ===. Няколко класа го имплементират:

case

Class#===

def qualify(thing)
  case thing
    when Integer then 'this is a number'
    when String  then 'it is a string'
    when Array   then thing.map { |item| qualify item }
    else 'huh?'
  end
end

case

Range#===

case hours_of_sleep
  when 8..10 then 'I feel fine.'
  when 6...8 then 'I am a little sleepy.'
  when 0..3  then 'OUT OF MY WAY! I HAVE PLACES TO BE AND PEOPLE TO SEE!'
end

case

Regexp#===

def parse_date(date_string)
  case date_string
    when /(\d{4})-(\d\d)-(\d\d)/
      Date.new $1.to_i, $2.to_i, $3.to_i
    when /(\d\d)\/(\d\d)\/(\d{4})/
      Date.new $3.to_i, $1.to_i, $2.to_i
  end
end

case

when с няколко стойности

Ruby позволява да обедините проверката за няколко възможни стойности в един when, дори да не са от един и същи тип.

case number
  when (42+0i)  then 'This is too complex for me!'
  when 42, 42.0 then 'This is more like it!'
end

case

с обикновени условия

thing = 42
case
  when thing == 1 then 1
  else 'no_idea'
end

Въпроси по case

Сега е моментът.

Импортиране на файлове

В Ruby, код от други файлове се импортира с require.

Например:

require 'bigdecimal'
require 'bigdecimal/util'

Какво търси require?

Зареждане на файлове от текущата директория

Зареждане на файлове от текущата директория

require_relative

Load path

където Ruby търси файлове за require

Как работи require?

Библиотеките в Ruby

Code Spelunking

из skeptic

Следващия път ще продължим с разглеждане структурата на един gem и ще пробваме да се спуснем в пещерата на skeptic. Ще демонстрираме основни пещернячески умения.

Въпроси