Slide 1

Slide 1 text

А вашият език може ли това?

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Защо точно ?

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

user.save if email.valid?

Slide 7

Slide 7 text

allow_any_instance_of(Validator).to receive(:validate) .and_return(true)

Slide 8

Slide 8 text

Often people, especially computer engineers, focus on the machines. They think, "By doing this, the machine will run faster. By doing this, the machine will run more effectively. By doing this, the machine will something something something." They are focusing on machines. But in fact we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves. -- Matz

Slide 9

Slide 9 text

Добър код

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

The Rails Doctrine By David Heinemeier Hansson (DHH) in January, 2016

Slide 12

Slide 12 text

1. Optimize for programmer happiness

Slide 13

Slide 13 text

2. Convention over Configuration

Slide 14

Slide 14 text

3. The menu is omakase

Slide 15

Slide 15 text

4. No one paradigm

Slide 16

Slide 16 text

5. Exalt beautiful code

Slide 17

Slide 17 text

6. Value integrated systems

Slide 18

Slide 18 text

7. Push up a big tent

Slide 19

Slide 19 text

The community

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Конференции (2015) Garden City RubyConf Ruby devroom at FOSDEM Ruby ConfAustralia Rubyfuza Ruby on Ales Tropical Ruby MountainWest RubyConf Bath Ruby Conference wroc_love.rb RubyConfLT Ancient City Ruby RubyConfPhilippines Ruby ConfIndia RailsConf ROSSConf Vienna RubyConfKenya Ruby Conference Kiev RedDotRubyConf RubyNation Gotham Ruby Conference Brighton Ruby JRubyConfEU Burlington Ruby Conference eurucamp DeccanRubyConf Madison+ Ruby Ruby Midwest Barcelona Ruby Conf RubyConfTaiwan RubyConfPortugal WindyCityRails RubyConfBrazil Rocky Mountain Ruby Conference ROSSConf Berlin ArrrrCamp Los Angeles Ruby Conference RubyConfColombia EuRuKo Keep Ruby Weird RubyWorld Conference RubyDay RubyConf RailsIsrael RubyKaigi

Slide 22

Slide 22 text

require 'open-uri' require 'nokogiri' CONFERENCES_SITE = 'http://rubyconferences.org/past/' doc = Nokogiri::HTML(open(CONFERENCES_SITE)) headings = doc.css('article#past dt').map { |heading| heading.content.strip } dates = doc.css('article#past dd').map { |desc| desc.css('li').first.content } conferences = headings.zip(dates) .select { |_, description| description.include? '2015' } .map(&:first) puts conferences

Slide 23

Slide 23 text

EuRuKo Sofia 23-24 септември 2016

Slide 24

Slide 24 text

Rails Girls Шесто поредно издание (в България) 25-26 март 2016

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

fmi. .bg

Slide 28

Slide 28 text

if talk.is? :cheap show me, the_code end

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

В всичко е израз

Slide 31

Slide 31 text

classification = if age < 13 'младок' elsif age < 20 'тийн' else 'старец' end puts classification

Slide 32

Slide 32 text

def foo(a, b = a, c = b) c end puts foo('bar') # => 'bar'

Slide 33

Slide 33 text

def doge(a, b = def doge(a); 'W'; end) a end puts doge('W', 1) + doge('O') + doge('whatever') # => WOW

Slide 34

Slide 34 text

В има числа

Slide 35

Slide 35 text

a = 5 * 2 #=> 10 b = 10 ** 2 #=> 100 a.class #=> Fixnum

Slide 36

Slide 36 text

c = 2 ** 1_024 #=> 17976931348623159077293051907890247… c.to_s.size #=> 309 c.class #=> Bignum

Slide 37

Slide 37 text

(2 ** 100_000).to_s.size #=> 30103

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

В всичко е обект

Slide 41

Slide 41 text

class A def foo 'bar' end end class_a = A class_a.new.foo #=> 'bar'

Slide 42

Slide 42 text

В може да се дефинират методи

Slide 43

Slide 43 text

class String def such; "such #{self}"; end def wow; "#{self}. wow!"; end end 'cool'.such.wow #=> 'such cool. wow!'

Slide 44

Slide 44 text

2.mm #=> 0.002 10.m #=> 10.0 10.5.km #=> 10500.0 10.5.km + 15.cm – 3.mm #=> 10500.147

Slide 45

Slide 45 text

class Numeric MM_SIZE = 0.001 UNITS = [:mm, :cm, :dm, :m, :dam, :hm, :km] UNITS.reduce(MM_SIZE) do |size, unit| define_method(unit) { self * size } size * 10 end end

Slide 46

Slide 46 text

liar = [1, 2, 3] liar.size #=> 3 def liar.size 42 end liar.size #=> 42 [1, 2, 3].size #=> 3

Slide 47

Slide 47 text

В има дати

Slide 48

Slide 48 text

2.days.ago 1.hour.from_now (1.hour + 3.minutes).ago

Slide 49

Slide 49 text

class Numeric def day self * 24.hours end def hour self * 60.minutes end def minute self * 60.seconds end def second self end end

Slide 50

Slide 50 text

class Numeric alias_method :days, :day alias_method :hours, :hour alias_method :minutes, :minute alias_method :seconds, :second end

Slide 51

Slide 51 text

class Numeric def ago Time.now - self end def from_now Time.now + self end end

Slide 52

Slide 52 text

В се пише на английски

Slide 53

Slide 53 text

5.пъти { покажи 'въй' } #=> въй въй въй въй въй

Slide 54

Slide 54 text

module Kernel alias_method :покажи, :puts end module Enumerable alias_method :пъти, :times end

Slide 55

Slide 55 text

В false е обратното на true

Slide 56

Slide 56 text

true #=> true !true #=> false

Slide 57

Slide 57 text

def true.@! true end !true #=> true !!false #=> true

Slide 58

Slide 58 text

В има if-ове...

Slide 59

Slide 59 text

true .if_true { 'yes' }.if_false { 'no' } #=> 'yes' false.if_true { 'yes' }.if_false { 'no' } #=> 'no' 'wtf'.if_true { 42 }.if_false { 666 } #=> 42

Slide 60

Slide 60 text

class BasicObject def if_true; yield; end def if_false; self; end end def false.if_true; self; end def nil.if_true; self; end def false.if_false; yield; end def nil.if_false; yield; end

Slide 61

Slide 61 text

В клас се инстанцира с `.new`...

Slide 62

Slide 62 text

class Class alias_method :!@, :new end !Array #=> [] !String #=> '' !A #=> #

Slide 63

Slide 63 text

class Class alias_method :[], :new end Array[1, 2, 3] #=> [1, 2, 3] String[] #=> '' A[] #=> #

Slide 64

Slide 64 text

В няма абстрактни класове...

Slide 65

Slide 65 text

class A class << self private :new end end A.new #=> NoMethodError: private method `new' called

Slide 66

Slide 66 text

Singleton?

Slide 67

Slide 67 text

class A def self.new @instance ||= super end end A.new #=> # A.new #=> # A.new #=> #

Slide 68

Slide 68 text

В няма декоратори...

Slide 69

Slide 69 text

class Fibonacci memoized def calculate(n) return 1 if n <= 2 puts "Calculating fib(#{n})" calculate(n – 1) + calculate(n – 2) end end

Slide 70

Slide 70 text

f = Fibonacci.new f.calculate(8) # Calculating fib(8) # Calculating fib(6) # Calculating fib(4) # Calculating fib(3) # Calculating fib(5) # Calculating fib(7) #=> 21 f.calculate(8) #=> 21

Slide 71

Slide 71 text

class Class def memoized(method_name) original = "#{method_name}_original" alias_method original, method_name define_method method_name do |*args| cache_key = [method_name, args] @_method_cache ||= {} @_method_cache[cache_key] ||= send(original, *args) end end end

Slide 72

Slide 72 text

class Class def memoized(method_name) decorate method_name do |method, *args| cache_key = [method_name, args] @_method_cache ||= {} @_method_cache[cache_key] ||= method.call(*args) end end end

Slide 73

Slide 73 text

class Class def decorate(method_name) method = instance_method(method_name) define_method method_name do |*args| yield method.bind(self), *args end end end

Slide 74

Slide 74 text

не е Java...

Slide 75

Slide 75 text

module A public static void def lol() 'I am a Java! Love me!' end end A.lol #=> "I am a Java! Love me!"

Slide 76

Slide 76 text

class Module def static(name) module_function name end end

Slide 77

Slide 77 text

class Module def void(method) decorate method do |method, *args| method.call(*args) nil end end end

Slide 78

Slide 78 text

не е Haskell...

Slide 79

Slide 79 text

plus = proc { |a, b| a + b } plus_one = plus.curry[1] [1, 2, 3, 4].map &plus_one #=> [2, 3, 4, 5]

Slide 80

Slide 80 text

naturals = 1..Float::INFINITY naturals.lazy .map { |x| x ** 2 } .take_while { |x| x <= 100 } .reduce(:+) #=> 385

Slide 81

Slide 81 text

В може да си направим placeholder обект

Slide 82

Slide 82 text

naturals = 1..Float::INFINITY naturals.lazy .map { |x| x ** 2 } .take_while { |x| x <= 100 } .reduce(:+) #=> 385

Slide 83

Slide 83 text

naturals = 1..Float::INFINITY naturals.lazy .map(&P ** 2) .take_while(&P <= 100) .reduce(:+) #=> 385

Slide 84

Slide 84 text

[[1, 2, 3, 8], [4, 5], [6]].map(&P.select(&:even?)) #=> [[2, 8], [4], [6]]

Slide 85

Slide 85 text

class P < BasicObject class << self def method_missing(method, *args, &block) ::Proc.new { |object| object.send method, *args, &block } end def to_proc ::Proc.new { |object| object } end end end

Slide 86

Slide 86 text

В инстанционните променливи са private...

Slide 87

Slide 87 text

f = Fibonacci.new f.calculate(4) #=> 3 f.instance_variable_get('@_method_cache') #=> { # [:fib, [2]] => 1, # [:fib, [1]] => 1, # [:fib, [3]] => 2, # [:fib, [4]] => 3 # } f.instance_variable_set('@_method_cache', {[:fib, [4]] => 42}) f.calculate(4) #=> 42

Slide 88

Slide 88 text

В има private методи...

Slide 89

Slide 89 text

class A private def call_me_if_you_can; 'gj'; end end a = A.new a.call_me_if_you_can #=> NoMethodError: private method # `call_me_if_you_can' called

Slide 90

Slide 90 text

a.call :call_me_if_you_can #=> "gj" a.instance_eval { call_me_if_you_can } #=> "gj" A.class_eval { public :call_me_if_you_can } a.call_me_if_you_can #=> "gj"

Slide 91

Slide 91 text

В има константи...

Slide 92

Slide 92 text

A_CONSTANT = 1234 A_CONSTANT = 42 #=> warning: already initialized # constant A_CONSTANT A_CONSTANT #=> 42

Slide 93

Slide 93 text

A_CONSTANT = 1234 Object.send :remove_const, 'A_CONSTANT' A_CONSTANT = 42 A_CONSTANT #=> 42

Slide 94

Slide 94 text

В всеки обект може да се направи immutable...

Slide 95

Slide 95 text

array = [1] array << 2 array #=> [1, 2] array.freeze array << 3 #=> RuntimeError: can't modify frozen Array

Slide 96

Slide 96 text

В няма начин да се un-freeze-не обект

Slide 97

Slide 97 text

require 'fiddle' class Object def unfreeze Fiddle::Pointer.new(object_id * 2)[1] &= ~(1 << 3) end end

Slide 98

Slide 98 text

array << 3 #=> RuntimeError: can't modify frozen Array array.unfreeze array.frozen? #=> false array << 3 array #=> [1, 2, 3]

Slide 99

Slide 99 text

В дори методите са обекти

Slide 100

Slide 100 text

class Person def initialize(name) @name = name end def likes(*items) "I am #{@name}. I like #{items.join(', ')}." end end

Slide 101

Slide 101 text

ivan = Person.new('Ivan') ivan.likes('cake', 'cats') #=> 'I am Ivan. I like cake, cats.' m = ivan.method(:likes) #=> # m.call('pancakes') #=> 'I am Ivan. I like pancakes.'

Slide 102

Slide 102 text

patrick = Person.new('Patrick') def patrick.likes '[censored]' end patrick.likes('coffee') #=> '[censored]' m.unbind.bind(patrick).call('coffee') #=> 'I am Patrick. I like coffee.'

Slide 103

Slide 103 text

class Test def f(a, b=2, *args) end end m = Test.new.method(:f) m.source_location #=> ["/Users/gangelov/ruby-test.rb", 2] m.parameters #=> [[:req, :a], [:opt, :b], [:rest, :args]]

Slide 104

Slide 104 text

може да разопакова аргументи

Slide 105

Slide 105 text

[[1, [2, 3]], [4, [5, 6]]].each do |a, (b, c)| puts a, b, c end #=> 1 2 3 #=> 4 5 6

Slide 106

Slide 106 text

person = { first_name: "Иван", last_name: "Петров", age: 22, # ... } person.using do |first_name, last_name| puts "Здравей, #{first_name} #{last_name}!" end

Slide 107

Slide 107 text

person = { first_name: "Иван", last_name: "Петров", age: 22, # ... } person.using do |first_name, age| puts "#{first_name} е на #{age}!" end

Slide 108

Slide 108 text

class Hash def using(&block) values = block.parameters.map do |(type, name)| self[name] end yield *values end end

Slide 109

Slide 109 text

triangles = [ {a: 3, b: 4, c: 5 }, {a: 5, b: 12, c: 13}, ... ] triangles.select.using do |a, b, c| a**2 + b**2 == c**2 end

Slide 110

Slide 110 text

module Enumerable def using(&block) each do |hash| hash.using(&block) end end end

Slide 111

Slide 111 text

В всеки обект си има клас

Slide 112

Slide 112 text

'foo'.class #=> String 1234.class #=> Fixnum String.class #=> Class Class.class #=> Class Class.class.class.….class #=> Class

Slide 113

Slide 113 text

Кажете "Класът на класа Class е Class"

Slide 114

Slide 114 text

В всеки клас си има родител

Slide 115

Slide 115 text

String.superclass #=> Object Object.superclass #=> BasicObject BasicObject.superclass #=> nil

Slide 116

Slide 116 text

Class.superclass #=> Module Module.class #=> Class

Slide 117

Slide 117 text

Хм, класът е клас, значи има new…

Slide 118

Slide 118 text

Class.new #=> # doge_class = Class.new do def such 'much' end end doge_class.new.such #=> 'much'

Slide 119

Slide 119 text

В има пет типа променливи

Slide 120

Slide 120 text

$global = 'глобална променлива' local = 'локална променлива' Constant = 'константа' @instance = 'инстанционна променлива' @@class = 'класова променлива'

Slide 121

Slide 121 text

В неанонимните класове са анонимни класове с имена

Slide 122

Slide 122 text

doge_class = Class.new do def such 'much' end end doge_class.name #=> nil Doge = doge_class doge_class.name #=> 'Doge'

Slide 123

Slide 123 text

В използването на недефинирана променлива предизвиква грешка

Slide 124

Slide 124 text

bla #=> NameError: undefined local variable or method

Slide 125

Slide 125 text

def method_missing(*) end bla #=> nil hello_undefined_var #=> nil

Slide 126

Slide 126 text

В низовете се ограждат с кавички

Slide 127

Slide 127 text

'hello world!' #=> 'hello world!' str { hello world! } #=> 'hello world!'

Slide 128

Slide 128 text

class Str def method_missing(*args) args.join(' ') end end def str(&block) Str.new.instance_eval(&block) end

Slide 129

Slide 129 text

В може да дефинираме безкраен хеш

Slide 130

Slide 130 text

h = {} h['a'] #=> nil h['a']['b'] #=> undefined method `[]` for nil:NilClass

Slide 131

Slide 131 text

h = Hash.new do |hash, key| hash[key] = Hash.new(&hash.default_proc) end h['a'] #=> {} h['a']['b']['c']['d'] = 42 h #=> {"a" => {"b" => {"c" => {"d" => 42}}}}

Slide 132

Slide 132 text

ви има пълно доверие

Slide 133

Slide 133 text

ObjectSpace.each_object(String) do |object| p object end #=> всички низове, които са в паметта в момента

Slide 134

Slide 134 text

GC.disable loop { '1' } #=> NoMemoryError GC.enable GC.start

Slide 135

Slide 135 text

С може да възкресите мъртвите

Slide 136

Slide 136 text

john = Person.new('John') john_id = john.object_id john = nil ObjectSpace._id2ref(john_id) #=> #

Slide 137

Slide 137 text

В дори binding-ът е обект

Slide 138

Slide 138 text

puts answer #=> NameError: undefined local variable binding.local_variable_set('answer', 42) puts answer #=> 42

Slide 139

Slide 139 text

a_counter = 1 b_counter = 3 c_counter = 9 increment_counters a_counter #=> 2 b_counter #=> 4 c_counter #=> 10

Slide 140

Slide 140 text

require 'binding_of_caller' def increment_counters b = binding.of_caller(1) b.local_variables .select { |name| name =~ /_counter$/ }.each do |name| value = b.local_variable_get(name) b.local_variable_set(name, value + 1) end end

Slide 141

Slide 141 text

С може да бъдете ДАНС

Slide 142

Slide 142 text

set_trace_func proc do |event, file, line, id, binding, cn| printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, cn end t = Test.new t.test #=> line prog.rb:11 false #=> c-call prog.rb:11 new Class #=> c-call prog.rb:11 initialize Object #=> c-return prog.rb:11 initialize Object #=> c-return prog.rb:11 new Class #=> line prog.rb:12 false #=> call prog.rb:2 test Test #=> line prog.rb:3 test Test #=> line prog.rb:4 test Test #=> return prog.rb:4 test Test

Slide 143

Slide 143 text

С може да декомпилирате Ruby

Slide 144

Slide 144 text

i = RubyVM::InstructionSequence.compile("Test.new.method") puts i.disassemble #=> 0000 trace 1 ( 1) #=> 0002 getinlinecache 9, #=> 0005 getconstant :Test #=> 0007 setinlinecache #=> 0009 opt_send_without_block , #=> 0012 opt_send_without_block , #=> 0015 leave

Slide 145

Slide 145 text

С може да сте шпиони

Slide 146

Slide 146 text

class Person def say(message) "#{message}!" end end person = Spy.new(Person.new) person.class #=> Person person.say('hello') #=> They called say with hello #=> 'hello!'

Slide 147

Slide 147 text

class Spy < BasicObject def initialize(obj) @instance = obj end def method_missing(name, *args, &block) $stdout.puts "They called #{name} with (#{args.join(', ')})" @instance.send(name, *args) end end

Slide 148

Slide 148 text

С може да пътувате във времето

Slide 149

Slide 149 text

require 'timecop' new_time = Time.local(2008, 9, 1, 12, 0, 0) Timecop.freeze(new_time) sleep 10 new_time == Time.now #=> true

Slide 150

Slide 150 text

# Seconds will now seem like hours Timecop.scale(3600) Time.now # => 2016-02-28 21:23:25 +0200 # A few seconds later... Time.now # => 2016-02-29 06:22:59 +0200

Slide 151

Slide 151 text

ви дава достатъчно дълго въже, че да се застреляте в крака

Slide 152

Slide 152 text

Бонус: Знаете ли какво е Quine?

Slide 153

Slide 153 text

No content