The Enterprise Strikes Back

171
The Enterprise Strikes Back The Ruby Trilogy: Part III

description

Explains how to make use of ruby in java-based work environments. There are some hints at .NET equivalents along the way.This is part 3 of a trilogy of Star Wars-themed ruby talks given at Protegra's SDEC 2011 in Winnipeg, Canada.

Transcript of The Enterprise Strikes Back

Page 1: The Enterprise Strikes Back

The Enterprise Strikes BackThe Ruby Trilogy: Part III

Page 2: The Enterprise Strikes Back

The Enterprise Strikes BackThe Ruby Trilogy: Part III

Page 3: The Enterprise Strikes Back

Burke Libbey@burkelibbey

Stefan Penner@stefanpenner

Page 4: The Enterprise Strikes Back

Burke Libbey@burkelibbey

Stefan Penner@stefanpenner

Page 5: The Enterprise Strikes Back

Burke Libbey@burkelibbey

Stefan Penner@stefanpenner

Page 6: The Enterprise Strikes Back

Overview

• Ruby on the JVM (20m)

• Ruby as Glue (20m)

• Testing Java with RSpec (10m)

• Cloud City (15m)

Page 7: The Enterprise Strikes Back

Ruby Java

+ Productive- Scary

+ Not Scary- Less productive

Page 8: The Enterprise Strikes Back

Ruby in Java

+ Not Scary+ Productive

Page 10: The Enterprise Strikes Back

• Full ruby implementation on the JVM

• Access to both ruby and Java libraries

• Can be deployed to existing Java infrastructure

Page 11: The Enterprise Strikes Back

The many flavours of ruby

• MRI (and YARV)

• JRuby

• IronRuby

• MacRuby

• Rubinius

• ...and several more...

Page 12: The Enterprise Strikes Back

java.lang.System.out.println("Hello World")

Page 13: The Enterprise Strikes Back

The Magic Sauce

require 'java'(contains up to 30% midichlorians)

Page 14: The Enterprise Strikes Back

Calling Java from ruby

f = javax.swing.JFrame.newf.getContentPane.add(javax.swing.JLabel.new("Hello World"))close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf.setDefaultCloseOperation(close_operation)f.packf.setVisible(true)

Page 15: The Enterprise Strikes Back

Impedance Mismatch

f = javax.swing.JFrame.new

close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf.setDefaultCloseOperation(close_operation)f.packf.setVisible(true)

Let’s break this down.

f.getContentPane.add(javax.swing.JLabel.new("Hello World"))

Page 16: The Enterprise Strikes Back

Impedance Mismatch

f = javax.swing.JFrame.newf.getContentPane.add(javax.swing.JLabel.new("Hello World"))close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf.setDefaultCloseOperation(close_operation)f.packf.setVisible(true)

getContentPane

“Getters” and “Setters” are non-idiomatic in ruby.

snake_case is generally preferred to CamelCase

Page 17: The Enterprise Strikes Back

Impedance Mismatch

f = javax.swing.JFrame.newf. .add(javax.swing.JLabel.new("Hello World"))close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf.setDefaultCloseOperation(close_operation)f.packf.setVisible(true)

content_pane

JavaBean properties can be accessed like this:

“get” disappears, CamelCase changes to snake_case

Page 18: The Enterprise Strikes Back

Impedance Mismatch

f = javax.swing.JFrame.newf. .add(javax.swing.JLabel.new("Hello World"))close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf. close_operationf.packf. true

content_pane

default_close_operation =

visible =

“set” is replaced by “=”

“setDefaultCloseOperation(x)”becomes

“default_close_operation = x”

Page 19: The Enterprise Strikes Back

Ugliness Abounds

f = javax.swing.JFrame.newf.content_pane.add(javax.swing.JLabel.new("Hello World"))close_operation = javax.swing.JFrame::EXIT_ON_CLOSEf.default_close_operation = close_operationf.packf.visible = true

Namespaces everywhere!

javax.swing. javax.swing. javax.swing.

Page 20: The Enterprise Strikes Back

Ugliness Abounds

f = JFrame.newf.content_pane.add(JLabel.new("Hello World"))close_operation = JFrame::EXIT_ON_CLOSEf.default_close_operation = close_operationf.packf.visible = true

java_import adds classes to a ruby context

java_import 'javax.swing.JFrame'java_import 'javax.swing.JLabel' JFrame.new JLabel.new JFrame::EXIT_ON_CLOSE

Page 21: The Enterprise Strikes Back

100% Rubified™

java_import 'javax.swing.JFrame'java_import 'javax.swing.JLabel'

JFrame.new.tap do |f| f.content_pane.add JLabel.new("Hello World") f.default_close_operation = JFrame::EXIT_ON_CLOSE f.pack f.visible = trueend

Page 22: The Enterprise Strikes Back

Method Rubification™

• In general, CamelCase Java methods can optionally be transliterated to snake case.

Page 23: The Enterprise Strikes Back

Uniform Access PrincipleAll services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.

- Bertrand Meyer

Page 24: The Enterprise Strikes Back

Two Rules

• Everything's an Object• Objects expose Methods and Only Methods

Page 25: The Enterprise Strikes Back
Page 26: The Enterprise Strikes Back

Method Rubification™

Java

RubySystem.currentTimeMillis()

System.current_time_millis

Page 27: The Enterprise Strikes Back

Method Rubification™

Java

Rubyperson.getName()

person.name

Seriously though, not actually trademarked.

Page 28: The Enterprise Strikes Back

Method Rubification™

Java

Rubyperson.setAge(42)

person.age = 42

Someone shouldget on that.

Page 29: The Enterprise Strikes Back

Method Rubification™

Java person.isJedi()

person.jedi?Ruby

FALSE! TRUE!

Page 30: The Enterprise Strikes Back

Is ruby an acceptable Java?

• Most Java code can literally be written as ruby with few high-level changes.

• A more relaxed type system and syntax often has productivity benefits.

(http://bit.ly/pfNluA)

Page 31: The Enterprise Strikes Back

Exhibit A// interfaces = HashMap{ label => NetworkInterface }Collection c = interfaces.values();Iterator itr = c.iterator();

while(itr.hasNext()) { NetworkInterface interface = itr.next(); if (interface.isLoopback()) { return interface.getDisplayName(); }}

# interfaces = {label => NetworkInterface}interfaces.values.find(&:loopback?).display_name

VS.

Java

Ruby

Page 32: The Enterprise Strikes Back

Exhibit A// interfaces = HashMap{ label => NetworkInterface }Collection c = interfaces.values();Iterator itr = c.iterator();

while(itr.hasNext()) { NetworkInterface interface = itr.next(); if (interface.isLoopback()) { return interface.getDisplayName(); }}

# interfaces = {label => NetworkInterface}interfaces.values.find(&:loopback?).display_name

VS.

Java

Ruby 1 2 3 4 5 6 7

Only 7 characters of syntactic support!

Page 33: The Enterprise Strikes Back

“Are you suggesting I write all my Java in ruby?!”

• Not really...

• JRuby is much slower than Java (doesn’t matter as often as you’d think)

• Ruby’s added expressiveness makes it easier to shoot yourself in the foot.(or, in fact, to lazily clone an infinite number of your feet every planck length between your gun and your target)

Page 34: The Enterprise Strikes Back

• ...but maybe sometimes.

• One possibility:

• Encode high-level logic in expressive and concise ruby code

• Supporting code in fast, safe Java

• Mix and match as appropriate

“Are you suggesting I write all my Java in ruby?!”

Page 35: The Enterprise Strikes Back

Ruby as Glue

• Ruby is great for:

• wiring existing codebases together

• other miscellaneous tasks

Page 36: The Enterprise Strikes Back

PerlThe original

“Swiss Army Knife”

Page 37: The Enterprise Strikes Back

Perl• “glue”

• “duct tape”

• “swiss army knife”

Pretty much mean the same thing.

Page 38: The Enterprise Strikes Back

Perl Ruby

Page 39: The Enterprise Strikes Back

Subcategories of “Glue”

• Wiring stuff together

• Sysadmin tasks

Page 40: The Enterprise Strikes Back

Wiring stuff together

• There’s a lot we could cover here, but:

Page 41: The Enterprise Strikes Back

Nokogiri

• An extremely user-friendly XML library

• fast! (wraps libxml2)

Page 42: The Enterprise Strikes Back

Nokogiri

require 'open-uri'require 'nokogiri'html = open("http://slashdot.org").readdoc = Nokogiri::XML(html)(doc/".story a").each do |link| puts "#{link.text} (#{link.attr('href')})"end

# Britain's Broadband Censors: a Bunch of Students (//yro.slashdot...# ...

Page 43: The Enterprise Strikes Back

Don’t do this.

(Nokogiri::XML(open("http://slashdot.org").read)/".story a").each{|a|puts "#{a.text} (#{a.attr("href")})"}

Page 44: The Enterprise Strikes Back

Sysadmin with Ruby

• Nice system APIs(quite similar to perl’s)

• System provisioning libraries/DSLs

Page 45: The Enterprise Strikes Back

Provisioning systems

• Puppet

• Chef

• Vagrant

Page 46: The Enterprise Strikes Back

Puppet

• Describe system, and puppet sets it up

• Nontrivial, but the general idea is:

• I want mysql

• I want nginx < 0.8

• I want this cron job: “....”

• Go.

http://puppetlabs.com/

Page 47: The Enterprise Strikes Back

Puppetclass postgres-server { package { postgresql-server: ensure => latest } group { postgres: gid => 26 } user { postgres: comment => "PostgreSQL Server", uid => 26, gid => 26, home => "/var/lib/pgsql", shell => "/bin/bash" } service { postgresql: running => true, pattern => "/usr/bin/postmaster", require => package["postgresql-server"] }}

Page 48: The Enterprise Strikes Back

Puppet

• Fantastic for defining a reproducible production environment

Page 49: The Enterprise Strikes Back

Chef

• Same idea as puppet

• Somewhat less powerful

• Slightly more approachable to most ruby developers

http://www.opscode.com/chef/

Page 50: The Enterprise Strikes Back

Chefpackage "sudo" do action :upgradeend

template "/etc/sudoers" do source "sudoers.erb" mode 0440 owner "root" group "root" variables( :sudoers_groups => node['authorization']['sudo']['groups'], :sudoers_users => node['authorization']['sudo']['users'], :passwordless => node['authorization']['sudo']['passwordless'] )end

Page 51: The Enterprise Strikes Back

Puppet Chef

Configuration Language custom ruby

Targeted at production production

“Powerfulness” Lots Mostly lots

Verdict Good Different

Written in ruby ruby

Page 52: The Enterprise Strikes Back

Vagrant

• Uses puppet and/or chef

• End product is a virtual machine for development use

• Consistent system for all developers, per project

Page 53: The Enterprise Strikes Back

Vagrant

• If you use puppet or chef, vagrant lets you test production locally

Page 54: The Enterprise Strikes Back

Suggestions

• As a non-ruby-dev:

• Use puppet

• Consider vagrant

Page 55: The Enterprise Strikes Back

Suggestions

• As a ruby developer:

• Consider chef and puppet, use whichever suits your taste and needs

• Consider vagrant

Page 56: The Enterprise Strikes Back

Databases

Page 57: The Enterprise Strikes Back

In the Real World,

Page 58: The Enterprise Strikes Back

In the Real World,

We have Data

Page 59: The Enterprise Strikes Back

In the Real World,

We have Data

Which lives in Databases

Page 60: The Enterprise Strikes Back

Databases Are Always simple

Page 61: The Enterprise Strikes Back

All our data is

ALWAYS in the same DBMS

Page 62: The Enterprise Strikes Back

Reality Check

Page 63: The Enterprise Strikes Back

LuckilyWe have

ODBC + JDBC

Page 64: The Enterprise Strikes Back

LuckilyWe have

ODBC + JDBC

+Ruby

Page 65: The Enterprise Strikes Back

Ruby Gives you Options

• Active Record

• Sequel

• DataMapper

• more

Page 66: The Enterprise Strikes Back

Active RecordDesign pattern coined by Martin Fowler in “Patterns of enterprise application architecture”.

Also, Ruby on Rails’s default ORM.

https://github.com/rails/rails/tree/master/activerecord

• Lots of Power• Lots of Opinion• Might fight with you (for non-standard uses)

Page 67: The Enterprise Strikes Back

Active Record Syntax (Raw)

require 'active_record'

ActiveRecord::Base.establish_connection({ :adapter => 'mysql', :database => 'test_database', :username => 'tester', :password => 'test22'})

connection = ActiveRecord::Base.connection

connection.tables> ['users', 'products', 'ducks', 'oranges']

users = [] connection.execute('SELECT * FROM users').each_hash do |user| users << userend

users> .... array of users, each user as a hash.

users.first> { :id => 1, :username => 'stefan', :password => 'is_super_secure' }

Page 68: The Enterprise Strikes Back

require 'active_record'

ActiveRecord::Base.establish_connection({ :adapter => 'mysql', :database => 'test_database', :username => 'tester', :password => 'test22'})

# class <camel_case_singular_table_name> < ActiveRecord::Baseclass User < ActiveRecord::Base # if the table's name does not fit convention, it can be manually overridden. # table_name :users_tableend

User.first> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

User.find(2)> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

User.where(:name => 'stefan')> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

Active Record Syntax (ORM)

Page 69: The Enterprise Strikes Back

Active Record Syntax (AREL)

User.first> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

User.find(2)> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

User.where(:name => 'stefan')> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

User.where(:name => 'stefan').order('id ASC')> #<User id: 2, :name => 'stefan', :password => 'is_super_secure' >

Page 70: The Enterprise Strikes Back

SequelElegant Full featured database toolkit for ruby.

http://sequel.rubyforge.org/

Supports- ADO, Amalgalite, DataObjects, DB2, DBI, DO, Firebird, ibmdb, Informix, JDBC, MySQL, Mysql2, ODBC, OpenBase, Oracle, PostgreSQL, SQLite3, Swift, and tinytds

• Supports a ton of DBMS’s• DSL• ORM

Page 71: The Enterprise Strikes Back

Sequel Examplerequire "sequel"

# connect to an in-memory databaseDB = Sequel.sqlite

# create an items tableDB.create_table :items do primary_key :id String :name Float :priceend

# create a dataset from the items tableitems = DB[:items]

# populate the tableitems.insert(:name => 'abc', :price => rand * 100)items.insert(:name => 'def', :price => rand * 100)items.insert(:name => 'ghi', :price => rand * 100)

# print out the number of recordsputs "Item count: #{items.count}"

# print out the average priceputs "The average price is: #{items.avg(:price)}"

Page 72: The Enterprise Strikes Back

Sequel ORMrequire "sequel"

# connect to an in-memory databaseDB = Sequel.sqlite

# create an items tableDB.create_table :items do primary_key :id String :name Float :priceend

# create a dataset from the items tableclass Item < Sequel::Model(:items) # associations # validations end

# populate the tableItem.create(:name => 'abc', :price => rand * 100)Item.create(:name => 'def', :price => rand * 100)Item.create(:name => 'ghi', :price => rand * 100)

# print out the number of recordsputs "Item count: #{Item.count}"

# print out the average priceputs "The average price is: #{Item.avg(:price)}"

Page 73: The Enterprise Strikes Back

ready out of the box

Sequel ORM

+jRuby

Page 74: The Enterprise Strikes Back

apparently works?

Sequel ORM

+IRONRuby

Page 75: The Enterprise Strikes Back

Case Study (Access)

• Access (top 2 solutions)

• Solution 1 (Cross Platform)

• jRuby

• JDBC

• HXTT’s driver (www.hxtt.com)

• Sequel

• Solution 2 (Windows Only)

• Ruby

• ADO via WIN32OLE

• Sequel

Page 76: The Enterprise Strikes Back

Case Study (Access)

Page 77: The Enterprise Strikes Back

1. Download jRuby http://jruby.org/

Case Study (Access)

Page 78: The Enterprise Strikes Back

1. Download jRuby http://jruby.org/

2. Install Sequel gem install Sequel

Case Study (Access)

Page 79: The Enterprise Strikes Back

1. Download jRuby http://jruby.org/

2. Install Sequel gem install Sequel

3. Download JDBC Access Driverhttp://www.hxtt.com/access.html

Case Study (Access)

Page 80: The Enterprise Strikes Back

Case Study (Access)require 'rubygems'require 'sequel'require 'sequel/adapters/jdbc'require 'sequel/jdbc_hxtt_adapter'require '../Support/Access_JDBC40.jar'

root = File.expand_path "../../", __FILE__path_to_db = root + "/Support/AccessThemeDemo.mdb"DB = Sequel.connect("jdbc:access:////#{path_to_db}")puts DB.tables

class Notes < Sequel::Model(:Notes)end

class ThemeImages < Sequel::Model(:tbl_ThemeImages)end

class Users < Sequel::Model(:tbl_Users)end

Page 81: The Enterprise Strikes Back

ba-da-bing

Page 82: The Enterprise Strikes Back

But our new appand our old database

have different system requirements.

Page 83: The Enterprise Strikes Back

We Want Isolation

Page 84: The Enterprise Strikes Back

We Want Isolation-_Need

Page 85: The Enterprise Strikes Back

Power by.. Sinatra

used at linkedInhttp://engineering.linkedin.com/44/linkedin-app-end-end-jruby-frontier-and-voldemort

Web DSL

get '/pictures' do ['picture1','picture2','picture2']end

post '/pictures' {}put '/pictures/:id' {}delete '/pictures/:id' {}

Page 86: The Enterprise Strikes Back

sooo... big deal?

Page 87: The Enterprise Strikes Back

RestServer

• any jdbc database into a restful json service

• https://github.com/stefanpenner/restserver

Page 88: The Enterprise Strikes Back

Portability/Bundling

• Warbler

http://github.com/nicksieger/warbler

• single jar/war file

• compiled (if needed)

Page 89: The Enterprise Strikes Back

it’s an app!it’s an app!

Page 90: The Enterprise Strikes Back

Putting it all together (p1)

ScreenShotrdownload:

https://github.com/stefanpenner/screenshotr/zipball/master

[email protected]:stefanpenner/screenshotr

Page 91: The Enterprise Strikes Back

Sorry, contrived example!

Page 92: The Enterprise Strikes Back

anyways...

Page 93: The Enterprise Strikes Back

Java Gives Us• Portability

Ruby Gives Us• Happiness

Page 94: The Enterprise Strikes Back

ScreenShotr

• screen capture

• GUI

Normally Annoying re: Portability

but thx jRuby

Page 95: The Enterprise Strikes Back

Lets Shoot some Screensrequire 'java'

java_import 'java.awt.Robot'java_import 'java.awt.Toolkit'java_import 'java.awt.Rectangle'java_import 'java.awt.Image'java_import 'java.awt.image.BufferedImage'java_import 'javax.imageio.ImageIO'

screenRect = Rectangle.new(Toolkit.default_toolkit.getScreenSize())capture = Robot.new.createScreenCapture(screenRect)

ImageIO.write(capture,'jpg',java.io.File.new('some_tmp_file.jpg'))

Page 96: The Enterprise Strikes Back

Hold UP

Page 97: The Enterprise Strikes Back

Hold UPjava_import ?

Page 98: The Enterprise Strikes Back

Hold UPjava_import ?

why not require?

Page 99: The Enterprise Strikes Back

Hold UPjava_import ?

why not require?requiring classes just makes them discoverable later.

Page 100: The Enterprise Strikes Back

Hold UPjava_import ?

why not import?

why not require?requiring classes just makes them discoverable later.

Page 101: The Enterprise Strikes Back

Hold UPjava_import ?

why not import?Rake defines import

why not require?requiring classes just makes them discoverable later.

Page 102: The Enterprise Strikes Back

Hold UPjava_import ?

why not import?Rake defines import

why not require?requiring classes just makes them discoverable later.

weird...

Page 103: The Enterprise Strikes Back

And fill some clipboards

require 'java'

java_import 'java.awt.Toolkit'java_import 'javax.imageio.ImageIO'

ss = StringSelection.new(public_url) Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, nil)

Page 104: The Enterprise Strikes Back

upload to servergem install rest-client

require 'rubygems'

require 'rest-client'

RestClient.post('http://../resource', :file => File.new('path/to/file'))

Page 105: The Enterprise Strikes Back

upload to servergem install rest-client

require 'rubygems'

require 'rest-client'

RestClient.post('http://../resource', :file => File.new('path/to/file'))

Page 106: The Enterprise Strikes Back

<Insert Segue Here>

Page 107: The Enterprise Strikes Back

...and Vice Versa

• We’ve done a lot of calling Java from ruby.

• The reverse is possible as well.

Page 108: The Enterprise Strikes Back

...and Vice Versa

http://en.wikipedia.org/wiki/Jruby

import org.jruby.embed.InvokeFailedException;import org.jruby.embed.ScriptingContainer;

// ...ScriptingContainer container = new ScriptingContainer();container.runScriptlet("puts \"That's no Moon\"");

Page 109: The Enterprise Strikes Back

“i find your lack of tests disturbing.”

Testing Java with Ruby

Page 110: The Enterprise Strikes Back

Testing Java with Ruby

• JtestR is wonderful

• Includes most of ruby’s leading testing libraries

• supports ant and maven

• easy to add to a project

• takes advantage of jruby/java bridge

Page 111: The Enterprise Strikes Back

JtestR Installation

• Download jarfile from jtestr.codehaus.org

• Add to classpath

• Add a task to maven/ant

• Create tests in ./test or ./spec

• Run task

Page 112: The Enterprise Strikes Back

import java.util.HashMap

describe "An empty", HashMap do before :each do @hash_map = HashMap.new end

it "accepts new entries" do @hash_map.put "foo", "bar" @hash_map.get("foo").should == "bar" end

it "returns a keyset iterator that throws an exception on next" do proc do @hash_map.key_set.iterator.next end.should raise_error(java.util.NoSuchElementException) endend

Example!

Page 113: The Enterprise Strikes Back

“i saw a city in the clouds”

Page 114: The Enterprise Strikes Back

MYTH: Ruby can’t scale.

Page 115: The Enterprise Strikes Back

FACT: Ruby scales like a BOSS

Page 116: The Enterprise Strikes Back

FACT: Ruby scales like a BOSS(because it has to)

Page 117: The Enterprise Strikes Back

Fog

• “The Ruby Cloud Services Library”

• Lets you upload to S3, provision instances in EC2, set DNS records in DNSimple...

• ...and much more.

Page 118: The Enterprise Strikes Back

whargarblbgarblgr-garblgragh

Fog

• Chewbacca-approved.

“ ”

Page 119: The Enterprise Strikes Back

whargarblbgarblgr-garblgragh

Fog

• Chewbacca-approved. (chewbaccaproved?)

“ ”

Page 120: The Enterprise Strikes Back

2.5 imperial tons of providers

Page 121: The Enterprise Strikes Back

2.5 imperial tons of providersHeh.( )

Page 122: The Enterprise Strikes Back
Page 123: The Enterprise Strikes Back
Page 124: The Enterprise Strikes Back
Page 125: The Enterprise Strikes Back
Page 126: The Enterprise Strikes Back
Page 127: The Enterprise Strikes Back
Page 128: The Enterprise Strikes Back
Page 129: The Enterprise Strikes Back
Page 130: The Enterprise Strikes Back
Page 131: The Enterprise Strikes Back
Page 132: The Enterprise Strikes Back
Page 133: The Enterprise Strikes Back
Page 134: The Enterprise Strikes Back
Page 135: The Enterprise Strikes Back
Page 136: The Enterprise Strikes Back
Page 137: The Enterprise Strikes Back
Page 138: The Enterprise Strikes Back
Page 139: The Enterprise Strikes Back
Page 140: The Enterprise Strikes Back
Page 141: The Enterprise Strikes Back
Page 142: The Enterprise Strikes Back
Page 143: The Enterprise Strikes Back
Page 144: The Enterprise Strikes Back
Page 145: The Enterprise Strikes Back
Page 146: The Enterprise Strikes Back

Sinatra Example

#config.rurequire './lib/screen_shotr/server'run ScreenShotr::Server.new

Page 147: The Enterprise Strikes Back

require 'sinatra'require 'fog'require 'digest/sha1'

Page 148: The Enterprise Strikes Back

module ScreenShotr class Server < Sinatra::Base def storage #@storage ||= Fog::Storage.new({ # :provider => 'AWS', # :aws_access_key_id => ACCESS_KEY_ID, # :aws_secret_access_key => SECRET_ACCESS_KEY})

@storage ||= Fog::Storage.new({ :local_root => '~/fog', :provider => 'Local' })

def directory storage.directories.find("data").first or storage.directories.create(:key => 'data' ) end

# snip ....

Page 149: The Enterprise Strikes Back

get '/' do "hello, world!"end

Page 150: The Enterprise Strikes Back

post '/picture/create' do file = params[:file] data = file[:tempfile]

#super secure filename filename = file[:filename]

key = Digest::SHA1.hexdigest("super random seed"+Time.now.to_s) key << '.jpg'

file = directory.files.create( :body => data.read, :key => key ) file.public_url or "http://0.0.0.0:9292/picture/#{key}"end

Page 151: The Enterprise Strikes Back

get '/picture/:key' do file = directory.files.get(params[:key]) send_file file.send(:path)end

Page 152: The Enterprise Strikes Back

rackup

Page 153: The Enterprise Strikes Back

and...

Page 154: The Enterprise Strikes Back
Page 155: The Enterprise Strikes Back

Fog Storage: Kind of cool.

Page 156: The Enterprise Strikes Back

Fog Compute: Wicked cool.

Page 157: The Enterprise Strikes Back
Page 158: The Enterprise Strikes Back
Page 159: The Enterprise Strikes Back
Page 160: The Enterprise Strikes Back
Page 161: The Enterprise Strikes Back
Page 162: The Enterprise Strikes Back
Page 163: The Enterprise Strikes Back
Page 164: The Enterprise Strikes Back
Page 165: The Enterprise Strikes Back
Page 166: The Enterprise Strikes Back
Page 167: The Enterprise Strikes Back

Heroku

Cedar Stack (run “anything”)Classic Stack (run rack/rails)

Page 168: The Enterprise Strikes Back

Heroku

Classic Stack (run rack/rails)

$ heroku createCreated sushi.herokuapp.com | [email protected]:sushi.git

$ git push heroku master-----> Heroku receiving push-----> Rails app detected-----> Compiled slug size is 8.0MB-----> Launching... done, v1http://sushi.herokuapp.com deployed to Heroku

Page 169: The Enterprise Strikes Back

Heroku

$ cat Procfileweb: bundle exec rails server -p $PORTworker: bundle exec rake resque:work QUEUE=*urgentworker: bundle exec rake resque:work QUEUE=urgentclock: bundle exec clockwork clock.rb

$ heroku scale web=4 worker=2 urgentworker=1 clock=1Scaling processes... done

Cedar Stack (run “anything”)

Ruby, Node.js,Clojure, Java, Python, and Scala

“Officially Everything”:

Page 170: The Enterprise Strikes Back

“help me ruby... you’re my only hope!”“help me ruby...

you’re my only hope!”

Page 171: The Enterprise Strikes Back

“good... the force is strong with you.

a powerful rubyist you will become.”

Thanks!