jarorcon sp

Post on 18-May-2015

1.680 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Jarorcon company introducing Ruby on Rails

TRANSCRIPT

Mirosław WołoszynPrzemysław Kowalczyk

Jarorcon Sp. z o.o.

ul. Wałbrzyska 12

52-314 Wrocław

email: info@jarorcon.pl

www.susuh.de

Użyte technologie: Ruby on Rails, Ajax, JavaScrip, XML, MySql, Apache, Mongrel, Memcache, Ferret, GetText, RCov, Test Driven Development Serwisy zintegrowane z portalem: Jajah, Twistage, Sevenload, HiClip, Google Maps Api, Ad Sense, Octazen Invite Sender & Contact Importer

Runek usług Susuh.

www.define-finance.com

Użyte technologie: Ruby on Rails, Behaviour Driven Development (RSpec), Ajax, Javascript, XML, MySql, Apache, Mongrel, Memcache, Ferret, GetText, BackgrounDRb Serwisy zintegrowane z portalem: Sevenload

Portal dla osób działających na europejskim rynku finansów i ubezpieczeń.

www.absolventa.de

Portal pracy przeznaczony dla absolwentów.

Użyte technologie: Ruby on Rails, Behaviour Driven Development (RSpec), Ajax, Javascript, XML, MySql, Apache, Mongrel, Memcache, BackgrounDRb Serwisy zintegrowane z portalem: Amazon S3

Praca, praktyka w Jarorcon Sp. z o.o.

Wrocław - praca we Wrocławskim biurze firmy Jarorcon Sp. z o.o.

Hamburg - praca w niemieckiej firmie AKRA GmbH.

Kontakt: miroslaw.woloszyn@jarorcon.pl www.jarorcon.pl

Rubyi

Rails

Przemysław Kowalczyk

Jarorcon sp. z o.o.

O mnie

Absolwent Uniwersytetu Wr., 1999 r., kierunek: Informatyka, specjalizacja: Inżynieria Oprogramowania

Pracuję jako programista od 1997 r. Java: 6 lat,

C++: 4 lata, Ruby: prawie rok

Aplikacje WWW: prawie 7 lat

Plan prezentacji

Ruby Ruby <=> Java przykłady

Ruby on Rails wprowadzenie przykłady

ActiveRecord ActiveRecord <=> JPA przykłady

Stworzony w 1995 r. przez Yukihiro Matsumoto (a.k.a. "Matz")

“Designed for programmer productivity and fun!”

Ogólnego zastosowania

Wieloplatformowy Open source Obiektowy Elastyczny

Automatyczne zarządzanie pamięcią

Refleksja Inspiracje:

Smalltalk Perl Lisp Python

Ruby <=> Java

Kompilowany Statyczne typowanie

Wszystko jest obiektem

(oprócz typów prymitywnych, tablic, interfejsów, enumów, adnotacji) ☺

Wywoływanie metod

Interpretowany Dynamiczne typowanie

(duck-typing) Wszystko jest obiektem

(klasy, moduły)

Wysyłanie komunikatów

Ruby <=> Java Ruby > Java

Zwięzły, wyrazisty kod => szybsze tworzenie, niższe koszty utrzymania

DSL (Domain Specific Language) => myślenie pojęciami z dziedziny problemu

Otwarte klasy, metaprogramowanie => łatwość tworzenia DSL, frameworków, AOP (programowanie aspektowe)

Przyjazny dla programisty: składnia, Principle of Least Surprise

Ruby < Java Wolniejszy (ale: JRuby, wiele innych implementacji w toku)

Słabe wsparcie Unicode (tylko UTF-8, poprawione w Ruby 1.9)

Trudniejszy refactoring

Bardziej wymagający (łatwiej sobie zrobić krzywdę)

Przyjazna składnia

puts 'Hello World!'

10.times {puts 'Hello'}

array = [1, 'hi', 3.14, 1, 2, [4, 5]]

hash = {'water' => 'wet', 'fire' => 'hot'}puts hash['water']

Nawiasy opcjonalne

int też obiekt i swoje metody ma

Składnia dla tworzenia tablic

Składnia dla tworzenia tablic asocjacyjnych

Metody mogą mieć blok kodu jako parametr

Średniki opcjonalne

Przyjazna składnia

def fib n return 1 if n < 2 fib(n-1) + fib(n-2)end

n = 5

puts "#{n}-th Fibonacci number is #{fib n}"

(1..10).map {|i| i * 2}.find_all {|i| i%3 == 0}

=> [6, 12, 18]

Skrócona forma if

return zbędny na końcu metody

Interpretowane wewnątrz napisu

Tworzy obiekt klasy Range

Zwięzły kod

top5 = users. sort_by{|u| u.activity}. last(5). collect{|u| u.login}

Collections.sort(users, new Comparator<User>() {

public int compare(User u1, User u2) {

return u1.getActivity() - u2.getActivity();

}

});

List<String> top5 = new ArrayList<String>(5);

for (User user : users.subList(users.size() - 5, users.size())) {

top5.add(user.getLogin());

}

Dostępne w Rails i Ruby 1.9

top5 = users. sort_by(&:activity). last(5). collect(&:login)

Podejrzane!

Błędy!

Accidentalcomplexity!

DSL – Domain Specific Language

class User < ActiveRecord::Base

has_many :projects

belongs_to :department

validates_presence_of :name

validates_uniqueness_of :login

validate :blacklisted_login?

before_save :encrypt_password

...

Otwarte klasy

class String def blank? self.strip == '' endend

class NilClass def blank?; true; endend

"RUBY".length

"RUBY".blank?

nil.blank?

public class StringUtils { public static boolean isBlank(String str) { return str == null || str.trim().equals(""); }}

"JAVA".length();

StringUtils.isBlank("JAVA");

StringUtils.isBlank(null);

Osobna klasa!Metoda statyczna!

Brak konsekwencji!

Metaprogramowanie

xml = XmlGenerator.new

puts xml.people {

xml.person {

xml.name {"Gallagher"} +

xml.profession {"inventor"} +

xml.fictional

}

}

<people><person><name>Gallegher</name><profession>inventor</profession><fictional/></person></people>

class XmlGenerator

def method_missing m, *args

if block_given?

"<#{m}>#{yield}</#{m}>"

else

"<#{m}/>"

end

end

end

Metaprogramowanie

Person = Struct.new(:name, :phone, :email)p1 = Person.new(:name => "DHH")

#Campingclass Post < R '/post/(\d+)' def get post_id ... endend

def run_tests methods.grep /^test_/ do |m| self.send m endend

Ruby on Rails

Twórca: David Heinemeier Hansson Data opublikowania: lipiec 2004 r. Obecna wersja stabilna: 2.0.2 Stworzony przez

wydzielenie z istniejącejaplikacji (Basecamp)

Ruby on Rails – buzzwords

MVCAJAXRESTDRYConvention over Configuration

Generatory plikówplugins wsparcie dla TDD

Web development that doesn't hurt!

Optimized for programmer happiness

Does it scale?YES!

Ruby will reach 4 million programmers by 2013 (Gartner)

Ruby on Rails – enterprise ready?

amazon.com BBC CapGemini Cisco C|Net EA (Electronic Arts) IBM JP Morgan NASA Oracle

New York Times NBC Barclays LA Times Chicago Tribune Orbitz Google Turner Media Siemens Yahoo!

YES!

Convention over Configuration

MessageFoldersController(klasa kontrolera)

message_folders(tabela)

MessageFolder(klasa modelu)

app/models/message_folder.rb(plik)

MessageFolderTest(klasa testowa dla modelu)

test/unit/message_folder_test.rb(plik)

app/controllers/message_folders_controller.rb(plik)

app/views/message_folders/index.rhtmledit.rhtml

show.rhtml(widoki)

MessageFoldersControllerTest(klasa testowa dla kontrolera)

test/functional/message_folders_controller_test.rb(plik)

Ruby on Rails – model

class Campaign < ActiveRecord::Base

has_many :codes, :dependent => :destroy has_many :free_codes, :class_name => "Code", :conditions => "user_id is null" belongs_to :creator, :class_name => "User"

validates_presence_of :name, :valid_from, :valid_to, :invitations_no validates_uniqueness_of :name

def initialize *args super if @new_record valid_from ||= Time.now.tomorrow.midnight valid_to ||= 2.weeks.since(valid_from) invitations_no ||= 5 end end

def active? Time.now >= valid_from && Time.now <= valid_to endend

Operacje na czasie i datach

Nazwa klasy na podstawie nazwy relacji

Ruby on Rails – controller

class AdminCampaignsController < ApplicationController before_filter :admin_required caches_page :index, :show cache_sweeper :campaign_sweeper, :only => [:create, :update, :destroy]

def index @campaigns = Campaign.paginate :all, :page=>params[:page], :per_page=>25 end

def edit @campaign = Campaign.find(params[:id]) end

def update @campaign = Campaign.find(params[:id]) if @campaign.update_attributes(params[:campaign]) flash[:notice] = _('Campaign was successfully updated.') redirect_to admin_campaign_url(@campaign) else render :action => "edit" end end

...

Cache'owanie!

Ruby on Rails – view

<h1>New campaign</h1><%= error_messages_for :campaign %><% form_for(:campaign, :url => admin_campaigns_path) do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <p> <%= submit_tag "Create" %> </p><% end %><%= link_to 'Back', admin_campaigns_path %>

<p> <b>Name</b><br /> <%= f.text_field :name %></p>

<p> <b>Valid from</b><br /><%= f.datetime_select :valid_from %></p>

<p> <b>Valid to</b><br /> <%= f.datetime_select :valid_to %></p>

Formularz dla modelu

Wstawienie fragmentu strony

Partial '_form.rhtml'

Widok 'new.rhtml'

Ruby on Rails – test

class AdminCampaignsControllerTest < Test::Unit::TestCase

fixtures :campaigns, :campaign_codes

def test_should_get_index get :index assert_response :success assert assigns(:campaigns) end

def test_should_create_campaign assert_difference Campaign, :count, 1 do post :create, :campaign => { :name => 'test campaign' } end

assert_redirected_to admin_campaign_path(assigns(:campaign)) end

def test_shouldnt_create_campaign_without_name assert_difference Campaign, :count, 0 do post :create, :campaign => { :name => '' } end assert_not_nil assigns(:campaign).errors.on(:name) end

Fixtures – predefiniowane dane w bazie testowej

Wykonanie żądania HTTP: GET index

Blok kodu powinien zwiększyć Campaign.count o 1

Wykonanie żądania HTTP: POST create z parametrami

ActiveRecord <=> JPA

Wzorzec projektowy: ActiveRecord

Atrybuty zdefiniowane w tabeli

Relacje zdefiniowane w klasie

Mapowanie automatyczne

Finders, dynamic finders, SQL

Wzorzec projektowy: DataMapper

Atrybuty zdefiniowane w klasie

Relacje zdefiniowane w klasie lub XML

Mapowanie przez adnotacje lub XML

Criteria, HQL, SQL

ActiveRecord

find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])

find(:first, :conditions => { :user_name => user_name, :password => password })

find(:first, :conditions => params[:user])

find_by_user_name_and_password(user_name, password)

Tag.find_or_create_by_name("Summer")

user.manager.projects.find(project_id)

manager.projects.create(:name => 'new project')

Dynamic finder

Znajdź lub stwórz

User belongs_to :manager

Manager has_many :projects

Znajduje projekt, ale tylko wtedy, gdy ma go manager danego użytkownika

ActiveRecord (2)

Person.find(:all, :include => [ :account, :friends ])

Company.find(:first, :conditions => [ "id = :id AND name = :name AND division = :division AND created_at > :accounting_date", { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }]

Message.find(all, :select => "messages.*", :joins => "INNER JOIN message_folder_items mfi ON (mfi.message_id = messages.id)", :conditions => ["mfi.message_folder_id = ?", self.id], :order => 'messages.sent_at desc', :limit => 20)

Eager loading

YAML <=> XML

dates:

month names: [sty, lut, mar, kwi, ...]

day names: [Nie, Pon, Wto, Śro, ...]

date formats:

short: '%e %b'

long: '%e %B %Y'

numbers:

separator: '.'

delimiter: ','

precision: 3

<format> <dates> <month-names> <month-name>sty</month-name> <month-name>lut</month-name> <month-name>mar</month-name> <month-name>kwi</month-name> <month-name>...</month-name> </month-names> <day-names> <day-name>Nie</day-name> <day-name>Pon</day-name> <day-name>Wto</day-name> <day-name>Śro</day-name> <day-name>...</day-name> </day-names> <date-formats> <short>%e %b</short> <long>%e %B %Y</long> </date-formats> </dates> <numbers> <separator>.</separator> <delimiter>,</delimiter> <precision>3</precision> </numbers></format>

Przydatne adresy

http://www.ruby-lang.org/pl/ http://www.rubyonrails.org/ http://jarorcon.pl/ http://szeryf.wordpress.com/

Pytania?

top related