Ruby & Ruby on Rails
for arkitekter
Kim Harding Christensen
Agenda
•
Intro & problemstilling
•
Introduktion til Ruby
•
DSL’er
•
Introduktion til Ruby on Rails
•
Begreber (MVC & REST)
Software udvikling er
for svært og tager al for
lang tid
.NET 3.0
Problemområde
[Distribuerede
informationssystemer]
Infosets + Objects + Tuples
=
When I work in Java, I wouldn't say I feel joy.
I don't feel like I'm riding a fast stallion through beautiful
wooded hills, the wind in my long, flowing hair.
I feel more like I'm struggling to convince a workhorse
to pull a plow.
“Java is the blunt scissors of programming.
It’s what we give to children to program”
Problemområde
Sprog
Introduktion til Ruby
(på 10 slides)
I have a lot of trouble writing about Ruby, because I find there's nothing to say. It's why I
almost never post to the O'Reilly Ruby blog. Ruby seems so self-explanatory to me. It
makes it almost boring; you try to focus on Ruby and you wind up talking about some
problem domain instead of the language. I think that's the goal of all programming
Ruby
•
Pure Object-Oriented
Language
•
Dynamisk type system
•
Simpel nedarvning +
mixins
•
Block, closures,
continuations
•
Read-eval-print
•
Meta-programmering,
•
metaklasser,
introspection, eval
•
Simpel & konsistent
syntaks
•
Regulære udtryk
•
Cross-platform
class
MyClass
@instance_var
@@class_var
def
instance_method(arg) ...
end
def
self.class_method(arg) ...
end
def
foo() # getter
@foo
end
def
foo=(value) # setter
@foo = value
end
def
state_changing_method!() ...
end
def
query_method? ...
end
class
LinkedList
class
Node
def
initialize(element)
@element = element
end
def
element()
@element
end
def
next()
@next
end
def
next=(node)
@next = node
end
end
def
add(element)
...
end
class
LinkedList
class
Node
def
initialize(element)
@element = element
end
def
element()
@element
end
def
next()
@next
end
def
next=(node)
@next = node
end
end
def
add(element)
...
end
class
Node
attr_reader :element
attr_accessor :next
def
initialize(element)
@element = element
end
end
class
LinkedList
class
Node
...
end
def
add(element)
node = Node.new(element)
if
(@first == nil)
@first = node
end
if
(@last != nil)
@last.next = node
end
@last = node
end
end
class
LinkedList
class
Node
...
end
def
add(element)
node = Node.new(element)
if
(@first == nil)
@first = node
end
if
(@last != nil)
@last.next = node
end
@last = node
end
end
class
LinkedList
class
Node
...
end
def
add(element)
node = Node.new(element)
@first = node
unless
@first
@last.next = node
if
@last
@last = node
end
end
Block & Closures
a = 7
Block & Closures
def
twice()
yield
yield
end
twice()
{ puts “Hello” }
a = 7
class
LinkedList
def
add(element)
...
end
def
each()
if
block_given?
node = @first
while
node
do
yield
node.element
node = node.next
end
end
self
end
end
> l = LinkedList.new
> [1,2,3,4,5].each {|e| l.add e}
> l.each {|e| puts e}
1
2
3
4
5
>
Nedarvning
class
Collection
def
size()
count = 0
self.each {|e| count += 1}
count
end
end
class
LinkedList < Collection
def
add(element)
...
end
def
each()
...
end
end
Moduler & Mixins
module
Enumeration
def
select()
result = Array.new
this.each {|e| result << yield(e)}
result
end
def
detect() ... end
def
reject() ... end
def
collect() ... end
...
class
Collection
include Enumeration
def
size()
count = 0
self.each {|e| count += 1}
count
end
end
class
LinkedList < Collection
def
add(element) ...
end
alias
:<< :add
def
each() ...
end
end
Metode lookup
module Kernel
module M
b = B.new
class Object
include Kernel
end
class A
include M
end
class B < A
DSL
•
Ekstern DSL
•
Intern DSL
Rake - Ruby Make
•
Rakefiler er skrevet i standard Ruby - ingen
behov for XML filer
•
Tasks med afhængigheder
•
Rule patterns
•
Rake består af en fil: 400-500 linier Ruby
kode
http://rake.rubyforge.org
file 'main.o' => ["main.c", "greet.h"]
do
sh "cc -c -o main.o main.c"
end
file 'greet.o' => ['greet.c']
do
sh "cc -c -o greet.o greet.c"
end
file "hello" => ["main.o", "greet.o"]
do
sh "cc -o hello main.o greet.o"
end
require
'rake/clean'
CLEAN.include('*.o')
CLOBBER.include('hello')
task :default => ["hello"]
SRC = FileList['*.c']
OBJ = SRC.ext('o')
rule '.o' => '.c'
do
|t|
sh "cc -c -o #{t.name} #{t.source}"
end
file "hello" => OBJ
do
sh "cc -o hello #{OBJ}"
end
# File dependencies go here ...
file 'main.o' => ['main.c', 'greet.h']
file 'greet.o' => ['greet.c']
•
“Full stack” web framework
•
MVC baseret
•
“Opinionated”
•
“Convention over configuration”
•
Open Source
Model - View - Controller
Controller
Model
View
DB
1
2
3
4
Rails MVC
Controller
Model
View
DB
Rails MVC
Controller
Model
View
DB
Routing
http://kimharding.com/kursus/index.html
Rails MVC
Controller
Model
View
DB
Routing
http://kimharding.com/kursus/index.html
KursusController.index()
Rails MVC
Controller
Model
View
DB
Routing
http://kimharding.com/kursus/index.html
KursusController.index()
@kurser = Kursus.find(:all)
Rails MVC
Controller
Model
View
DB
Routing
http://kimharding.com/kursus/index.html
KursusController.index()
@kurser = Kursus.find(:all)
index.rhtml
Rails MVC
Controller
Model
View
DB
Routing
http://kimharding.com/kursus/index.html
KursusController.index()
@kurser = Kursus.find(:all)
index.rhtml
<h1>Kurser</h1>
<% @kurser.each do |kursus| %>
<h2><%= @kursus.titel() %></h2>
ActiveRecord
“The essence of an Active Record is a Domain Model in
which the classes match very closely the record structure of
an underlying database. Each Active Record is responsible
for saving and loading to the database and also for any
domain logic that acts on the data...
The data structure of the Active Record should exactly
match that of the database: one field in the class for each
column in the table...”
Patterns of Enterprise Application Architecture
Martin Fowler
Analyse model
title
description
logo_url
Brand
title
description
image_url
ProductType
title
price
Product
*
1
*
title
Category
*
*
children
DB Design
description
id
logo_url
title
varchar(256)
varchar(512)
varchar(80)
int
BRANDS
int
product_type_id
price
id
title
number(8,2)
varchar(80)
int
PRODUCTS
int
brand_id
description
id
image_url
title
varchar(256)
varchar(512)
varchar(80)
int
PRODUCT_TYPES
product_types_id
category_id
int
int
CATEGORIES_PRODUCT_TYPES
id
title
varchar(80)
int
CATEGORIES
description
id
logo_url
title
varchar(256)
varchar(512)
varchar(80)
int
BRANDS
int
product_type_id
price
id
title
number(8,2)
varchar(80)
int
PRODUCTS
int
brand_id
description
id
image_url
title
varchar(256)
varchar(512)
varchar(80)
int
PRODUCT_TYPES
product_types_id
category_id
int
int
CATEGORIES_PRODUCT_TYPES
parent_id
int
id
title
varchar(80)
int
CATEGORIES
class
CreateBrands < ActiveRecord::Migration
def
self.up
create_table :brands
do
|t|
t.column :title, :string, :null => false
t.column :description, :text
t.column :logo_url, :string
end
end
def
self.down
drop_table :brands
end
end
class Brand < ActiveRecord::Base
has_many :product_types
end
class ProductType < ActiveRecord::Base
belongs_to :brand
end
title
description
logo_url
Brand
title
description
image_url
ProductType
title
price
Product
*
1
*
title
Category
*
*
parent
children
class ProductType < ActiveRecord::Base
belongs_to :brand
has_many :products, :dependent => true
end
class Product < ActiveRecord::Base
belongs_to :product_type
end
title
description
logo_url
Brand
title
description
image_url
ProductType
title
price
Product
*
1
*
title
Category
*
*
parent
children
class ProductType < ActiveRecord::Base
belongs_to :brand
has_many :products
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :product_types
end
title
description
logo_url
Brand
title
description
image_url
ProductType
title
price
Product
*
1
*
title
Category
*
*
parent
children
title
description
logo_url
Brand
title
description
image_url
ProductType
title
price
Product
*
1
*
title
Category
*
*
parent
children
class Category < ActiveRecord::Base
has_and_belongs_to_many :product_types
acts_as_tree :order => "title"
end
Hvad er REST?
“Representational State Transfer is intended to evoke an
image of how a well-designed Web application behaves: a
network of web pages (a virtual state-machine), where
the user progresses through an application by selecting
links (state transitions), resulting in the next page
(representing the next state of the application) being
transferred to the user and rendered for their use.”
Dr. Roy Fielding
Principper
•
Applikationstilstand og funktionalitet realiseres vha.
ressourcer
•
Enhver ressource kan adresseres vha. en URI
•
Alle ressourcer benytter samme uniforme interface
til at flytte tilstand mellem klient og ressource
•
Veldefineret sæt af operationer
•
Veldefineret sæt af content-typer
•
En protokol som er Client/Server, Stateless &
Cacheable
REST & HTTP
•
HTTP benyttes ofte som fundament for REST
•
Client/Server, Stateless & Cacheable
•
Ressourcer identificeres af URLs
•
Operationer er GET, PUT, POST, DELETE
(TRACE, OPTIONS, HEAD)
•
GET: hent ressource repræsentation
•
PUT: opdater ressource
•
POST: opret ny ressource
Eksempel
Customer
Order
Eksempel
Customer
Order
OrderLine
Product
GET: list all customers
POST: add new customers
/customers
GET: get customer details
PUT: update customer
DELETE: delete customer
/customers/{id}
Eksempel
Customer Order
OrderLine Product