ruby 101

190
Ruby 101

Upload: the-active-network

Post on 18-May-2015

7.080 views

Category:

Technology


2 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Ruby 101

Ruby 101

Page 2: Ruby 101

Your favoritelanguage

sucks.

Page 3: Ruby 101

Ruby is the greatest

language ever made.

Page 4: Ruby 101

Ruby is the greatest

language ever made.

And if you disagree, you’re wrong.

Page 5: Ruby 101

February 24, 1993

Page 6: Ruby 101

Yukihiro “Matz” Matsumotoまつもとゆきひろ

Page 7: Ruby 101

“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.”

Page 8: Ruby 101

“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.”

Page 9: Ruby 101

“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.”

Page 10: Ruby 101

for (var i=0; i<3; i++) { alert('Hello, world!');}

Page 11: Ruby 101

for (var i=0; i<3; i++) { alert('Hello, world!');}

3.times do puts 'Hello, world!'end

Page 12: Ruby 101

var people = ['Rob','Eugene','Crystal'];for (var i=0; i<people.length; i++) { alert(people[i] + ' loves Ruby');}

Page 13: Ruby 101

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 "#{name} loves Ruby"end

Page 14: Ruby 101

var today = new Date();today.setDate(today.getDate() + 2);

Page 15: Ruby 101

var today = new Date();today.setDate(today.getDate() + 2);

2.days.from_now

Page 16: Ruby 101

“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.”

Page 17: Ruby 101

REPL

Page 18: Ruby 101

REPL

Read - Eval - Print - Loop

Page 19: Ruby 101

REPL

Read - Eval - Print - Loop

irb

Page 20: Ruby 101

REPL

Read - Eval - Print - Loop

irbinteractive ruby

Page 21: Ruby 101

rob$

Page 22: Ruby 101

rob$ irb

Page 23: Ruby 101

rob$ irbruby-1.9.2 :001 >

Page 24: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

Page 25: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

Page 26: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length

Page 27: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length => 3 ruby-1.9.2 :003 >

Page 28: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length => 3 ruby-1.9.2 :003 > people.last

Page 29: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length => 3 ruby-1.9.2 :003 > people.last => "Crystal"

ruby-1.9.2 :004 >

Page 30: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length => 3 ruby-1.9.2 :003 > people.last => "Crystal"

ruby-1.9.2 :004 > people.reverse

Page 31: Ruby 101

rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']

=> ["Rob", "Eugene", "Crystal"] ruby-1.9.2 :002 >

people.length => 3 ruby-1.9.2 :003 > people.last => "Crystal"

ruby-1.9.2 :004 > people.reverse => ["Crystal", "Eugene",

"Rob"]

ruby-1.9.2 :005 >

Page 32: Ruby 101

The Basics

Page 33: Ruby 101

count = 42

Page 34: Ruby 101

count = 42

amount = 23.83

Page 35: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

Page 36: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

Page 37: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

people = ['Rob','Eugene','Crystal']

Page 38: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

people = ['Rob','Eugene','Crystal']

person = { :name => 'Rob', :gender => 'male' }

Page 39: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

people = ['Rob','Eugene','Crystal']

person = { :name => 'Rob', :gender => 'male' }

this = true

Page 40: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

people = ['Rob','Eugene','Crystal']

person = { :name => 'Rob', :gender => 'male' }

this = true

that = false

Page 41: Ruby 101

count = 42

amount = 23.83

language = 'Ruby'

text = "#{language} is the best!"

people = ['Rob','Eugene','Crystal']

person = { :name => 'Rob', :gender => 'male' }

this = true

that = false

nothing = nil

Page 42: Ruby 101

['Rob','Eugene','Crystal'].each do |name| puts "#{name} loves Ruby"end

Page 43: Ruby 101

['Rob','Eugene','Crystal'].each do |name| puts "#{name} loves Ruby"end

Iterators

Page 44: Ruby 101

['Rob','Eugene','Crystal'].each do |name| puts "#{name} loves Ruby"end

Iterators

each find collect each_with_index reject

inject

Page 45: Ruby 101

$('li').each(function(index) { alert('index='+index);});

Page 46: Ruby 101

$('li').each(function(index) { alert('index='+index);});

an_array.each do |item| puts "item=#{item}"end

Page 47: Ruby 101

Loops?

Page 48: Ruby 101

Conditionals

Page 49: Ruby 101

if person.has_red_hair? Sun.burn personend

Page 50: Ruby 101

if person.has_red_hair? Sun.burn personend

unless car.sugar_in_gas_tank? car.startend

Page 51: Ruby 101

if person.has_red_hair? Sun.burn personend

unless car.sugar_in_gas_tank? car.startend

15.times { wash_hands } if person.ocd?

Page 52: Ruby 101

if person.has_red_hair? Sun.burn personend

unless car.sugar_in_gas_tank? car.startend

15.times { wash_hands } if person.ocd?

car.accelerate unless TrafficLight.is_red?

Page 53: Ruby 101

if just_worked_out and date_tonight take_a_showerend

Page 54: Ruby 101

if just_worked_out and date_tonight take_a_showerend

if love_mom or just_drunk get_a_tattooend

Page 55: Ruby 101

if just_worked_out and date_tonight take_a_showerend

if love_mom or just_drunk get_a_tattooend

if taco_bell? and not pepto_bismol_nearby? get_to_bathroom!end

Page 56: Ruby 101

!

Page 57: Ruby 101

airlines = ['Southwest','United','Delta']

Page 58: Ruby 101

airlines = ['Southwest','United','Delta']airlines.reverse => ['Delta','United','Southwest']

Page 59: Ruby 101

airlines = ['Southwest','United','Delta']airlines.reverse => ['Delta','United','Southwest']puts airlines => ['Southwest','United','Delta']

Page 60: Ruby 101

airlines = ['Southwest','United','Delta']airlines.reverse => ['Delta','United','Southwest']puts airlines => ['Southwest','United','Delta']airlines.reverse! => ['Delta','United','Southwest']

Page 61: Ruby 101

airlines = ['Southwest','United','Delta']airlines.reverse => ['Delta','United','Southwest']puts airlines => ['Southwest','United','Delta']airlines.reverse! => ['Delta','United','Southwest']puts airlines => ['Delta','United','Southwest']

Page 62: Ruby 101

everything is an object

Page 63: Ruby 101

‘Rob’.class

Page 64: Ruby 101

‘Rob’.class => String

Page 65: Ruby 101

‘Rob’.class => String

42.class

Page 66: Ruby 101

‘Rob’.class => String

42.class => Fixnum

Page 67: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class

Page 68: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

Page 69: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class

Page 70: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

Page 71: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class

Page 72: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

Page 73: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

String.class

Page 74: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

String.class => Class

Page 75: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

String.class => Class

Class.class

Page 76: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

String.class => Class

Class.class => Class

Page 77: Ruby 101

‘Rob’.class => String

42.class => Fixnum

(23.45).class => Float

true.class => TrueClass

nil.class => NilClass

String.class => Class

Class.class => Class

Class.superclass

Page 78: Ruby 101

‘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

Page 79: Ruby 101

‘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

Page 80: Ruby 101

‘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

Page 81: Ruby 101

‘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

Page 82: Ruby 101

‘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

Page 83: Ruby 101

‘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

Page 84: Ruby 101

‘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

Page 85: Ruby 101

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

Page 86: Ruby 101

Introspection

Page 87: Ruby 101

42.methods

Page 88: Ruby 101

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, :imaginar

y, :initialize_clone, :initialize_dup, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_va

riable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :integer?, :is_a?, :

kind_of?, :lcm, :magnitude, :method, :methods, :modulo, :next, :nil?, :nonzero?, :numerator, :object_i

d, :odd?, :ord, :phase, :polar, :pred, :private_methods, :protected_methods, :public_method, :public_

methods, :public_send, :quo, :rationalize, :real, :real?, :rect, :rectangular, :remainder, :respond_to?, :r

espond_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, :trunca

te, :trust, :untaint, :untrust, :untrusted?, :upto, :zero?, :|, :~]

Page 89: Ruby 101

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, :imaginar

y, :initialize_clone, :initialize_dup, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_va

riable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :integer?, :is_a?, :

kind_of?, :lcm, :magnitude, :method, :methods, :modulo, :next, :nil?, :nonzero?, :numerator, :object_i

d, :odd?, :ord, :phase, :polar, :pred, :private_methods, :protected_methods, :public_method, :public_

methods, :public_send, :quo, :rationalize, :real, :real?, :rect, :rectangular, :remainder, :respond_to?, :r

espond_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, :trunca

te, :trust, :untaint, :untrust, :untrusted?, :upto, :zero?, :|, :~]

Page 90: Ruby 101

var method = 'first_name'eval('person.' + method)

Page 91: Ruby 101

var method = 'first_name'eval('person.' + method)

method = 'first_name'person.send(method)

Page 92: Ruby 101

2 + 2

Page 93: Ruby 101

2 + 2

2.+(2)

Page 94: Ruby 101

2 + 2

2.+(2)

2.send('+',2)

Page 95: Ruby 101

Syntactic Sugar

Page 96: Ruby 101

2 == 2

Page 97: Ruby 101

2 == 2

2.==(2)

Page 98: Ruby 101

2 == 2

2.==(2)

2.send('==',2)

Page 99: Ruby 101

Ruby removes the cruft

Page 100: Ruby 101

car = Vehicle.new('honda', 'civic', { :interior => 'beige' })

car = Vehicle.new 'honda', 'civic', :interior => 'beige'

Page 101: Ruby 101

Beautiful code

Page 102: Ruby 101

class Person attr_accessor 'gender','eyes','chin','name' def initialize(gender,eyes,chin) @gender = gender @eyes = eyes @chin = chin endend

Page 103: Ruby 101

class Person attr_accessor 'gender','eyes','chin','name' def initialize(gender,eyes,chin) @gender = gender @eyes = eyes @chin = chin endend

rob = Person.new 'male','blue','square'

Page 104: Ruby 101

class Person attr_accessor 'gender','eyes','chin','name' def initialize(gender,eyes,chin) @gender = gender @eyes = eyes @chin = chin endend

rob = Person.new 'male','blue','square'aimee = Person.new 'female','brown','cleft'

Page 105: Ruby 101

class Person attr_accessor 'gender','eyes','chin','name' def initialize(gender,eyes,chin) @gender = gender @eyes = eyes @chin = chin endend

rob = Person.new 'male','blue','square'aimee = Person.new 'female','brown','cleft'

Page 106: Ruby 101

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

Page 107: Ruby 101

baby = rob + aimee

Page 108: Ruby 101

baby = rob + aimeebaby.name = 'Jack'

Page 109: Ruby 101
Page 110: Ruby 101

baby = rob + aimeebaby.name = 'Jack'

baby.name=('Jack')

Page 111: Ruby 101

baby = rob + aimeebaby.name = 'Jack'

baby.name=('Jack')

baby.inspect

Page 112: Ruby 101

baby = rob + aimeebaby.name = 'Jack'

baby.name=('Jack')

baby.inspect

#<Person:0x0000010083fdf0 @gender="male", @eyes="blue", @chin="cleft", @name="Jack">

Page 113: Ruby 101

“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

Page 114: Ruby 101

return gene_pool[rand(gene_pool.size)].send feature

Page 115: Ruby 101

return gene_pool[rand(gene_pool.size)].send feature

class Array def random return self[rand(self.length)] endend

Page 116: Ruby 101

return gene_pool[rand(gene_pool.size)].send feature

class Array def random return self[rand(self.length)] endend

return gene_pool.random.send feature

Page 117: Ruby 101

unless [].respond_to? 'random' class Array def random return self[rand(self.length)] end endend

Page 118: Ruby 101

MonkeyPatching!!1!one!!!

Page 120: Ruby 101

“UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things.” — Doug Gwyn

Page 121: Ruby 101

“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

Page 122: Ruby 101

class Array def random return self[rand(self.length)] endend

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

Page 123: Ruby 101

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>();

Page 124: Ruby 101

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) {

Page 125: Ruby 101

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("/") == false) virtualDirectory = virtualDirectory + "/"; listener.Prefixes.Add("http://" + (DefaultConfiguration.HostName ?? "+") + ":" + DefaultConfiguration.Port + virtualDirectory);

Page 126: Ruby 101

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("/admin",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("Cannot understand access mode: " + DefaultConfiguration.AnonymousUserAccessMode); } databasesCleanupTimer = new Timer(CleanupDatabases, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); listener.Start(); listener.BeginGetContext(GetContext, null); }

Page 127: Ruby 101

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; }

Page 128: Ruby 101

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("Error on request", e); } finally { try { FinalizeRequestProcessing(ctx, sw, ravenUiRequest); } catch (Exception e) { logger.ErrorException("Could not finalize request properly", e); }

Page 129: Ruby 101

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("Could not gather information to log request stats",

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.

Page 130: Ruby 101

if (logHttpRequestStatsParams.Headers["Raven-Timer-Request"] == "true" && logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds <= 25) return; var curReq = Interlocked.Increment(ref reqNum); logger.Debug("Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}",

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("Failed to properly handle error, further error handling is ignored", e); } } protected abstract bool TryHandleException(IHttpContext ctx, Exception exception);

Page 131: Ruby 101

private static void HandleTooBusyError(IHttpContext ctx) { ctx.Response.StatusCode = 503; ctx.Response.StatusDescription = "Service Unavailable"; SerializeError(ctx, new { Url = ctx.Request.RawUrl, Error = "The server is too busy, could not acquire transactional access" }); } private static void HandleGenericException(IHttpContext ctx, Exception e) { ctx.Response.StatusCode = 500; ctx.Response.StatusDescription = "Internal Server Error"; 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 }); }

Page 132: Ruby 101

private static void HandleConcurrencyException(IHttpContext ctx, ConcurrencyException e) { ctx.Response.StatusCode = 409; ctx.Response.StatusDescription = "Conflict"; 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);

Page 133: Ruby 101

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 == "HEAD") return false; ctx.Write( @"<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>"); } finally { CurrentOperationContext.Headers.Value = new NameValueCollection(); currentDatabase.Value = DefaultResourceStore; currentConfiguration.Value = DefaultConfiguration; } return false; } protected virtual void OnDispatchingRequest(IHttpContext ctx){}

Page 134: Ruby 101

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 != "/"){ 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("Could not find a database named: " + tenantId); } } }

Page 135: Ruby 101

protected abstract bool TryGetOrCreateResourceStore(string name, out IResourceStore database); private void AddAccessControlAllowOriginHeader(IHttpContext ctx) { if (string.IsNullOrEmpty(DefaultConfiguration.AccessControlAllowOrigin)) return; ctx.Response.AddHeader("Access-Control-Allow-Origin", DefaultConfiguration.AccessControlAllowOrigin); } private static void AddHttpCompressionIfClientCanAcceptIt(IHttpContext ctx) { var acceptEncoding = ctx.Request.Headers["Accept-Encoding"]; 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("gzip", StringComparison.InvariantCultureIgnoreCase) != -1)) { ctx.SetResponseFilter(s => new GZipStream(s, CompressionMode.Compress, true)); ctx.Response.AddHeader("Content-Encoding","gzip"); } else if (acceptEncoding.IndexOf("deflate", StringComparison.InvariantCultureIgnoreCase) != -1) { ctx.SetResponseFilter(s => new DeflateStream(s, CompressionMode.Compress, true)); ctx.Response.AddHeader("Content-Encoding", "deflate"); } } private bool AssertSecurityRights(IHttpContext ctx) { if (DefaultConfiguration.AnonymousUserAccessMode == AnonymousUserAccessMode.None && IsInvalidUser(ctx)) {ctx.SetStatusToUnauthorized(); return false; }

Page 136: Ruby 101

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 == "GET" || httpMethod == "HEAD"); } 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

Page 137: Ruby 101

webserver = TCPServer.new('127.0.0.1', 3000)while (session = webserver.accept) session.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n" 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.closeend

Page 138: Ruby 101

“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

Page 139: Ruby 101

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

Page 140: Ruby 101

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

Page 141: Ruby 101

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

Page 142: Ruby 101

Implicit return

Any statement in Ruby returns the value of the

last evaluated expression

Page 143: Ruby 101

ruby-1.9.2 :001 > puts 'Hello, world!'

Page 144: Ruby 101

ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 >

Page 145: Ruby 101

ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 > puts('Hello, world!')

Page 146: Ruby 101

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 >

Page 147: Ruby 101

Blabber

Talk to your servers via IM

Page 148: Ruby 101
Page 149: Ruby 101

gems

Page 150: Ruby 101

rob$

Page 151: Ruby 101

rob$ gem install rails

Page 152: Ruby 101

rob$ gem install railsrob$ gem install httparty json

Page 153: Ruby 101

require 'rubygems'require 'json'require 'httparty'

Page 154: Ruby 101

rob$ irbruby-1.9.2 :001 >

Page 155: Ruby 101

rob$ irbruby-1.9.2 :001 > HTTParty

Page 156: Ruby 101

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 >

Page 157: Ruby 101

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'

Page 158: Ruby 101

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 >

Page 159: Ruby 101

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

Page 160: Ruby 101

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 >

Page 161: Ruby 101

Questions?

Page 162: Ruby 101

Workshop

Page 163: Ruby 101

Command line interface to the Active.com Search

API

Page 164: Ruby 101

It should:

Page 165: Ruby 101

It should:

• Present a list of channels and let the user select one

Page 166: Ruby 101

It should:

• Present a list of channels and let the user select one

• Prompt for (optional) keywords

Page 167: Ruby 101

It should:

• Present a list of channels and let the user select one

• Prompt for (optional) keywords• Present the top 10 results

Page 168: Ruby 101

It should:

• Present a list of channels and let the user select one

• Prompt for (optional) keywords• Present the top 10 results• Let the user select one result

Page 169: Ruby 101

It should:

• Present a list of channels and let the user select one

• Prompt for (optional) keywords• Present the top 10 results• Let the user select one result • Present the title, location, start

date and asset ID of the selected event

Page 170: Ruby 101

Example

Page 171: Ruby 101

What you need to know

Page 172: Ruby 101

Required Gems

require 'json'require 'httparty'

Page 176: Ruby 101

Get user inputuser_input = gets

Page 177: Ruby 101

Get user inputuser_input = gets

Remove newlinesuser_input.chomp

Page 178: Ruby 101

Get user inputuser_input = gets

Print to STDOUTprint 'text'puts 'text'

Remove newlinesuser_input.chomp

Page 179: Ruby 101

Iterate through array with index

my_array.each_with_index do |item,i| puts “#{item} is at position #{i}”end

Page 180: Ruby 101

Exitexit 0

Iterate through array with index

my_array.each_with_index do |item,i| puts “#{item} is at position #{i}”end

Page 181: Ruby 101

Define methodsdef method_name(first, second) # codeend

Create classes

class ClassName def initialize # code endend

Page 182: Ruby 101

Questions?

Page 184: Ruby 101

“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

Page 185: Ruby 101

Learning a new language

Page 186: Ruby 101
Page 187: Ruby 101
Page 188: Ruby 101

EGO

Page 189: Ruby 101

“Would you rather be a king of fools or a

student of masters?”

Page 190: Ruby 101

The End