Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby - Can your language do this?

Ruby - Can your language do this?

E1873b75f09c042ef07fe136ba2446f6?s=128

Georgy Angelov

June 24, 2016
Tweet

Transcript

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

  2. None
  3. None
  4. Защо точно ?

  5. None
  6. user.save if email.valid?

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

  8. 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
  9. Добър код

  10. None
  11. The Rails Doctrine By David Heinemeier Hansson (DHH) in January,

    2016
  12. 1. Optimize for programmer happiness

  13. 2. Convention over Configuration

  14. 3. The menu is omakase

  15. 4. No one paradigm

  16. 5. Exalt beautiful code

  17. 6. Value integrated systems

  18. 7. Push up a big tent

  19. The community

  20. None
  21. Конференции (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
  22. 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
  23. EuRuKo Sofia 23-24 септември 2016

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

  25. None
  26. None
  27. fmi. .bg

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

  29. None
  30. В всичко е израз

  31. classification = if age < 13 'младок' elsif age <

    20 'тийн' else 'старец' end puts classification
  32. def foo(a, b = a, c = b) c end

    puts foo('bar') # => 'bar'
  33. def doge(a, b = def doge(a); 'W'; end) a end

    puts doge('W', 1) + doge('O') + doge('whatever') # => WOW
  34. В има числа

  35. a = 5 * 2 #=> 10 b = 10

    ** 2 #=> 100 a.class #=> Fixnum
  36. c = 2 ** 1_024 #=> 17976931348623159077293051907890247… c.to_s.size #=> 309

    c.class #=> Bignum
  37. (2 ** 100_000).to_s.size #=> 30103

  38. None
  39. None
  40. В всичко е обект

  41. class A def foo 'bar' end end class_a = A

    class_a.new.foo #=> 'bar'
  42. В може да се дефинират методи

  43. class String def such; "such #{self}"; end def wow; "#{self}.

    wow!"; end end 'cool'.such.wow #=> 'such cool. wow!'
  44. 2.mm #=> 0.002 10.m #=> 10.0 10.5.km #=> 10500.0 10.5.km

    + 15.cm – 3.mm #=> 10500.147
  45. 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
  46. liar = [1, 2, 3] liar.size #=> 3 def liar.size

    42 end liar.size #=> 42 [1, 2, 3].size #=> 3
  47. В има дати

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

  49. 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
  50. class Numeric alias_method :days, :day alias_method :hours, :hour alias_method :minutes,

    :minute alias_method :seconds, :second end
  51. class Numeric def ago Time.now - self end def from_now

    Time.now + self end end
  52. В се пише на английски

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

    въй
  54. module Kernel alias_method :покажи, :puts end module Enumerable alias_method :пъти,

    :times end
  55. В false е обратното на true

  56. true #=> true !true #=> false

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

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

  59. true .if_true { 'yes' }.if_false { 'no' } #=> 'yes'

    false.if_true { 'yes' }.if_false { 'no' } #=> 'no' 'wtf'.if_true { 42 }.if_false { 666 } #=> 42
  60. 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
  61. В клас се инстанцира с `.new`...

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

    #=> '' !A #=> #<A:0x007fb953bcae58>
  63. class Class alias_method :[], :new end Array[1, 2, 3] #=>

    [1, 2, 3] String[] #=> '' A[] #=> #<A:0x007fb953bcae58>
  64. В няма абстрактни класове...

  65. class A class << self private :new end end A.new

    #=> NoMethodError: private method `new' called
  66. Singleton?

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

    #=> #<A:0x007fb953bcae58> A.new #=> #<A:0x007fb953bcae58> A.new #=> #<A:0x007fb953bcae58>
  68. В няма декоратори...

  69. class Fibonacci memoized def calculate(n) return 1 if n <=

    2 puts "Calculating fib(#{n})" calculate(n – 1) + calculate(n – 2) end end
  70. 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
  71. 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
  72. 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
  73. 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
  74. не е Java...

  75. module A public static void def lol() 'I am a

    Java! Love me!' end end A.lol #=> "I am a Java! Love me!"
  76. class Module def static(name) module_function name end end

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

    nil end end end
  78. не е Haskell...

  79. plus = proc { |a, b| a + b }

    plus_one = plus.curry[1] [1, 2, 3, 4].map &plus_one #=> [2, 3, 4, 5]
  80. naturals = 1..Float::INFINITY naturals.lazy .map { |x| x ** 2

    } .take_while { |x| x <= 100 } .reduce(:+) #=> 385
  81. В може да си направим placeholder обект

  82. naturals = 1..Float::INFINITY naturals.lazy .map { |x| x ** 2

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

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

    [4], [6]]
  85. 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
  86. В инстанционните променливи са private...

  87. 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
  88. В има private методи...

  89. 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
  90. 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"
  91. В има константи...

  92. A_CONSTANT = 1234 A_CONSTANT = 42 #=> warning: already initialized

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

    #=> 42
  94. В всеки обект може да се направи immutable...

  95. array = [1] array << 2 array #=> [1, 2]

    array.freeze array << 3 #=> RuntimeError: can't modify frozen Array
  96. В няма начин да се un-freeze-не обект

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

    ~(1 << 3) end end
  98. array << 3 #=> RuntimeError: can't modify frozen Array array.unfreeze

    array.frozen? #=> false array << 3 array #=> [1, 2, 3]
  99. В дори методите са обекти

  100. class Person def initialize(name) @name = name end def likes(*items)

    "I am #{@name}. I like #{items.join(', ')}." end end
  101. ivan = Person.new('Ivan') ivan.likes('cake', 'cats') #=> 'I am Ivan. I

    like cake, cats.' m = ivan.method(:likes) #=> #<Method: Person#likes> m.call('pancakes') #=> 'I am Ivan. I like pancakes.'
  102. 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.'
  103. 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]]
  104. може да разопакова аргументи

  105. [[1, [2, 3]], [4, [5, 6]]].each do |a, (b, c)|

    puts a, b, c end #=> 1 2 3 #=> 4 5 6
  106. person = { first_name: "Иван", last_name: "Петров", age: 22, #

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

    ... } person.using do |first_name, age| puts "#{first_name} е на #{age}!" end
  108. class Hash def using(&block) values = block.parameters.map do |(type, name)|

    self[name] end yield *values end end
  109. 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
  110. module Enumerable def using(&block) each do |hash| hash.using(&block) end end

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

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

    #=> Class Class.class.class.….class #=> Class
  113. Кажете "Класът на класа Class е Class"

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

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

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

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

  118. Class.new #=> #<Class:0x0077fd4e4984b90> doge_class = Class.new do def such 'much'

    end end doge_class.new.such #=> 'much'
  119. В има пет типа променливи

  120. $global = 'глобална променлива' local = 'локална променлива' Constant =

    'константа' @instance = 'инстанционна променлива' @@class = 'класова променлива'
  121. В неанонимните класове са анонимни класове с имена

  122. doge_class = Class.new do def such 'much' end end doge_class.name

    #=> nil Doge = doge_class doge_class.name #=> 'Doge'
  123. В използването на недефинирана променлива предизвиква грешка

  124. bla #=> NameError: undefined local variable or method

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

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

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

    #=> 'hello world!'
  128. class Str def method_missing(*args) args.join(' ') end end def str(&block)

    Str.new.instance_eval(&block) end
  129. В може да дефинираме безкраен хеш

  130. h = {} h['a'] #=> nil h['a']['b'] #=> undefined method

    `[]` for nil:NilClass
  131. 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}}}}
  132. ви има пълно доверие

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

    са в паметта в момента
  134. GC.disable loop { '1' } #=> NoMemoryError GC.enable GC.start

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

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

    #=> #<Person:0x...>
  137. В дори binding-ът е обект

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

    answer #=> 42
  139. a_counter = 1 b_counter = 3 c_counter = 9 increment_counters

    a_counter #=> 2 b_counter #=> 4 c_counter #=> 10
  140. 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
  141. С може да бъдете ДАНС

  142. 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
  143. С може да декомпилирате Ruby

  144. i = RubyVM::InstructionSequence.compile("Test.new.method") puts i.disassemble #=> 0000 trace 1 (

    1) #=> 0002 getinlinecache 9, <is:0> #=> 0005 getconstant :Test #=> 0007 setinlinecache <is:0> #=> 0009 opt_send_without_block <callinfo!mid:new, argc:0, ARGS_SIMPLE>, <callcache> #=> 0012 opt_send_without_block <callinfo!mid:method, argc:0, ARGS_SIMPLE>, <callcache> #=> 0015 leave
  145. С може да сте шпиони

  146. 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!'
  147. 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
  148. С може да пътувате във времето

  149. require 'timecop' new_time = Time.local(2008, 9, 1, 12, 0, 0)

    Timecop.freeze(new_time) sleep 10 new_time == Time.now #=> true
  150. # 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
  151. ви дава достатъчно дълго въже, че да се застреляте в

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

  153. None