Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Ruby Programming    Language
About Me> 8 years of developing experienceretail, e-commerce, logistics,fashion, multi-media, etc.lead developer, team lea...
Why RubyEverything is an ObjectDynamic typingOpenMix-insFunctional supportMethods vs Keywords(Meta)programming‘Scripting’ ...
Everything is  an object
Classical                            class MyClass                              def method                                ...
Everything is an Object                         superclass               Object                 Moduleinst   class       s...
ClassesCode:class Cls < Array  def sum    inject{ |sum, element| sum + element}  endend
ClassesCode:class Cls < Array                                 Cls = Class.new(Array) do  def sum                          ...
ClassesCode:class Cls < Array                                 Cls = Class.new(Array) do  def sum                          ...
ClassesCode:class Cls < Array                                      Cls = Class.new(Array) do  def sum                     ...
ClassesCode:class Cls < Array                                      Cls = Class.new(Array) do  def sum                     ...
Dynamic Typing
Dynamic TypingCode:        class CreditCard          def pay; #credit code; end        end        class Cod          def p...
Ruby is an openlanguage by design
Class OpeningCode:
Class OpeningCode:  3.times do    class Cls      puts “Hi”    end  end
Class OpeningCode:  3.times do    class Cls      puts “Hi”    end  end  => Hi     Hi     Hi
Class OpeningCode:  3.times do      def Cls.hi    class Cls       puts “Hi Class”      puts “Hi”   end    end  end  => Hi ...
Class OpeningCode:  3.times do      def Cls.hi    class Cls       puts “Hi Class”      puts “Hi”   end    end  end  => Hi ...
Class OpeningCode:                  def Cls.hi          obj1 = Cls.new  3.times do                    puts “Hi Class”   ob...
Class OpeningCode:                  def Cls.hi          obj1 = Cls.new  3.times do                    puts “Hi Class”   ob...
Class OpeningCode:                  def Cls.hi          obj1 = Cls.new  3.times do                    puts “Hi Class”   ob...
Mixins
Modules  Code:    module Mod      CONSTANT = Outer      class Cls        CONSTANT = Inner      end    end
Modules  Code:    module Mod      CONSTANT = Outer      class Cls        CONSTANT = Inner      end    end    Mod::CONSTANT...
ModulesCode:  module Mod    def my_method      M#my_method()    end  end  class Cls    include Mod  end  class Cls    exte...
ModulesCode:  module Mod    def my_method      M#my_method()    end  end  class Cls    include Mod   Cls.new.my_method # =...
ModulesCode:  module Mod    def my_method      M#my_method()    end  end  class Cls    include Mod   Cls.new.my_method # =...
ModulesCode:  module Mod    def my_method      M#my_method()                         private instance    end              ...
ModulesCode:  module Mod    def my_method      M#my_method()                            private instance    end           ...
Functional Support
BlocksCode:def three_times  yield  yield  yieldendthree_times { puts "Hello" }# => Hello Hello Hello
BlocksCode:    File.open("path/file", "r") do |file|      file.each_line do |line|        name, surname = line.split(,)   ...
BlocksCode:        def my_method          x = “Hello”          yield("cruel")        end        x = "Goodbye"        my_me...
Scope                                              Class                                              ModuleCode:         ...
VariablesCode:        $v1 = ‘global variable’        def Cls          v2 = ‘local variable’          @v3 = ‘class instance...
Blocks   Code:             def define_methods              Dynamic                                             Method  Sco...
Proc and Lambda                                       DeferredCode:                                  Evaluation    plus_on...
Proc and Lambda             (& and to_proc)Code:    [1, 2, 5].inject(0){|sum, e| sum + e} # => 8
Proc and Lambda             (& and to_proc)Code:    [1, 2, 5].inject(0){|sum, e| sum + e} # => 8    [1, 2, 5].inject(0, &:...
Proc and Lambda             (& and to_proc)Code:    [1, 2, 5].inject(0){|sum, e| sum + e} # => 8                          ...
Proc and Lambda             (& and to_proc)Code:    [1, 2, 5].inject(0){|sum, e| sum + e} # => 8                          ...
Methods vs Keywords
Method Visibilityclass Cls! def public_method! ! self.private_method  !end!! private!! def private_method; endend
Method Visibilityclass Cls! def public_method! ! self.private_method  !end!! private!! def private_method; endendC.new.pub...
Method Visibility                                 class Cls                                   (1..5).each do |i|          ...
Method Visibility          Code:                  Dynamic                                 Dispatch                  c = Cl...
ExceptionsCode: begin   raise “blew up” rescue => ex   puts “I #{ex}” end
ExceptionsCode:                       begin                              ... begin                        fail “error”   r...
ExceptionsCode:                                        begin                                               ... begin      ...
ExceptionsCode:                                        begin                                               ... begin      ...
Exceptions                       (raise)Code:   def raise(error_cls_or_obj, msg, backtrace)          error = error_cls_or_...
Exceptions                       (raise)Code:   def raise(error_cls_or_obj, msg, backtrace)          error = error_cls_or_...
Exceptions    (dynamic rescue clauses)Code:        ignore_exceptions(IOError, SystemCallError) do          open("NONEXISTE...
(Meta)Programming
(Meta)Programming                  Class Macros ExampleCode: Class Customer   def name     @name   end   def name=(n)     ...
(Meta)Programming                  Class Macros ExampleCode: Class Customer              class Customer   def name        ...
(Meta)Programming                      Class Macros ExampleCode: Class Customer                         class Customer   d...
Hook Methods                    (a.k.a. callbacks)Method related hooks                                 Class and module re...
Method Missing Code: config = {     :host => ws.contactlab.it,     :path => /RPC2,     :use_ssl => true } class ContactLab...
Scripting
ExpressionsCode:  song_type = if song.mp3Type == MP3::Jazz                if song.written < Date.new(1935, 1, 1)          ...
Infrastructure as codeCode: package "rabbimq-server" do   action :install end service "rabbitmq-server" do   supports :sta...
Testing
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new    @stack.push :item  end ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:describe Stack do                            RSpec  before(:each) do    @stack = Stack.new                expect {   ...
Code:                        Cucumber  Feature: Google Search    In order to learn something   As an internet user    I wa...
The Object Model Revisited
Splash                                               "motherboard" =~ /board/class String                                 ...
Why Ruby?
Why Ruby?Your own choice!!!
ns?    stio ueQ
References
Than    k you   :)    !
Upcoming SlideShare
Loading in …5
×

Why I choosed Ruby

1,199 views

Published on

Published in: Technology
  • Be the first to comment

Why I choosed Ruby

  1. 1. Ruby Programming Language
  2. 2. About Me> 8 years of developing experienceretail, e-commerce, logistics,fashion, multi-media, etc.lead developer, team leader,project manager, functionalanalysts, architect.a runner and a mountain lover elimi @I ndritS
  3. 3. Why RubyEverything is an ObjectDynamic typingOpenMix-insFunctional supportMethods vs Keywords(Meta)programming‘Scripting’ supportLBNL: Testing
  4. 4. Everything is an object
  5. 5. Classical class MyClass def method @v = 1 end end Object Class Instance class MyClass @v = 1 method()Code: obj = MyClass.new obj.methods == MyClass.instance_methods # => true obj.methods != MyClass.methods # => true
  6. 6. Everything is an Object superclass Object Moduleinst class superclass superclass class MyClass Class class
  7. 7. ClassesCode:class Cls < Array def sum inject{ |sum, element| sum + element} endend
  8. 8. ClassesCode:class Cls < Array Cls = Class.new(Array) do def sum def sum inject{ |sum, element| sum + element} inject{|sum, element| sum + element} end endend end
  9. 9. ClassesCode:class Cls < Array Cls = Class.new(Array) do def sum def sum inject{ |sum, element| sum + element} inject{|sum, element| sum + element} end endend end
  10. 10. ClassesCode:class Cls < Array Cls = Class.new(Array) do def sum def sum inject{ |sum, element| sum + element} inject{|sum, element| sum + element} end endend end Classes are nothing but objects, class names are nothing but constants.
  11. 11. ClassesCode:class Cls < Array Cls = Class.new(Array) do def sum def sum inject{ |sum, element| sum + element} inject{|sum, element| sum + element} end endend end ! Classes are nothing but objects, class names are nothing but constants.
  12. 12. Dynamic Typing
  13. 13. Dynamic TypingCode: class CreditCard def pay; #credit code; end end class Cod def pay; #cod code; end end class WireTransfer def pay; #wrt code; end end def process(payment) ... payment.pay ... end
  14. 14. Ruby is an openlanguage by design
  15. 15. Class OpeningCode:
  16. 16. Class OpeningCode: 3.times do class Cls puts “Hi” end end
  17. 17. Class OpeningCode: 3.times do class Cls puts “Hi” end end => Hi Hi Hi
  18. 18. Class OpeningCode: 3.times do def Cls.hi class Cls puts “Hi Class” puts “Hi” end end end => Hi Hi Hi
  19. 19. Class OpeningCode: 3.times do def Cls.hi class Cls puts “Hi Class” puts “Hi” end end end => Hi Cls.hi #=> Hi Hi Hi
  20. 20. Class OpeningCode: def Cls.hi obj1 = Cls.new 3.times do puts “Hi Class” obj2 = Cls.new class Cls puts “Hi” end def obj1.hi end puts “Hi” end end => Hi Cls.hi #=> Hi Hi Hi
  21. 21. Class OpeningCode: def Cls.hi obj1 = Cls.new 3.times do puts “Hi Class” obj2 = Cls.new class Cls puts “Hi” end def obj1.hi end puts “Hi” end end => Hi Cls.hi #=> Hi obj1.hi # => Hi Hi Hi
  22. 22. Class OpeningCode: def Cls.hi obj1 = Cls.new 3.times do puts “Hi Class” obj2 = Cls.new class Cls puts “Hi” end def obj1.hi end puts “Hi” end end => Hi Cls.hi #=> Hi obj1.hi # => Hi Hi obj2.hi # => Hi NoMethodError
  23. 23. Mixins
  24. 24. Modules Code: module Mod CONSTANT = Outer class Cls CONSTANT = Inner end end
  25. 25. Modules Code: module Mod CONSTANT = Outer class Cls CONSTANT = Inner end end Mod::CONSTANT => “Outer” Mod::Cls::CONSTANT => “Inner”
  26. 26. ModulesCode: module Mod def my_method M#my_method() end end class Cls include Mod end class Cls extend Mod end
  27. 27. ModulesCode: module Mod def my_method M#my_method() end end class Cls include Mod Cls.new.my_method # =>“M#my_method()” end class Cls extend Mod end
  28. 28. ModulesCode: module Mod def my_method M#my_method() end end class Cls include Mod Cls.new.my_method # =>“M#my_method()” end class Cls extend Mod Cls.my_method # =>“M#my_method()” end
  29. 29. ModulesCode: module Mod def my_method M#my_method() private instance end method end of Module class Cls include Mod Cls.new.my_method # =>“M#my_method()” end class Cls extend Mod Cls.my_method # =>“M#my_method()” end
  30. 30. ModulesCode: module Mod def my_method M#my_method() private instance end method end of Module class Cls include Mod Cls.new.my_method # =>“M#my_method()” end Object#extend class Cls extend Mod Cls.my_method # =>“M#my_method()” end
  31. 31. Functional Support
  32. 32. BlocksCode:def three_times yield yield yieldendthree_times { puts "Hello" }# => Hello Hello Hello
  33. 33. BlocksCode: File.open("path/file", "r") do |file| file.each_line do |line| name, surname = line.split(,) ... end end
  34. 34. BlocksCode: def my_method x = “Hello” yield("cruel") end x = "Goodbye" my_method {|y| "#{x}, #{y} world" } # => "Goodbye, cruel world"
  35. 35. Scope Class ModuleCode: Method v1 = 1 class Cls # SCOPE GATE: entering class v2 = 2 local_variables # => ["v2"] def my_method # SCOPE GATE: entering def v3 = 3 local_variables # => ["v3"] end # SCOPE GATE: leaving def local_variables # => ["v2"] end # SCOPE GATE: leaving class
  36. 36. VariablesCode: $v1 = ‘global variable’ def Cls v2 = ‘local variable’ @v3 = ‘class instance variable’ def my_method @v3 = ‘instance variable’ end @@v4 = ‘class hiearchy variable’ end
  37. 37. Blocks Code: def define_methods Dynamic Method Scope shared = 0Flattening Kernel.send :define_method, :counter do shared end Kernel.send :define_method, :inc do |x| shared += x end end counter # => 0 inc(4) counter # => 4
  38. 38. Proc and Lambda DeferredCode: Evaluation plus_one = Proc.new {|x| x + 1 } ... plus_one.call(2) # => 3 plus_one = lambda {|x| x + 1 } plus_one.call(2) # => 3
  39. 39. Proc and Lambda (& and to_proc)Code: [1, 2, 5].inject(0){|sum, e| sum + e} # => 8
  40. 40. Proc and Lambda (& and to_proc)Code: [1, 2, 5].inject(0){|sum, e| sum + e} # => 8 [1, 2, 5].inject(0, &:+) # => 8
  41. 41. Proc and Lambda (& and to_proc)Code: [1, 2, 5].inject(0){|sum, e| sum + e} # => 8 Symbol [1, 2, 5].inject(0, &:+) # => 8
  42. 42. Proc and Lambda (& and to_proc)Code: [1, 2, 5].inject(0){|sum, e| sum + e} # => 8 Symbol [1, 2, 5].inject(0, &:+) # => 8 Class Symbol def to_proc proc { |obj, *args| obj.send(self, *args) } end end
  43. 43. Methods vs Keywords
  44. 44. Method Visibilityclass Cls! def public_method! ! self.private_method !end!! private!! def private_method; endend
  45. 45. Method Visibilityclass Cls! def public_method! ! self.private_method !end!! private!! def private_method; endendC.new.public_method #=> NoMethodError: private method
  46. 46. Method Visibility class Cls (1..5).each do |i| define_method(“m#{i}”){}class Cls end! def public_method !! ! self.private_method public :m1, m2 !end private :m3, m4! protected :m5 ! !! private end!! def private_method; endendC.new.public_method #=> NoMethodError: private method
  47. 47. Method Visibility Code: Dynamic Dispatch c = Cls.new c.send :private_methodContext c.instance_eval {private_method} Probe c.instance_eval {@var}
  48. 48. ExceptionsCode: begin raise “blew up” rescue => ex puts “I #{ex}” end
  49. 49. ExceptionsCode: begin ... begin fail “error” raise “blew up” ... rescue => ex rescue StandardError => ex puts “I #{ex}” puts “Failed: ” + ex end raise else ... ensure # clean up ... end
  50. 50. ExceptionsCode: begin ... begin fail “error” raise “blew up” ... rescue => ex rescue StandardError => ex puts “I #{ex}” puts “Failed: ” + ex end raise else ... ensure # clean up tries = 0 ... begin end tries += 1 puts "Trying #{tries}..." raise "Didn’t work" rescue retry if tries < 3 puts "I give up" end
  51. 51. ExceptionsCode: begin ... begin fail “error” raise “blew up” ... rescue => ex rescue StandardError => ex puts “I #{ex}” puts “Failed: ” + ex end raise else ... ensure Retry # clean up tries = 0 ... begin end tries += 1 puts "Trying #{tries}..." raise "Didn’t work" rescue retry if tries < 3 puts "I give up" end
  52. 52. Exceptions (raise)Code: def raise(error_cls_or_obj, msg, backtrace) error = error_cls_or_obj.exception(msg) #... end
  53. 53. Exceptions (raise)Code: def raise(error_cls_or_obj, msg, backtrace) error = error_cls_or_obj.exception(msg) #... end # Bang! module RaiseExit def raise(msg_or_exc, msg=msg_or_exc, trace=caller) warn msg.to_s exit! end end class Object include RaiseExit end
  54. 54. Exceptions (dynamic rescue clauses)Code: ignore_exceptions(IOError, SystemCallError) do open("NONEXISTENT_FILE") end def ignore_exceptions(*exceptions) yield rescue *exceptions => e puts "IGNORED: ’#{e}’" end
  55. 55. (Meta)Programming
  56. 56. (Meta)Programming Class Macros ExampleCode: Class Customer def name @name end def name=(n) @name = n end ... def age @age end def age=(a) @age = a end end
  57. 57. (Meta)Programming Class Macros ExampleCode: Class Customer class Customer def name attr_accessor :name, :surname, :age @name end end def name=(n) @name = n end ... def age @age end def age=(a) @age = a end end
  58. 58. (Meta)Programming Class Macros ExampleCode: Class Customer class Customer def name attr_accessor :name, :surname, :age @name end end def name=(n) class Customer @name = n def self.attr_accessor(*accessors) end accessors.each do |accessor| ... define_method(accessor) do instance_variable_get("@#{accessor}") def age end @age end define_method("#{accessor}=") do |accessor_value| instance_variable_set("@#{accessor}", accessor_value) def age=(a) end @age = a end end end end end
  59. 59. Hook Methods (a.k.a. callbacks)Method related hooks Class and module related hooks• method_missing• method_added • append_features• method_removed • const_missing• method_undefined • extend_object• singleton_method_added • extended• • includedsingleton_method_removed• • inheritedsingleton_method_undefined • initialize_copyObject marshaling Coercionhooks hooks• marshal_dump • coerce• marshal_load • induced_from • to_xxx
  60. 60. Method Missing Code: config = { :host => ws.contactlab.it, :path => /RPC2, :use_ssl => true } class ContactLab def initialize(c) @ws_client = XMLRPC::Client.new(c) end def method_missing(rpc_method_name, *params) @ws_client.call("contactlab.#{rpc_method_name}", params) end end ContactLab.new(config).addNewRecipient(recipient)
  61. 61. Scripting
  62. 62. ExpressionsCode: song_type = if song.mp3Type == MP3::Jazz if song.written < Date.new(1935, 1, 1) Song::TradJazz else Song::Jazz end else Song::Other end
  63. 63. Infrastructure as codeCode: package "rabbimq-server" do action :install end service "rabbitmq-server" do supports :status => true, :restart => true, :reload => true action[:enable, :start] end
  64. 64. Testing
  65. 65. Code:describe Stack do RSpec before(:each) do @stack = Stack.new @stack.push :item end describe "#peek" do it "returns the top element" do @stack.peek.should == :item end it "doesn’t remove the top" do @stack.peek @stack.size.should == 1 end end describe "#pop" do it "returns the top element" do @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  66. 66. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do @stack.peek.should == :item end it "doesn’t remove the top" do @stack.peek @stack.size.should == 1 end end describe "#pop" do it "returns the top element" do @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  67. 67. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do @stack.peek @stack.size.should == 1 end end describe "#pop" do it "returns the top element" do @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  68. 68. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do expect{do_something_risky}.to raise_error /too risky/ @stack.peek @stack.size.should == 1 end end describe "#pop" do it "returns the top element" do @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  69. 69. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do expect{do_something_risky}.to raise_error /too risky/ @stack.peek @stack.size.should == 1 end array.empty?.should == true <--> array.should be_empty end describe "#pop" do it "returns the top element" do @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  70. 70. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do expect{do_something_risky}.to raise_error /too risky/ @stack.peek @stack.size.should == 1 end array.empty?.should == true <--> array.should be_empty end describe "#pop" do field.players.select{|p| p.team == home_team} it "returns the top element" do .length.should == 9 @stack.pop.should == :item end it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  71. 71. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do expect{do_something_risky}.to raise_error /too risky/ @stack.peek @stack.size.should == 1 end array.empty?.should == true <--> array.should be_empty end describe "#pop" do field.players.select{|p| p.team == home_team} it "returns the top element" do .length.should == 9 @stack.pop.should == :item end home_team.should have(9).players_on(field) it "removes the top element" do @stack.pop @stack.size.should == 0 end endend
  72. 72. Code:describe Stack do RSpec before(:each) do @stack = Stack.new expect { @stack.push :item User.create!(:role => "admin") end }.to change{ User.admins.count }.by(1) describe "#peek" do it "returns the top element" do result.should be_close(5.25, 0.005) @stack.peek.should == :item end it "doesn’t remove the top" do expect{do_something_risky}.to raise_error /too risky/ @stack.peek @stack.size.should == 1 end array.empty?.should == true <--> array.should be_empty end describe "#pop" do field.players.select{|p| p.team == home_team} it "returns the top element" do .length.should == 9 @stack.pop.should == :item end home_team.should have(9).players_on(field) it "removes the top element" do @stack.pop a_politician.should have_at_least(3).escorts @stack.size.should == 0 end endend
  73. 73. Code: Cucumber Feature: Google Search In order to learn something As an internet user I want to search for information on Google Scenario: Learn about Scrat Given I am on google.com When I search for "Scrat" Then I should see search results about Scrat When /^I search for ["](.*)["]$/ do |query| fill_in(q, :with => query) click_button(Google Search) end Then /^I should see search results about (.*)$/ do |term| response_body.should include(term) end
  74. 74. The Object Model Revisited
  75. 75. Splash "motherboard" =~ /board/class String in_place! %w(a b c).freeze alias :real_length :length empty? :symbol def length a ||= [] real_length > 5 ? long : short end raise InvalidFormat unless Formats.include?(format)end [1,2,3].map{ |e| e * e } #=> [1,4,9] [1,2,3].inject{|sum, e| s + e} #=> 6 [1,2,3].select{|e| e % 2 != 0} #=> [1, 3] class Singleton RSpecspec = Gem::Specification.new do |s| s.name = “My Gem name” class << self s.version = “0.0.1” def instance File.instance_methods.grep(/.*each.*/) # ... @instance ||= newend end chars = "hello world".tap {|x| puts "original object: #{x.inspect}"} .each_char .tap {|x| puts "each_char returns: #{x.inspect}"} private :new .to_a .tap {|x| puts "to_a returns: #{x.inspect}"} end .map {|c| c.succ } .tap {|x| puts "map returns: #{x.inspect}" } end .sort .tap {|x| puts "sort returns: #{x.inspect}"}
  76. 76. Why Ruby?
  77. 77. Why Ruby?Your own choice!!!
  78. 78. ns? stio ueQ
  79. 79. References
  80. 80. Than k you :) !

×