Ruby 101

7,529 views
7,548 views

Published on

Rob Cameron, Developer at the Active Network, discusses the awesomeness that is the Ruby programming language.

Published in: Technology, Education
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,529
On SlideShare
0
From Embeds
0
Number of Embeds
5,853
Actions
Shares
0
Downloads
18
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Ruby 101

  1. 1. Ruby 101
  2. 2. Your favorite language sucks. language sucks.
  3. 3. Ruby is the greatest language ever made.
  4. 4. Ruby is the greatest language ever made. And if you disagree, you’re wrong.
  5. 5. February 24, 1993
  6. 6. Yukihiro “Matz” Matsumoto まつもとゆきひろ
  7. 7. Yukihiro “Matz” Matsumoto “ I wanted a scripting language that was more powerful than Perl, and more object-oriented than Python. That's why I decided to design my own language.”
  8. 8. Yukihiro “Matz” Matsumoto “ I hope to see Ruby help every programmer in the world to be productive, to enjoy programming, and to be happy. “ That is the primary purpose of the Ruby language.”
  9. 9. Yukihiro “Matz” Matsumoto “ 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.”
  10. 10. for ( var i = 0 ; i < 3 ; i ++ ) { alert ( 'Hello, world!' ); }
  11. 11. for ( var i = 0 ; i < 3 ; i ++ ) { alert ( 'Hello, world!' ); } 3 .times do puts 'Hello, world!' end
  12. 12. var people = [ 'Rob' , 'Eugene' , 'Crystal' ]; for ( var i = 0 ; i < people. length ; i ++ ) { alert (people[i] + ' loves Ruby' ); }
  13. 13. var people = [ 'Rob' , 'Eugene' , 'Crystal' ]; for ( var i = 0 ; i < people. length ; i ++ ) { alert (people[i] + ' loves Ruby' ); } [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end
  14. 14. var today = new Date (); today. setDate (today. getDate () + 2 );
  15. 15. var today = new Date (); today. setDate (today. getDate () + 2 ); 2 .days.from_now
  16. 16. Yukihiro “Matz” Matsumoto “ Sometimes people jot down pseudo-code on paper. If that pseudo-code runs directly on their computers, it’s best, isn’t it? “ Ruby tries to be like that, like pseudo-code that runs.”
  17. 17. REPL
  18. 18. REPL Read - Eval - Print - Loop
  19. 19. REPL Read - Eval - Print - Loop irb
  20. 20. REPL Read - Eval - Print - Loop irb interactive ruby
  21. 21. rob$
  22. 22. rob$ irb
  23. 23. rob$ irbruby-1.9.2 :001 >
  24. 24. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']
  25. 25. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 >
  26. 26. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length
  27. 27. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length => 3 ruby-1.9.2 :003 >
  28. 28. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length => 3 ruby-1.9.2 :003 > people.last
  29. 29. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length => 3 ruby-1.9.2 :003 > people.last => &quot;Crystal&quot; ruby-1.9.2 :004 >
  30. 30. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length => 3 ruby-1.9.2 :003 > people.last => &quot;Crystal&quot; ruby-1.9.2 :004 > people.reverse
  31. 31. rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 > people.length => 3 ruby-1.9.2 :003 > people.last => &quot;Crystal&quot; ruby-1.9.2 :004 > people.reverse => [&quot;Crystal&quot;, &quot;Eugene&quot;, &quot;Rob&quot;] ruby-1.9.2 :005 >
  32. 32. The Basics
  33. 33. count = 42
  34. 34. count = 42 amount = 23.83
  35. 35. count = 42 amount = 23.83 language = 'Ruby'
  36. 36. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot;
  37. 37. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ]
  38. 38. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ] person = { :name => 'Rob' , :gender => 'male' }
  39. 39. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ] person = { :name => 'Rob' , :gender => 'male' } this = true
  40. 40. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ] person = { :name => 'Rob' , :gender => 'male' } this = true that = false
  41. 41. count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ] person = { :name => 'Rob' , :gender => 'male' } this = true that = false nothing = nil
  42. 42. [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end
  43. 43. [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end Iterators
  44. 44. [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end Iterators each find collect each_with_index reject inject
  45. 45. $ ( 'li' ).each( function (index) { alert ( 'index=' + index); });
  46. 46. $ ( 'li' ).each( function (index) { alert ( 'index=' + index); }); an_array.each do | item | puts &quot;item=#{item}&quot; end
  47. 47. Loops?
  48. 48. Conditionals
  49. 49. if person.has_red_hair? Sun .burn person end
  50. 50. if person.has_red_hair? Sun .burn person end unless car.sugar_in_gas_tank? car.start end
  51. 51. if person.has_red_hair? Sun .burn person end unless car.sugar_in_gas_tank? car.start end 15 .times { wash_hands } if person.ocd?
  52. 52. if person.has_red_hair? Sun .burn person end unless car.sugar_in_gas_tank? car.start end 15 .times { wash_hands } if person.ocd? car.accelerate unless TrafficLight .is_red?
  53. 53. if just_worked_out and date_tonight take_a_shower end
  54. 54. if just_worked_out and date_tonight take_a_shower end if love_mom or just_drunk get_a_tattoo end
  55. 55. if just_worked_out and date_tonight take_a_shower end if love_mom or just_drunk get_a_tattoo end if taco_bell? and not pepto_bismol_nearby? get_to_bathroom! end
  56. 56. !
  57. 57. airlines = [ 'Southwest' , 'United' , 'Delta' ]
  58. 58. airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ]
  59. 59. airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ]
  60. 60. airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse! => [ 'Delta' , 'United' , 'Southwest' ]
  61. 61. airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse! => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Delta' , 'United' , 'Southwest' ]
  62. 62. everything is an object
  63. 63. ‘ Rob’.class
  64. 64. ‘ Rob’.class => String
  65. 65. ‘ Rob’.class => String 42.class
  66. 66. ‘ Rob’.class => String 42.class => Fixnum
  67. 67. ‘ Rob’.class => String 42.class => Fixnum (23.45).class
  68. 68. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float
  69. 69. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class
  70. 70. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass
  71. 71. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class
  72. 72. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass
  73. 73. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class
  74. 74. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class
  75. 75. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class
  76. 76. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class
  77. 77. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass
  78. 78. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module
  79. 79. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass
  80. 80. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass => Object
  81. 81. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass => Object Object.superclass
  82. 82. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass => Object Object.superclass => BasicObject
  83. 83. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass => Object Object.superclass => BasicObject BasicObject.superclass
  84. 84. ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass => Module Module.superclass => Object Object.superclass => BasicObject BasicObject.superclass => nil
  85. 85. Class, Object, Module and all other classes are instances of a class Class . Class, Module and Object have a circular dependency as they are in the core of the OO model
  86. 86. Introspection
  87. 87. 42.methods
  88. 88. 42.methods [:!, :!=, :!~, :%, :&, :*, :**, :+, :+@, :-, :-@, :/, :<, :<<, :<=, :<=>, :==, :===, :=~, :>, :>=, :>>, :[], :^, :__id__, :__send__, :abs, :abs2, :angle, :arg, :between?, :ceil, :chr, :class, :clone, :coerce, :conj, :conjugate, :define_singleton_method, :denominator, :display, :div, :divmod, :downto, :dup, :enum_for, :eql?, :equal?, :even?, :extend, :fdiv, :floor, :freeze, :frozen?, :gcd, :gcdlcm, :hash, :i, :imag, :imaginary, :initialize_clone, :initialize_dup, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_variable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :integer?, :is_a?, :kind_of?, :lcm, :magnitude, :method, :methods, :modulo, :next, :nil?, :nonzero?, :numerator, :object_id, :odd?, :ord, :phase, :polar, :pred, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :quo, :rationalize, :real, :real?, :rect, :rectangular, :remainder, :respond_to?, :respond_to_missing?, :round, :send, :singleton_class, :singleton_method_added, :singleton_methods, :size, :step, :succ, :taint, :tainted?, :tap, :times, :to_c, :to_enum, :to_f, :to_i, :to_int, :to_r, :to_s, :truncate, :trust, :untaint, :untrust, :untrusted?, :upto, :zero?, :|, :~]
  89. 89. 42.methods [:!, :!=, :!~, :%, :&, :*, :**, :+, :+@, :-, :-@, :/, :<, :<<, :<=, :<=>, :==, :===, :=~, :>, :>=, :>>, :[], :^, :__id__, :__send__, :abs, :abs2, :angle, :arg, :between?, :ceil, :chr, :class, :clone, :coerce, :conj, :conjugate, :define_singleton_method, :denominator, :display, :div, :divmod, :downto, :dup, :enum_for, :eql?, :equal?, :even?, :extend, :fdiv, :floor, :freeze, :frozen?, :gcd, :gcdlcm, :hash, :i, :imag, :imaginary, :initialize_clone, :initialize_dup, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_variable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables , :integer?, :is_a?, :kind_of?, :lcm, :magnitude, :method, :methods, :modulo, :next, :nil?, :nonzero?, :numerator, :object_id, :odd?, :ord, :phase, :polar, :pred, :private_methods , :protected_methods, :public_method, :public_methods , :public_send, :quo, :rationalize, :real, :real?, :rect, :rectangular, :remainder, :respond_to? , :respond_to_missing?, :round, :send , :singleton_class, :singleton_method_added, :singleton_methods, :size, :step, :succ, :taint, :tainted?, :tap, :times, :to_c, :to_enum, :to_f, :to_i, :to_int, :to_r, :to_s, :truncate, :trust, :untaint, :untrust, :untrusted?, :upto, :zero?, :|, :~]
  90. 90. var method = 'first_name' eval ( 'person.' + method)
  91. 91. var method = 'first_name' eval ( 'person.' + method) method = 'first_name' person.send(method)
  92. 92. 2 + 2
  93. 93. 2 + 2 2.+(2)
  94. 94. 2 + 2 2.+(2) 2.send('+',2)
  95. 95. Syntactic Sugar
  96. 96. 2 == 2
  97. 97. 2 == 2 2.==(2)
  98. 98. 2 == 2 2.==(2) 2.send('==',2)
  99. 99. Ruby removes the cruft
  100. 100. car = Vehicle . new ( 'honda' , 'civic' , { :interior => 'beige' }) car = Vehicle . new 'honda' , 'civic' , :interior => 'beige'
  101. 101. Beautiful code
  102. 102. class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end end
  103. 103. class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end end rob = Person . new 'male' , 'blue' , 'square'
  104. 104. class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end end rob = Person . new 'male' , 'blue' , 'square' aimee = Person . new 'female' , 'brown' , 'cleft'
  105. 105. class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end end rob = Person . new 'male' , 'blue' , 'square' aimee = Person . new 'female' , 'brown' , 'cleft'
  106. 106. class Person def + ( other_person ) gene_pool = [ self ,other_person] Person . new selection(gene_pool, 'gender' ), selection(gene_pool, 'eyes' ), selection(gene_pool, 'chin' ) end def selection ( gene_pool,feature ) return gene_pool[rand(gene_pool.size)].send feature end private 'selection' end
  107. 107. baby = rob + aimee
  108. 108. baby = rob + aimee baby.name = 'Jack'
  109. 110. baby = rob + aimee baby.name = 'Jack' baby.name=( 'Jack' )
  110. 111. baby = rob + aimee baby.name = 'Jack' baby.name=( 'Jack' ) baby.inspect
  111. 112. baby = rob + aimee baby.name = 'Jack' baby.name=( 'Jack' ) baby.inspect #<Person:0x0000010083fdf0 @gender=&quot;male&quot;, @eyes=&quot;blue&quot;, @chin=&quot;cleft&quot;, @name=&quot;Jack&quot;>
  112. 113. “ When I am working on a problem I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.” — R. Buckminster Fuller
  113. 114. return gene_pool[rand(gene_pool.size)].send feature
  114. 115. return gene_pool[rand(gene_pool.size)].send feature class Array def random return self [rand( self .length)] end end
  115. 116. return gene_pool[rand(gene_pool.size)].send feature class Array def random return self [rand( self .length)] end end return gene_pool.random.send feature
  116. 117. unless []. respond_to ? 'random' class Array def random return self [rand( self .length)] end end end
  117. 118. Monkey Patching!!1!one!!!
  118. 119. David Heinemeier Hansson (DHH) “ Why Ruby” http://confreaks.net/system/assets/datas/694/original/431-rubyconf2010-keynote-why-ruby-small.mp4?1291226733
  119. 120. “ UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things.” — Doug Gwyn
  120. 121. “ There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code.” — Anonymous
  121. 122. class Array def random return self [rand( self .length)] end end class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end def + ( other_person ) gene_pool = [ self ,other_person] Person . new selection(gene_pool, 'gender' ), selection(gene_pool, 'eyes' ), selection(gene_pool, 'chin' ) end def selection ( gene_pool,feature ) return gene_pool.random.send feature end private 'selection' end
  122. 123. using System;using System.Collections.Concurrent;using System.Collections.Specialized;using System.ComponentModel.Composition;using System.Diagnostics;using System.IO;using System.IO.Compression;using System.Net;using System.Text.RegularExpressions;using System.Threading;using System.Linq;using Newtonsoft.Json;using NLog;using Raven.Abstractions.Data;using Raven.Abstractions.Exceptions;using Raven.Abstractions.MEF;using Raven.Http.Abstractions;using Raven.Http.Exceptions;using Raven.Http.Extensions;using Formatting = Newtonsoft.Json.Formatting;namespace Raven.Http{ public abstract class HttpServer : IDisposable { private const int MaxConcurrentRequests = 192; protected readonly IResourceStore DefaultResourceStore; protected readonly IRavenHttpConfiguration DefaultConfiguration; private readonly ThreadLocal<string> currentTenantId = new ThreadLocal<string>(); private readonly ThreadLocal<IResourceStore> currentDatabase = new ThreadLocal<IResourceStore>(); private readonly ThreadLocal<IRavenHttpConfiguration> currentConfiguration = new ThreadLocal<IRavenHttpConfiguration>(); protected readonly ConcurrentDictionary<string, IResourceStore> ResourcesStoresCache = new ConcurrentDictionary<string, IResourceStore>(StringComparer.InvariantCultureIgnoreCase); private readonly ConcurrentDictionary<string, DateTime> databaseLastRecentlyUsed = new ConcurrentDictionary<string, DateTime>();
  123. 124. public int NumberOfRequests { get { return Thread.VolatileRead(ref physicalRequestsCount); } } [ImportMany] public OrderedPartCollection<AbstractRequestResponder> RequestResponders { get; set; } public IRavenHttpConfiguration Configuration { get { return DefaultConfiguration; } } public abstract Regex TenantsQuery { get; } private HttpListener listener; private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private int reqNum; // concurrent requests // we set 1/4 aside for handling background tasks private readonly SemaphoreSlim concurretRequestSemaphore = new SemaphoreSlim(MaxConcurrentRequests); private Timer databasesCleanupTimer; private int physicalRequestsCount; public bool HasPendingRequests { get { return concurretRequestSemaphore.CurrentCount != MaxConcurrentRequests; } } protected HttpServer(IRavenHttpConfiguration configuration, IResourceStore resourceStore) {
  124. 125. DefaultResourceStore = resourceStore; DefaultConfiguration = configuration; configuration.Container.SatisfyImportsOnce(this); foreach (var requestResponder in RequestResponders) { requestResponder.Value.Initialize(() => currentDatabase.Value, () => currentConfiguration.Value, () => currentTenantId.Value, this); } } #region IDisposable Members public void Dispose() { databasesCleanupTimer.Dispose(); if (listener != null && listener.IsListening) listener.Stop(); foreach (var documentDatabase in ResourcesStoresCache) { documentDatabase.Value.Dispose(); } } #endregion public void Start() { listener = new HttpListener(); string virtualDirectory = DefaultConfiguration.VirtualDirectory; if (virtualDirectory.EndsWith(&quot;/&quot;) == false) virtualDirectory = virtualDirectory + &quot;/&quot;; listener.Prefixes.Add(&quot;http://&quot; + (DefaultConfiguration.HostName ?? &quot;+&quot;) + &quot;:&quot; + DefaultConfiguration.Port + virtualDirectory);
  125. 126. switch (DefaultConfiguration.AnonymousUserAccessMode) { case AnonymousUserAccessMode.None: listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication; break; case AnonymousUserAccessMode.All: listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication | AuthenticationSchemes.Anonymous; listener.AuthenticationSchemeSelectorDelegate = request => { if(request.RawUrl.StartsWith(&quot;/admin&quot;,StringComparison.InvariantCultureIgnoreCase)) return AuthenticationSchemes.IntegratedWindowsAuthentication; return AuthenticationSchemes.Anonymous; }; break; case AnonymousUserAccessMode.Get: listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication | AuthenticationSchemes.Anonymous; listener.AuthenticationSchemeSelectorDelegate = request => { return IsGetRequest(request.HttpMethod, request.Url.AbsolutePath) ? AuthenticationSchemes.Anonymous | AuthenticationSchemes.IntegratedWindowsAuthentication : AuthenticationSchemes.IntegratedWindowsAuthentication; }; break; default: throw new ArgumentException(&quot;Cannot understand access mode: &quot; + DefaultConfiguration.AnonymousUserAccessMode); } databasesCleanupTimer = new Timer(CleanupDatabases, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); listener.Start(); listener.BeginGetContext(GetContext, null); }
  126. 127. private void CleanupDatabases(object state) { var databasesToCleanup = databaseLastRecentlyUsed .Where(x=>(DateTime.Now - x.Value).TotalMinutes > 10) .Select(x=>x.Key) .ToArray(); foreach (var db in databasesToCleanup) { DateTime _; databaseLastRecentlyUsed.TryRemove(db, out _); IResourceStore database; if(ResourcesStoresCache.TryRemove(db, out database)) database.Dispose(); } } private void GetContext(IAsyncResult ar) { IHttpContext ctx; try { ctx = new HttpListenerContextAdpater(listener.EndGetContext(ar), DefaultConfiguration); //setup waiting for the next request listener.BeginGetContext(GetContext, null); } catch (InvalidOperationException) { // can't get current request / end new one, probably // listner shutdown return; } catch (HttpListenerException) { // can't get current request / end new one, probably // listner shutdown return; }
  127. 128. if (concurretRequestSemaphore.Wait(TimeSpan.FromSeconds(5)) == false) { HandleTooBusyError(ctx); return; } try { Interlocked.Increment(ref physicalRequestsCount); HandleActualRequest(ctx); } finally { concurretRequestSemaphore.Release(); } } public void HandleActualRequest(IHttpContext ctx) { var sw = Stopwatch.StartNew(); bool ravenUiRequest = false; try { ravenUiRequest = DispatchRequest(ctx); } catch (Exception e) { HandleException(ctx, e); if (ShouldLogException(e)) logger.WarnException(&quot;Error on request&quot;, e); } finally { try { FinalizeRequestProcessing(ctx, sw, ravenUiRequest); } catch (Exception e) { logger.ErrorException(&quot;Could not finalize request properly&quot;, e); }
  128. 129. protected virtual bool ShouldLogException(Exception exception) { return true; } private void FinalizeRequestProcessing(IHttpContext ctx, Stopwatch sw, bool ravenUiRequest) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, ctx.Request.Headers, ctx.Request.HttpMethod, ctx.Response.StatusCode, ctx.Request.Url.PathAndQuery); } catch (Exception e) { logger.WarnException(&quot;Could not gather information to log request stats&quot;, e); } ctx.FinalizeResonse(); sw.Stop(); if (ravenUiRequest || logHttpRequestStatsParam == null) return; LogHttpRequestStats(logHttpRequestStatsParam); ctx.OutputSavedLogItems(logger); } private void LogHttpRequestStats(LogHttpRequestStatsParams logHttpRequestStatsParams) { // we filter out requests for the UI because they fill the log with information // we probably don't care about them anyway. That said, we do output them if they take too // long.
  129. 130. if (logHttpRequestStatsParams.Headers[&quot;Raven-Timer-Request&quot;] == &quot;true&quot; && logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds <= 25) return; var curReq = Interlocked.Increment(ref reqNum); logger.Debug(&quot;Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}&quot;, curReq, logHttpRequestStatsParams.HttpMethod, logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, logHttpRequestStatsParams.ResponseStatusCode, logHttpRequestStatsParams.RequestUri, currentTenantId.Value); } private void HandleException(IHttpContext ctx, Exception e) { try { if (e is BadRequestException) HandleBadRequest(ctx, (BadRequestException)e); else if (e is ConcurrencyException) HandleConcurrencyException(ctx, (ConcurrencyException)e); else if (TryHandleException(ctx, e)) return; else HandleGenericException(ctx, e); } catch (Exception) { logger.ErrorException(&quot;Failed to properly handle error, further error handling is ignored&quot;, e); } } protected abstract bool TryHandleException(IHttpContext ctx, Exception exception);
  130. 131. private static void HandleTooBusyError(IHttpContext ctx) { ctx.Response.StatusCode = 503; ctx.Response.StatusDescription = &quot;Service Unavailable&quot;; SerializeError(ctx, new { Url = ctx.Request.RawUrl, Error = &quot;The server is too busy, could not acquire transactional access&quot; }); } private static void HandleGenericException(IHttpContext ctx, Exception e) { ctx.Response.StatusCode = 500; ctx.Response.StatusDescription = &quot;Internal Server Error&quot;; SerializeError(ctx, new { Url = ctx.Request.RawUrl, Error = e.ToString() }); } private static void HandleBadRequest(IHttpContext ctx, BadRequestException e) { ctx.SetStatusToBadRequest(); SerializeError(ctx, new { Url = ctx.Request.RawUrl, e.Message, Error = e.Message }); }
  131. 132. private static void HandleConcurrencyException(IHttpContext ctx, ConcurrencyException e) { ctx.Response.StatusCode = 409; ctx.Response.StatusDescription = &quot;Conflict&quot;; SerializeError(ctx, new { Url = ctx.Request.RawUrl, e.ActualETag, e.ExpectedETag, Error = e.Message }); } protected static void SerializeError(IHttpContext ctx, object error) { var sw = new StreamWriter(ctx.Response.OutputStream); new JsonSerializer().Serialize(new JsonTextWriter(sw) { Formatting = Formatting.Indented, }, error); sw.Flush(); } private bool DispatchRequest(IHttpContext ctx) { if (AssertSecurityRights(ctx) == false) return false; SetupRequestToProperDatabase(ctx); CurrentOperationContext.Headers.Value = ctx.Request.Headers; try { OnDispatchingRequest(ctx); if (DefaultConfiguration.HttpCompression) AddHttpCompressionIfClientCanAcceptIt(ctx);
  132. 133. AddAccessControlAllowOriginHeader(ctx); foreach (var requestResponderLazy in RequestResponders) { var requestResponder = requestResponderLazy.Value; if (requestResponder.WillRespond(ctx)) { requestResponder.Respond(ctx); return requestResponder.IsUserInterfaceRequest; } } ctx.SetStatusToBadRequest(); if (ctx.Request.HttpMethod == &quot;HEAD&quot;) return false; ctx.Write( @&quot;<html> <body> <h1>Could not figure out what to do</h1> <p>Your request didn't match anything that Raven knows to do, sorry...</p> </body></html>&quot;); } finally { CurrentOperationContext.Headers.Value = new NameValueCollection(); currentDatabase.Value = DefaultResourceStore; currentConfiguration.Value = DefaultConfiguration; } return false; } protected virtual void OnDispatchingRequest(IHttpContext ctx){}
  133. 134. private void SetupRequestToProperDatabase(IHttpContext ctx) { var requestUrl = ctx.GetRequestUrlForTenantSelection(); var match = TenantsQuery.Match(requestUrl); if (match.Success == false) { currentTenantId.Value = Constants.DefaultDatabase; currentDatabase.Value = DefaultResourceStore; currentConfiguration.Value = DefaultConfiguration; } else { var tenantId = match.Groups[1].Value; IResourceStore resourceStore; if(TryGetOrCreateResourceStore(tenantId, out resourceStore)) { databaseLastRecentlyUsed.AddOrUpdate(tenantId, DateTime.Now, (s, time) => DateTime.Now); if (string.IsNullOrEmpty(Configuration.VirtualDirectory) == false && Configuration.VirtualDirectory != &quot;/&quot;) { ctx.AdjustUrl(Configuration.VirtualDirectory + match.Value); } else { ctx.AdjustUrl(match.Value); } currentTenantId.Value = tenantId; currentDatabase.Value = resourceStore; currentConfiguration.Value = resourceStore.Configuration; } else { throw new BadRequestException(&quot;Could not find a database named: &quot; + tenantId); } } }
  134. 135. protected abstract bool TryGetOrCreateResourceStore(string name, out IResourceStore database); private void AddAccessControlAllowOriginHeader(IHttpContext ctx) { if (string.IsNullOrEmpty(DefaultConfiguration.AccessControlAllowOrigin)) return; ctx.Response.AddHeader(&quot;Access-Control-Allow-Origin&quot;, DefaultConfiguration.AccessControlAllowOrigin); } private static void AddHttpCompressionIfClientCanAcceptIt(IHttpContext ctx) { var acceptEncoding = ctx.Request.Headers[&quot;Accept-Encoding&quot;]; if (string.IsNullOrEmpty(acceptEncoding)) return; // gzip must be first, because chrome has an issue accepting deflate data // when sending it json text if ((acceptEncoding.IndexOf(&quot;gzip&quot;, StringComparison.InvariantCultureIgnoreCase) != -1)) { ctx.SetResponseFilter(s => new GZipStream(s, CompressionMode.Compress, true)); ctx.Response.AddHeader(&quot;Content-Encoding&quot;,&quot;gzip&quot;); } else if (acceptEncoding.IndexOf(&quot;deflate&quot;, StringComparison.InvariantCultureIgnoreCase) != -1) { ctx.SetResponseFilter(s => new DeflateStream(s, CompressionMode.Compress, true)); ctx.Response.AddHeader(&quot;Content-Encoding&quot;, &quot;deflate&quot;); } } private bool AssertSecurityRights(IHttpContext ctx) { if (DefaultConfiguration.AnonymousUserAccessMode == AnonymousUserAccessMode.None && IsInvalidUser(ctx)) { ctx.SetStatusToUnauthorized(); return false; }
  135. 136. IHttpRequest httpRequest = ctx.Request; if (DefaultConfiguration.AnonymousUserAccessMode == AnonymousUserAccessMode.Get && IsInvalidUser(ctx) && IsGetRequest(httpRequest.HttpMethod, httpRequest.Url.AbsolutePath) == false ) { ctx.SetStatusToUnauthorized(); return false; } return true; } protected virtual bool IsGetRequest(string httpMethod, string requestPath) { return (httpMethod == &quot;GET&quot; || httpMethod == &quot;HEAD&quot;); } private static bool IsInvalidUser(IHttpContext ctx) { return (ctx.User == null || ctx.User.Identity == null || ctx.User.Identity.IsAuthenticated == false); } public void ResetNumberOfRequests() { Interlocked.Exchange(ref reqNum, 0); Interlocked.Exchange(ref physicalRequestsCount, 0); } }} 517 lines of code
  136. 137. webserver = TCPServer . new ( '127.0.0.1' , 3000 ) while (session = webserver.accept) session.print &quot;HTTP/1.1 200/OK rn Content-type:text/html rnrn &quot; request = session.gets filename = request.match( / / (.*?) / )[ 1 ] filename = 'index.html' if filename == '' begin session.print File .read(filename) rescue Errno :: ENOENT session.print 'File not found' end session.close end
  137. 138. “ There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.” — C.A.R. Hoare
  138. 139. class Person def + ( other_person ) gene_pool = [ self ,other_person] Person . new selection(gene_pool, 'gender' ), selection(gene_pool, 'eyes' ), selection(gene_pool, 'chin' ) end def selection ( gene_pool,feature ) return gene_pool[rand(gene_pool.size)].send feature end private 'selection' end
  139. 140. class Person def + ( other_person ) gene_pool = [ self ,other_person] Person . new selection(gene_pool, 'gender' ), selection(gene_pool, 'eyes' ), selection(gene_pool, 'chin' ) end def selection ( gene_pool,feature ) return gene_pool[rand(gene_pool.size)].send feature end private 'selection' end
  140. 141. class Person def + ( other_person ) gene_pool = [ self ,other_person] Person . new selection(gene_pool, 'gender' ), selection(gene_pool, 'eyes' ), selection(gene_pool, 'chin' ) end def selection ( gene_pool,feature ) return gene_pool[rand(gene_pool.size)].send feature end private 'selection' end
  141. 142. Implicit return Any statement in Ruby returns the value of the last evaluated expression
  142. 143. ruby-1.9.2 :001 > puts 'Hello, world!'
  143. 144. ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 >
  144. 145. ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 > puts('Hello, world!')
  145. 146. ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 > puts('Hello, world!')Hello, world! => nil ruby-1.9.2 :003 >
  146. 147. Blabber Talk to your servers via IM
  147. 149. gems
  148. 150. rob$
  149. 151. rob$ gem install rails
  150. 152. rob$ gem install rails rob$ gem install httparty json
  151. 153. require 'rubygems' require 'json' require 'httparty'
  152. 154. rob$ irbruby-1.9.2 :001 >
  153. 155. rob$ irbruby-1.9.2 :001 > HTTParty
  154. 156. rob$ irbruby-1.9.2 :001 > HTTPartyNameError: uninitialized constant Object::HTTParty from (irb):1 from /Users/rob/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'ruby-1.9.2 :002 >
  155. 157. rob$ irbruby-1.9.2 :001 > HTTPartyNameError: uninitialized constant Object::HTTParty from (irb):1 from /Users/rob/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'ruby-1.9.2 :002 > require 'httparty'
  156. 158. rob$ irbruby-1.9.2 :001 > HTTPartyNameError: uninitialized constant Object::HTTParty from (irb):1 from /Users/rob/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'ruby-1.9.2 :002 > require 'httparty' => true ruby-1.9.2 :003 >
  157. 159. rob$ irbruby-1.9.2 :001 > HTTPartyNameError: uninitialized constant Object::HTTParty from (irb):1 from /Users/rob/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'ruby-1.9.2 :002 > require 'httparty' => true ruby-1.9.2 :003 > HTTParty
  158. 160. rob$ irbruby-1.9.2 :001 > HTTPartyNameError: uninitialized constant Object::HTTParty from (irb):1 from /Users/rob/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'ruby-1.9.2 :002 > require 'httparty' => true ruby-1.9.2 :003 > HTTParty => HTTParty ruby-1.9.2 :004 >
  159. 161. Questions?
  160. 162. Workshop
  161. 163. Command line interface to the Active.com Search API
  162. 164. It should:
  163. 165. <ul><li>It should: </li></ul><ul><ul><li>Present a list of channels and let the user select one </li></ul></ul>
  164. 166. <ul><li>It should: </li></ul><ul><ul><li>Present a list of channels and let the user select one </li></ul></ul><ul><ul><li>Prompt for (optional) keywords </li></ul></ul>
  165. 167. <ul><li>It should: </li></ul><ul><ul><li>Present a list of channels and let the user select one </li></ul></ul><ul><ul><li>Prompt for (optional) keywords </li></ul></ul><ul><ul><li>Present the top 10 results </li></ul></ul>
  166. 168. <ul><li>It should: </li></ul><ul><ul><li>Present a list of channels and let the user select one </li></ul></ul><ul><ul><li>Prompt for (optional) keywords </li></ul></ul><ul><ul><li>Present the top 10 results </li></ul></ul><ul><ul><li>Let the user select one result </li></ul></ul>
  167. 169. <ul><li>It should: </li></ul><ul><ul><li>Present a list of channels and let the user select one </li></ul></ul><ul><ul><li>Prompt for (optional) keywords </li></ul></ul><ul><ul><li>Present the top 10 results </li></ul></ul><ul><ul><li>Let the user select one result </li></ul></ul><ul><ul><li>Present the title, location, start date and asset ID of the selected event </li></ul></ul>
  168. 170. Example
  169. 171. What you need to know
  170. 172. Required Gems require 'json' require 'httparty'
  171. 173. Search API Endpoint http://api.amp.active.com/search? v=json& k=keywords& m=meta:channel%3DRunning& api_key=wuhmn9ye94xn3xnteudxsavw
  172. 174. HTTP call HTTParty.get(url)
  173. 175. Parse JSON JSON.parse(text) HTTP call HTTParty.get(url)
  174. 176. Get user input user_input = gets
  175. 177. Get user input user_input = gets Remove newlines user_input.chomp
  176. 178. Get user input user_input = gets Print to STDOUT print 'text'puts 'text' Remove newlines user_input.chomp
  177. 179. Iterate through array with index my_array.each_with_index do |item,i| puts “#{item} is at position #{i}” end
  178. 180. Exit exit 0 Iterate through array with index my_array.each_with_index do |item,i| puts “#{item} is at position #{i}” end
  179. 181. Define methods <ul><li>def method_name(first, second) </li></ul><ul><ul><ul><li># code </li></ul></ul></ul><ul><ul><ul><li>end </li></ul></ul></ul>Create classes <ul><li>class ClassName </li></ul><ul><ul><ul><li>def initialize </li></ul></ul></ul><ul><ul><ul><li># code </li></ul></ul></ul><ul><ul><ul><li>end </li></ul></ul></ul><ul><ul><ul><li>end </li></ul></ul></ul>
  180. 182. Questions?
  181. 183. require 'json' require 'httparty' HTTParty.get(url) JSON.parse(text) user_input = gets print 'text' puts 'text' user_input.chomp my_array.each_with_index do |item,i| puts “#{item} is as position #{i}” end http://api.amp.active.com/search? v=json& k=keywords& m=meta:channel%3DRunning& api_key= wuhmn9ye94xn3xnteudxsavw exit 0
  182. 184. “ I am rarely happier than when spending an entire day programming my computer to perform automatically a task that would otherwise take me a good ten seconds to do by hand.” — Douglas Adams
  183. 185. Learning a new language
  184. 188. EGO
  185. 189. “ Would you rather be a king of fools or a student of masters?”
  186. 190. The End

×