• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Ruby 101
 

Ruby 101

on

  • 7,042 views

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

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

Statistics

Views

Total Views
7,042
Views on SlideShare
1,552
Embed Views
5,490

Actions

Likes
0
Downloads
10
Comments
0

5 Embeds 5,490

http://community.active.com 5484
http://webcache.googleusercontent.com 2
http://meltwaternews.com 2
http://www.hanrss.com 1
http://172.19.16.12 1

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Ruby 101 Ruby 101 Presentation Transcript

    • Ruby 101
    • Your favorite language sucks. language sucks.
    • Ruby is the greatest language ever made.
    • Ruby is the greatest language ever made. And if you disagree, you’re wrong.
    • February 24, 1993
    • Yukihiro “Matz” Matsumoto まつもとゆきひろ
    • 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.”
    • 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.”
    • 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.”
    • for ( var i = 0 ; i < 3 ; i ++ ) { alert ( 'Hello, world!' ); }
    • for ( var i = 0 ; i < 3 ; i ++ ) { alert ( 'Hello, world!' ); } 3 .times do puts 'Hello, world!' end
    • var people = [ 'Rob' , 'Eugene' , 'Crystal' ]; for ( var i = 0 ; i < people. length ; i ++ ) { alert (people[i] + ' loves Ruby' ); }
    • 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
    • var today = new Date (); today. setDate (today. getDate () + 2 );
    • var today = new Date (); today. setDate (today. getDate () + 2 ); 2 .days.from_now
    • 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.”
    • REPL
    • REPL Read - Eval - Print - Loop
    • REPL Read - Eval - Print - Loop irb
    • REPL Read - Eval - Print - Loop irb interactive ruby
    • rob$
    • rob$ irb
    • rob$ irbruby-1.9.2 :001 >
    • rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal']
    • rob$ irbruby-1.9.2 :001 > people = ['Rob','Eugene','Crystal'] => [&quot;Rob&quot;, &quot;Eugene&quot;, &quot;Crystal&quot;] ruby-1.9.2 :002 >
    • 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
    • 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 >
    • 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
    • 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 >
    • 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
    • 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 >
    • The Basics
    • count = 42
    • count = 42 amount = 23.83
    • count = 42 amount = 23.83 language = 'Ruby'
    • count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot;
    • count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ]
    • count = 42 amount = 23.83 language = 'Ruby' text = &quot;#{language} is the best!&quot; people = [ 'Rob' , 'Eugene' , 'Crystal' ] person = { :name => 'Rob' , :gender => 'male' }
    • 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
    • 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
    • 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
    • [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end
    • [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end Iterators
    • [ 'Rob' , 'Eugene' , 'Crystal' ].each do | name | puts &quot;#{name} loves Ruby&quot; end Iterators each find collect each_with_index reject inject
    • $ ( 'li' ).each( function (index) { alert ( 'index=' + index); });
    • $ ( 'li' ).each( function (index) { alert ( 'index=' + index); }); an_array.each do | item | puts &quot;item=#{item}&quot; end
    • Loops?
    • Conditionals
    • if person.has_red_hair? Sun .burn person end
    • if person.has_red_hair? Sun .burn person end unless car.sugar_in_gas_tank? car.start end
    • 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?
    • 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?
    • if just_worked_out and date_tonight take_a_shower end
    • if just_worked_out and date_tonight take_a_shower end if love_mom or just_drunk get_a_tattoo end
    • 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
    • !
    • airlines = [ 'Southwest' , 'United' , 'Delta' ]
    • airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ]
    • airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ]
    • airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse! => [ 'Delta' , 'United' , 'Southwest' ]
    • airlines = [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Southwest' , 'United' , 'Delta' ] airlines.reverse! => [ 'Delta' , 'United' , 'Southwest' ] puts airlines => [ 'Delta' , 'United' , 'Southwest' ]
    • everything is an object
    • ‘ Rob’.class
    • ‘ Rob’.class => String
    • ‘ Rob’.class => String 42.class
    • ‘ Rob’.class => String 42.class => Fixnum
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class
    • ‘ Rob’.class => String 42.class => Fixnum (23.45).class => Float true.class => TrueClass nil.class => NilClass String.class => Class Class.class => Class Class.superclass
    • ‘ 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
    • ‘ 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
    • ‘ 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
    • ‘ 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
    • ‘ 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
    • ‘ 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
    • ‘ 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
    • 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
    • Introspection
    • 42.methods
    • 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?, :|, :~]
    • 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?, :|, :~]
    • var method = 'first_name' eval ( 'person.' + method)
    • var method = 'first_name' eval ( 'person.' + method) method = 'first_name' person.send(method)
    • 2 + 2
    • 2 + 2 2.+(2)
    • 2 + 2 2.+(2) 2.send('+',2)
    • Syntactic Sugar
    • 2 == 2
    • 2 == 2 2.==(2)
    • 2 == 2 2.==(2) 2.send('==',2)
    • Ruby removes the cruft
    • car = Vehicle . new ( 'honda' , 'civic' , { :interior => 'beige' }) car = Vehicle . new 'honda' , 'civic' , :interior => 'beige'
    • Beautiful code
    • class Person attr_accessor 'gender' , 'eyes' , 'chin' , 'name' def initialize ( gender,eyes,chin ) @gender = gender @eyes = eyes @chin = chin end end
    • 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'
    • 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'
    • 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'
    • 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
    • baby = rob + aimee
    • baby = rob + aimee baby.name = 'Jack'
    •  
    • baby = rob + aimee baby.name = 'Jack' baby.name=( 'Jack' )
    • baby = rob + aimee baby.name = 'Jack' baby.name=( 'Jack' ) baby.inspect
    • 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;>
    • “ 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
    • return gene_pool[rand(gene_pool.size)].send feature
    • return gene_pool[rand(gene_pool.size)].send feature class Array def random return self [rand( self .length)] end end
    • 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
    • unless []. respond_to ? 'random' class Array def random return self [rand( self .length)] end end end
    • Monkey Patching!!1!one!!!
    • David Heinemeier Hansson (DHH) “ Why Ruby” http://confreaks.net/system/assets/datas/694/original/431-rubyconf2010-keynote-why-ruby-small.mp4?1291226733
    • “ UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things.” — Doug Gwyn
    • “ 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
    • 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
    • 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>();
    • 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) {
    • 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);
    • 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); }
    • 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; }
    • 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); }
    • 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.
    • 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);
    • 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 }); }
    • 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);
    • 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){}
    • 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); } } }
    • 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; }
    • 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
    • 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
    • “ 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
    • 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
    • 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
    • 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
    • Implicit return Any statement in Ruby returns the value of the last evaluated expression
    • ruby-1.9.2 :001 > puts 'Hello, world!'
    • ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 >
    • ruby-1.9.2 :001 > puts 'Hello, world!'Hello, world! => nil ruby-1.9.2 :002 > puts('Hello, world!')
    • 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 >
    • Blabber Talk to your servers via IM
    •  
    • gems
    • rob$
    • rob$ gem install rails
    • rob$ gem install rails rob$ gem install httparty json
    • require 'rubygems' require 'json' require 'httparty'
    • rob$ irbruby-1.9.2 :001 >
    • rob$ irbruby-1.9.2 :001 > HTTParty
    • 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 >
    • 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'
    • 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 >
    • 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
    • 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 >
    • Questions?
    • Workshop
    • Command line interface to the Active.com Search API
    • It should:
      • It should:
        • Present a list of channels and let the user select one
      • It should:
        • Present a list of channels and let the user select one
        • Prompt for (optional) keywords
      • It should:
        • Present a list of channels and let the user select one
        • Prompt for (optional) keywords
        • Present the top 10 results
      • 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
      • 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
    • Example
    • What you need to know
    • Required Gems require 'json' require 'httparty'
    • Search API Endpoint http://api.amp.active.com/search? v=json& k=keywords& m=meta:channel%3DRunning& api_key=wuhmn9ye94xn3xnteudxsavw
    • HTTP call HTTParty.get(url)
    • Parse JSON JSON.parse(text) HTTP call HTTParty.get(url)
    • Get user input user_input = gets
    • Get user input user_input = gets Remove newlines user_input.chomp
    • Get user input user_input = gets Print to STDOUT print 'text'puts 'text' Remove newlines user_input.chomp
    • Iterate through array with index my_array.each_with_index do |item,i| puts “#{item} is at position #{i}” end
    • Exit exit 0 Iterate through array with index my_array.each_with_index do |item,i| puts “#{item} is at position #{i}” end
    • Define methods
      • def method_name(first, second)
          • # code
          • end
      Create classes
      • class ClassName
          • def initialize
          • # code
          • end
          • end
    • Questions?
    • 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
    • “ 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
    • Learning a new language
    •  
    •  
    • EGO
    • “ Would you rather be a king of fools or a student of masters?”
    • The End