6. Overview
• Core concepts
• Ruby on the JVM (and the CLR, sort of)
• Data
• Integration
• Deployment
• Sysadmin
• The Cloud
Wednesday, 23 November, 11
7. Ruby’s weaknesses
• Poor performance
• Type system sometimes causes
headaches in large codebases
• No compiler to catch certain bugs
But your tests catch these, right?
Wednesday, 23 November, 11
8. Why ruby is slow
• Late method lookup
• Lots of context tracking to allow for eval
• Stop-the-world Mark & Sweep GC
• Runtime modification of code
Wednesday, 23 November, 11
9. Ruby’s strengths
• Developing working code quickly
• Reducing incidental complexity
Especially when best practices are adhered to
• Ease of developing powerful libraries
and succinct DSLs
Wednesday, 23 November, 11
10. Uniform Access Principle
All services o ered 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
Wednesday, 23 November, 11
11. Two Rules
• Everything is an object
• Objects expose methods and only methods
Wednesday, 23 November, 11
17. • Full ruby implementation on the JVM
• Access to both ruby and Java libraries
• Can be deployed to existing Java
infrastructure
Wednesday, 23 November, 11
18. The many flavours of ruby
• MRI (and YARV)
• JRuby
• IronRuby
• MacRuby
• Rubinius
• ...and several more...
Wednesday, 23 November, 11
23. Impedance Mismatch
“Getters” and “Setters” are non-idiomatic in ruby.
f = javax.swing.JFrame.new
f.getContentPane.add(javax.swing.JLabel.new("Hello World"))
getContentPane
close_operation = javax.swing.JFrame::EXIT_ON_CLOSE
f.setDefaultCloseOperation(close_operation)
f.pack
f.setVisible(true)
snake_case is generally preferred to CamelCase
Wednesday, 23 November, 11
24. Impedance Mismatch
JavaBean properties can be accessed like this:
f = javax.swing.JFrame.new
f.content_pane.add(javax.swing.JLabel.new("Hello World"))
close_operation = javax.swing.JFrame::EXIT_ON_CLOSE
f.setDefaultCloseOperation(close_operation)
f.pack
f.setVisible(true)
(UA P in action!)
“get” disappears, CamelCase changes to snake_case
Wednesday, 23 November, 11
34. Is ruby an acceptable
Java? (http://bit.ly/pfNluA)
• 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.
Wednesday, 23 November, 11
36. Exhibit A
// interfaces = HashMap{ label => NetworkInterface }
Java Collection c = interfaces.values();
Iterator itr = c.iterator();
while(itr.hasNext()) {
NetworkInterface interface = itr.next();
if (interface.isLoopback()) {
return interface.getDisplayName();
}
}
VS.
# interfaces = {label => NetworkInterface}
Ruby interfaces.values.find(&:loopback?).display_name
1 2 345 67
Only 7 characters of syntactic support!
Wednesday, 23 November, 11
37. “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)
Wednesday, 23 November, 11
38. “Are you suggesting I write
all my Java in ruby?!”
• ...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
Wednesday, 23 November, 11
39. Ruby as Glue
• Ruby is great for:
• wiring existing codebases together
• other miscellaneous tasks
Wednesday, 23 November, 11
40. Perl The original
“Swiss Army Knife”
Wednesday, 23 November, 11
41. Perl Pretty much mean
the same thing.
• “glue”
• “duct tape”
• “swiss army knife”
Wednesday, 23 November, 11
50. 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/
Wednesday, 23 November, 11
52. Puppet
• Fantastic for defining a reproducible
production environment
Wednesday, 23 November, 11
53. Chef
• Same idea as puppet
• Somewhat less powerful
• Slightly more approachable to most
ruby developers
http://www.opscode.com/chef/
Wednesday, 23 November, 11
54. Chef
package "sudo" do
action :upgrade
end
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
Wednesday, 23 November, 11
55. Puppet Chef
Configuration Language custom ruby
Targeted at production production
“Powerfulness” Lots Mostly lots
Verdict Good Di erent
Written in ruby ruby
Wednesday, 23 November, 11
56. Vagrant
• Uses puppet and/or chef
• End product is a virtual machine for
development use
• Consistent system for all developers, per
project
Wednesday, 23 November, 11
57. Vagrant
• If you use puppet or chef, vagrant lets
you test production locally
Wednesday, 23 November, 11
58. Suggestions
• As a non-ruby-dev:
• Use puppet
• Consider vagrant
Wednesday, 23 November, 11
59. Suggestions
• As a ruby developer:
• Consider chef and puppet, use
whichever suits your taste and needs
• Consider vagrant
Wednesday, 23 November, 11
67. Luckily
We have
ODBC + JDBC
Wednesday, 23 November, 11
68. Luckily
We have
ODBC + JDBC
+
Ruby
Wednesday, 23 November, 11
69. Ruby Gives you Options
• Active Record
• Sequel
• DataMapper
• more
Wednesday, 23 November, 11
70. Active Record
Design pattern coined by Martin Fowler in
“Patterns of enterprise application
architecture”.
Also, Ruby on Rails’s default ORM.
• Lots of Power
• Lots of Opinion
• Might fight with you (for non-standard uses)
https://github.com/rails/rails/tree/master/activerecord
Wednesday, 23 November, 11
71. 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 << user
end
users
> .... array of users, each user as a hash.
users.first
> { :id => 1, :username => 'stefan', :password => 'is_super_secure' }
Wednesday, 23 November, 11
72. Active Record Syntax (ORM)
require 'active_record'
ActiveRecord::Base.establish_connection({
:adapter => 'mysql',
:database => 'test_database',
:username => 'tester',
:password => 'test22'
})
# class <camel_case_singular_table_name> < ActiveRecord::Base
class User < ActiveRecord::Base
# if the table's name does not fit convention, it can be manually overridden.
# table_name :users_table
end
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' >
Wednesday, 23 November, 11
74. Sequel
Elegant Full featured database toolkit for ruby.
• Supports a ton of DBMS’s
• DSL
• ORM
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
Wednesday, 23 November, 11
75. require "sequel"
Sequel Example
# connect to an in-memory database
DB = Sequel.sqlite
# create an items table
DB.create_table :items do
primary_key :id
String :name
Float :price
end
# create a dataset from the items table
items = DB[:items]
# populate the table
items.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 records
puts "Item count: #{items.count}"
# print out the average price
puts "The average price is: #{items.avg(:price)}"
Wednesday, 23 November, 11
76. Sequel ORM
require "sequel"
# connect to an in-memory database
DB = Sequel.sqlite
# create an items table
DB.create_table :items do
primary_key :id
String :name
Float :price
end
# create a dataset from the items table
class Item < Sequel::Model(:items)
# associations
# validations
end
# populate the table
Item.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 records
puts "Item count: #{Item.count}"
# print out the average price
puts "The average price is: #{Item.avg(:price)}"
Wednesday, 23 November, 11
77. Sequel ORM
+
jRuby
ready out of the box
Wednesday, 23 November, 11
88. _
-Need
We Want Isolation
Wednesday, 23 November, 11
89. Power by.. Sinatra
Web DSL
get '/pictures' do
['picture1','picture2','picture2']
end
post '/pictures' {}
put '/pictures/:id' {}
delete '/pictures/:id' {}
used at linkedIn
http://engineering.linkedin.com/44/linkedin-app-end-end-jruby-frontier-and-voldemort
Wednesday, 23 November, 11
94. Putting it all together (p1)
ScreenShotr
download:
https://github.com/stefanpenner/screenshotr/zipball/master
git@github.com:stefanpenner/screenshotr
Wednesday, 23 November, 11
101. Hold UP
java_import ?
Wednesday, 23 November, 11
102. Hold UP
java_import ?
why not require?
Wednesday, 23 November, 11
103. Hold UP
java_import ?
why not require?
requiring classes just makes them discoverable later.
Wednesday, 23 November, 11
104. Hold UP
java_import ?
why not require?
requiring classes just makes them discoverable later.
why not import?
Wednesday, 23 November, 11
105. Hold UP
java_import ?
why not require?
requiring classes just makes them discoverable later.
why not import?
Rake defines import
Wednesday, 23 November, 11
106. Hold UP
java_import ?
why not require?
requiring classes just makes them discoverable later.
why not import?
Rake defines import
weird...
Wednesday, 23 November, 11
107. 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)
Wednesday, 23 November, 11
108. upload to server
gem install rest-client
require 'rubygems'
require 'rest-client'
RestClient.post('http://../resource',
:file => File.new('path/to/file'))
Wednesday, 23 November, 11
109. upload to server
gem install rest-client
require 'rubygems'
require 'rest-client'
RestClient.post('http://../resource',
:file => File.new('path/to/file'))
Wednesday, 23 November, 11
113. Testing Java with Ruby
“i find your lack of
tests disturbing.”
Wednesday, 23 November, 11
114. 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
Wednesday, 23 November, 11
115. 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
Wednesday, 23 November, 11
116. Example!
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)
end
end
Wednesday, 23 November, 11
117. BDD Any language
• Cucumber
• http://cukes.info
Wednesday, 23 November, 11
118. “i saw a city
in the clouds”
Wednesday, 23 November, 11
121. FACT: Ruby scales like a BOSS
(because it has to)
Wednesday, 23 November, 11
122. Fog
• “The Ruby Cloud Services Library”
• Lets you upload to S3, provision
instances in EC2, set DNS records in
DNSimple...
• ...and much more.
Wednesday, 23 November, 11