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

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

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

30 октомври 2013

Днес

Втора задача

OpenFest

Mislav @ OpenFest

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

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

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

a_hash_class = Hash
a_hash_class.new # {}

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

anonymous_class = Class.new
anonymous_class.new # #<#<Class:0x41089738>:0x41089710>
Class.new.new       # #<#<Class:0x410894f4>:0x410894cc>
Module.new          # #<Module:0x41089300>

Класовете като обекти (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:0x421bcb7c>
Person = Class.new  # Person

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

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

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

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

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

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

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

module MyLibrary
  class Object
  end
end

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

Текущ 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

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

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

Въпроси по case

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

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

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

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

Например:

require 'bigdecimal'
require 'bigdecimal/util'

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

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

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

require_relative

Load path

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

Как работи require?

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

Типичната структура на един gem

skeptic опростен

.
├── README.rdoc
├── Rakefile
├── bin
│   └── skeptic
├── features
├── lib
│   ├── skeptic
│   │   ├── rules.rb
│   │   └── scope.rb
│   └── skeptic.rb
├── skeptic.gemspec
└── spec 

Особеностите

Останалите неща

Kernel#load

Въпроси по require

Имате ли въпроси по require, load, gem-ове в Ruby?

Enumerator-и

Някои методи на Enumerable могат да не вземат блок.

numbers = []
1.upto(5) { |x| numbers << x }

numbers               # [1, 2, 3, 4, 5]

other = 1.upto(5)
other                 # #<Enumerator: 1:upto(5)>
other.to_a            # [1, 2, 3, 4, 5]

1.upto(5).map(&:succ) # [2, 3, 4, 5, 6]

Enumerator-и

нещо като итератори

Енумераторите могат да се държат като итератори.

numbers = 1.upto(3)

numbers.next   # 1
numbers.next   # 2
numbers.next   # 3
numbers.next   # error: StopIteration

Kernel#loop

loop прави безкраен цикъл. Спира на StopIteration.

numbers = 1.upto(3)

loop do
  puts numbers.next
end

#with_object и #with_index

Енумераторите имат някои интересни методи.

numbers = 1.upto(3)

numbers.with_index.to_a      # [[1, 0], [2, 1], [3, 2]]
numbers.with_object(:x).to_a # [[1, :x], [2, :x], [3, :x]]

Object#enum_for

Може да извадите енумератор от произволен метод с enum_for.

class Numbers
  def primes
    yield 2
    yield 3
    yield 5
    yield 7
  end
end

first_four_primes = Numbers.new.enum_for(:primes)
first_four_primes.to_a     # [2, 3, 5, 7]

map_with_index

навръзване на енумератори

Ако ви се е случвало да ви трябва индекс в map:

words = %w( foo bar baz ).map.with_index do |word, index|
  "#{index}: #{word.upcase}"
end

words # ["0: FOO", "1: BAR", "2: BAZ"]

Въпроси