Play vs Rails

51,524 views

Published on

Comparison between Play Framework (Scala) and RubyOnRails (Ruby)

Published in: Technology
  • Hmmm.. I went back and checked the link on the performance page and I think the colors are wrong on the chart.

    I get the following chart if I run the benchmarks which indicates that Scala (and Java 7) 1-2 orders of magnitude faster than Ruby.

    Scala used what fraction? used how many times more?
    Benchmark Time Memory Code
    fannkuch-redux † 1/229 4× 3×
    mandelbrot 1/72 3× ±
    n-body 1/28 4× ±
    k-nucleotide 1/24 2× 3×
    spectral-norm 1/23 ± ±
    fasta 1/17 1/9 ±
    binary-trees 1/12 6× ±
    reverse-complement † 1/6 3× 3×
    pidigits 2× 29× 2×
    regex-dna † 3× 3× ±
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Play vs Rails

  1. RubyPlay2.0 X On Rails by @danicuki
  2. Documentationhttp://www.playframework.com/documentation/ http://guides.rubyonrails.org/
  3. Installing$ apt-get install java $  apt-­‐get  install  ruby$ wget play-2.1.0.zip $  apt-­‐get  install  rubygems$ unzip play-2.1.0.zip $  gem  install  rails$ export PATH=$PATH:/pathToPlayhttp://www.playframework.com/documentation/2.1.0/Installing
  4. First App$ play new myapp $  rails  new  myapp
  5. Project Structureapp/ app/ ! assets ! assets ! stylesheets ! stylesheets ! javascripts ! javascripts ! controllers ! controllers ! models ! helpers ! views ! mailersconf/ ! models ! application.conf ! views ! routes config/public/ ! application.rbproject ! routes.rb ! build.properties ! database.yml ! Build.scala config.ru ! plugins.sbt dblib/ GemFilelogs/ lib/target/ log/ public/ ! scala-2.10.0 script/test/ test/ tmp/ vendor/
  6. Console
  7. DependenciesMavenproject/Build.scalaval appDependencies = Seq( "postgresql" % "postgresql" % "8.4-702.jdbc4" "org.mockito" % "mockito-all" % "1.8.5" % "test")RubyGemsGemfilegem "mysql2"group :test do gem "webmock"end
  8. Dependencies Support 429.000 jars mvnrepository.com 52,468 gems rubygems.org
  9. Views TemplatesSTE (Scala Template Engine)@(title: String)(content: Html)<title> @Messages("site.title") - @title</title>@{(video "title")(0).text}ERB (Embedded Ruby)<title>    <%=  t("site.title")  %>  -­‐  <%=  yield(:title)  %></title><%=  video[title]  %>
  10. js / css<link rel="stylesheet" href="@routes.Assets.at("stylesheets/grid.css")"><link rel="stylesheet" href="@routes.Assets.at("stylesheets/style.css")"><link rel="stylesheet" href="@routes.Assets.at("stylesheets/galleriffic.css")"><script src="@routes.Assets.at("javascripts/applicaton.js")" type="text/javascript" /><script src="@routes.Assets.at("javascripts/jquery.js")" type="text/javascript" /> <%=  javascript_include_tag  :all,  :cache  =>  true  %>   <%=  stylesheet_link_tag  :all,  :cache  =>  true  %>
  11. Links<li class="menu"> <a href="@routes.Application.cantora">@Messages("site.singer")</a></li> <li  class="menu">    <%=  link_to  "#{t(site.singer)}",  {:controller  =>  "cantora"}  %> </li>
  12. RoutesGET /cantora controllers.Application.cantoraGET /musicas controllers.Application.musicGET /agenda controllers.Application.showsGET /novidades controllers.Application.newsGET /clients/:id controllers.Clients.show(id: Long)map.connect  :controller/:action/:id
  13. Controllersdef cantora = Action { implicit request =>; Ok(views.html.cantora()) }def music = Action { implicit request =>; Ok(views.html.music()) }def shows = Action { implicit request => Ok(views.html.shows()) }def news = Action { implicit request => Ok(views.html.news()) }/app/views/[method_name].scala.htmlclass  CantoraController  <  ApplicationController def  index    endendclass  NewsController  <  ApplicationController   def  index   endend/app/views/[controller_name]/index.erb.html
  14. Databasesconf/application.conf:db.default.driver=com.mysql.jdbc.Driverdb.default.url="jdbc:mysql://localhost/playdb"db.default.user=playdbuserdb.default.pass="a strong password"config/database.yml:development:    adapter:  mysql2    database:  blog_development    username:  root    password:
  15. SQL API: Databasesval countries = SQL("Select name,population from Country")().collect { case Row("France", _) => France() case Row(name:String, pop:Int) if(pop > 1000000) => BigCountry(name) case Row(name:String, _) => SmallCountry(name)}val result: Int = SQL("delete from City where id = {id}").on(“id” -> 99).executeUpdate()Active  Record:Country.all.map  do  |c|    if  (c.name  ==  “France”)        France.new    else  if  (c.pop  >  1000000) Country.delete(99)        BigCountry.new(c.name)    else        SmallCountry.new(c.name)    endend
  16. Databases OGH (Old Good Hibernate)Active  Record:Country.all.map  do  |c|    if  (c.name  ==  “France”)        France.new    else  if  (c.pop  >  1000000) Country.delete(99)        BigCountry.new(c.name)    else        SmallCountry.new(c.name)    endend
  17. Migrations / Evolutions# --- !UpsCREATE TABLE Users ( id bigint(20) NOT NULL AUTO_INCREMENT, email varchar(255) NOT NULL, password varchar(255) NOT NULL, PRIMARY KEY (id));# --- !Downs run: AUTOMATIC!DROP TABLE Users; conf/evolutions/{database name}/{#}.sqlclass  CreateUsers  <  ActiveRecord::Migration    def  up        create_table  :users  do  |t|            t.string  :email            t.string  :password            t.timestamps        end    end    def  down        drop_table  :users run:  rake  db:migrate    end db/migrate/{timestamp}_create_users.rbend
  18. Web Servicesdef videos = Action { implicit request => Async { val uri = "http://gdata.youtube.com/feed.xml" WS.url(uri).get().map { response => Ok(views.html.videos(response.xml "entry")) } }}class  VideosController  <  ApplicationController    def  index        uri  =  "http://gdata.youtube.com/feed.xml"        video_feed  =  RestClient.get(uri)        @videos  =  Hash.from_xml(video_feed)[feed][entry]    endend
  19. XMLOk(views.html.videos(response.xml "entry"))@(videos: scala.xml.NodeSeq)@videos.map { video =>    <a href="@{ ((video "group") "player")(0).attribute("url")}">       @{(video "title")(0).text}    </a>}@videos  =  Hash.from_xml(video_feed)[feed][entry]<%  @videos.each  do  |video|  %>          <a  href="<%=  video[group][player][url]  %>">                  <%=  video[title]  %>          </a><%  end  %>
  20. WS.url("https://graph.facebook.com/daniella.alcarpe/albums").get().map  {  response  =>        val  albuns  =  (response.json    "data").            as[List[JsObject]].filter(album  =>                (album    "description").toString.equals(""*""))          val  photos  =  albuns.map  {  album  =>            WS.url("https://graph.facebook.com/"  +  (album    "id").toString.replace(""",  "")  +  "/photos").get().map  {  response2  =>                (response2.json    "data").as[List[JsObject]].map  {  photo  =>                    ((photo    "images")(3)    "source").toString.replace(""",  "")                }            }        }    Ok(views.html.photos(photos)) JSON}@albuns_photos  =  {}        @albuns  =  []        albuns  =  JSON.parse(RestClient.get("https://graph.facebook.com/daniella.alcarpe/albums"))["data"]        albuns.each  do  |album|            if  (album[description]  ==  "*")                photos  =  JSON.parse(RestClient.get("https://graph.facebook.com/#{album[id]}/photos"))["data"]                albuns_photos  =  photos.map  {|p|  p["images"][3]["source"]}                album[photos]  =  albuns_photos                @albuns  <<  album            end        end
  21. Cachedef videos = Cached("videos", 18000) {  Action { ...  }}class  VideosController  <  ApplicationController        caches_action  :index,  :expires_in  =>  1.dayend
  22. Unit Tests@Test def myTest() { val array = List(1, 2, 3) assert(array(0) === 1)}test  "my  test"  do    array  =  [1,  2,  3]    assert_equal  1,  array.firstend
  23. Specsclass HelloWorldSpec extends Specification { "The Hello world string" should { "contain 11 characters" in { specs2 "Hello world" must have size(11) } "end with world" in { "Hello world" must endWith("world") autotest: } } $ ~ test}describe  "HelloWorldSpec"  do context  "The  Hello  world  string  should"  do    it  "contain 11 characters"  do rspec        "Hello  world".size.should  eq(11)    end    it  "end with world"  do        "Hello  world".should  end_with("world") $ autospec    end endend
  24. In Procfile: Deployweb: target/start -Dhttp.port=${PORT} -DapplyEvolutions.default=true -Ddb.default.url=${DATABASE_URL} -Ddb.default.driver=org.postgresql.DriverIn project/Build.scala:val appDependencies = Seq( "postgresql" % "postgresql" % "8.4-702.jdbc4")$ heroku create$ git push heroku master$  heroku  create$  git  push  heroku  master
  25. AdendoScala X Ruby by @danicuki
  26. Lambdalist.filter(_ < 100) list.select  do  |el|    el  <  100list.filter { end   el: Int => (el < 100)}
  27. TypesStatic: Dynamic:val a = new a  =  Hash.new HashMap[Int, String] a  =  “BOO!”
  28. Pattern Matching require  case def  matchTest  x  case  x  when  7def myMatch(x: Any): Any =      "seven"x match {  when  "string" case 7 => “seven”      0 case “string” => 0  when  Case::All[Integer] case y:Int => “no.” case 2 :: tail => tail      "no."}  when   Case::Array[2,Case::Any]      x[1..-­‐1]  end end
  29. Monkey Patchclass MySuperString(original: String) { def myMethod = "yess!!!"}implicit def string2super(x: String) = new MySuperString(x)println("a".myMethod) // => yess!!!class  String    def  my_method      "yess!!!"    endendputs  "a".my_method  #  =>  yess!!!
  30. Dynamic Calls class Animal extends Dynamic { def _select_(name: String) = println("Animal says " + name) def _invoke_(name: String, args: Any*) = { println("Animal wants to " + name + args.mkString(", ")) this } val animal = new Animal } animal.qualk // => Animal says qualk animal.say("hello") // => Animal wants to say helloclass  Animal    def  method_missing  name,  *args        if  args.empty?            puts  "Animal  says  "  +  name.to_s        else            puts  "Animal  wants  to  "  +  name.to_s  +    args.join(",  ")        end        self animal  =  Animal.new    end animal.qualk  #  =>  Animal  says  :  qualks  !end animal.say("hello")  #  =>  Animal  wants  to  say  hello
  31. Modules / Traitstrait PimpMyClass { def myMethod = println("myMethod")}class IncludeTrait extends PimpMyClass(new IncludeTrait).myMethodmodule  PimpMyClass    def  my_method        puts  "my_method"    endendclass  IncludeModule    include  PimpMyClassendIncludeModule.new.my_method
  32. Duck Typingclass Duck { def ActAsADuck(a: { def quack; def walk })= { def quack = ... a.quack def walk = ... a.walk }}class Platypus { val duck = new Duck def quack = ... val platypus = new Platypus def walk = ... ActAsADuck(duck)} ActAsADuck(platypus)class  Duck def  act_as_a_duck  animal    def  quack;  end    animal.quack    def  walk;  end    animal.walkend endclass  Platypus duck  =  Duck.new    def  quack;  end platypus  =  Platypus.new    def  walk;  end act_as_a_duck(duck)end act_as_a_duck(platypus)
  33. Actors
  34. Performance 80 70.74 Scala 60 JRuby Ruby 39.74 40 202.07 0 Source : http://shootout.alioth.debian.org
  35. References✦ http://www.playframework.com/documentation✦ http://guides.rubyonrails.org/✦ http://www.agileandart.com/✦ http://www.slideshare.net/El_Picador/scala-vs-ruby
  36. Obrigado!www.agileandart.com @danicuki

×