ROEL voor RoR: Gewoon Ruby voor je HTML

Door Gamebuster op vrijdag 27 september 2013 01:40 - Reacties (4)
Categorie: if(post.relatedTo("programming")), Views: 2.630

In mijn eerdere blogpost besprak ik het idee om in plaats van HAML of ERB een plain-ruby syntax te gebruiken. In mijn welbekende naÔviteit dacht ik dat de implementatie met wat method-missings wel zou lukken.

Er zat echter 1 fatal flaw in mijn implementatie-idee: In combinatie met bestaande helpers zou dat nooit goed werken, aangezien die ontworpen zijn om een string te return'en. Zo zou bijv. de volgende code een ongewenst resultaat geven:


Ruby:
1
2
3
4
div {
  content_tag :foo
  bar
}



Het verwachte en gewenste resultaat is hier:

HTML:
1
2
3
4
<div>
  <foo></foo>
  <bar></bar>
</div>



... maar in de realiteit zou de foo-tag nooit meegenomen worden, omdat alleen de return-value van de laatste method in het block meegenomen kan worden. Dit is op te lossen door overal een +je tussen te plaatsen, maar dit heeft een sterk negatieve impact op het gemak van de syntax.

Ik heb daarom in de huidige implementatie ervoor gekozen om met een Ruby parser de templates te "hercompilen" naar de gewenste functionaliteit, met name door overal +jes tussen te plaatsen. Dit maakt het dan ook mogelijk om bijv. dit te doen:


Ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"<!DOCTYPE html>"
html lang: I18n.current_locale do
    head do
        title @title
        meta charset: "utf-8"
        stylesheet_link_tag "application"
        javascript_include_tag "application"
    end
    body id: "#{params[:controller]}_#{params[:action]}".gsub(/^[a-z0-9_]+/, "-") do
        render "head"
        div class: "container", &content
        render "foot"
    end
end



Het resultaat van mijn huidige "hercompiler" is:


Ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"<!DOCTYPE html>" +
html({ :lang => I18n.current_locale }){
  head{
    title(@title) +
    meta({ :charset => "utf-8" }) +
    stylesheet_link_tag("application") +
    javascript_include_tag("application")
  } +
  body({ :id => (params.[](:controller).to_s+"_"+params.[](:action).to_s).gsub(/^[a-z0-9_]+/, "-") }){
    render("head") +
    div({ :class => "container" }, &content) +
    render("foot")
  }
}



Ik heb de resulterende code nog niet getest omdat ik nog geen "enviroment" met de gewenste method-missings heb om deze uit te voeren. De code lijkt er zover al wel goed uit te zien: De resulterende code wordt gegenereerd door het parser-resultaat in te lezen en om te zetten in Ruby.

In de toekomst zou dit misschien als Gem in een RoR project gezet worden. Deze zal automagisch iedere template eenmalig compilen als een class, welke dan aangeroepen wordt met de huidige context om de pagina te renderen.

Bron van mijn huidige "compiler": http://pastebin.com/hs6tJYM0
Ik ben me ervan bewust dat mijn compiler vast nog bomvol bugs zit: Ik heb deze vlugjes geschreven om mijn idee werkend te krijgen.

Videobewerking

Door Gamebuster op donderdag 26 september 2013 14:58 - Reacties (4)
Categorie: funvids, Views: 1.893



Music by Bonobo.
YT: http://www.youtube.com/user/BonoboVids
iTunes: https://itunes.apple.com/nl/artist/bonobo/id416281071
WWW: http://bonobomusic.com/

Video by Cyriak:
YT: http://www.youtube.com/user/cyriak
WWW: http://www.cyriak.co.uk/

Mijn oudere post over Cyriak: /b/: Drugs + Adobe After Effects.

RoR: HAML of ERB? Waarom niet gewoon plain ruby?

Door Gamebuster op donderdag 26 september 2013 13:22 - Reacties (6)
Categorie: if(post.relatedTo("programming")), Views: 1.623

Ruby is leuk, maar in het geval met Ruby on Rails zal je uiteindelijk toch HTML moeten genereren voor je webapp. Zit je lekker te werken in Ruby, mag je opeens HTML gaan schrijven (blegh) en dit gaan combineren met inline ERB tags (dubbelblegh)

Met die gedachte is HAML/SLIM ontworpen. HAML wordt echter niet altijd even geliefd door iedereen, deels om het feit dat het op basis van significant whitespace werkt en vast nog wel meer redenen (to be honest: Ik heb het zelf nooit gebruikt)

In een brainfart dacht ik daarom: Wat is er mis met een puur Ruby oplossing om HTML te genereren; Voorbeeld van een layout: (filename zou dan bijv. layout.html.rb zijn)

Ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
html lang: I18n.current_locale {
    head {
        title @title
        meta charset: "utf-8"
        stylesheet_link_tag "application"
        javascript_include_tag "application"
    }
    body id: "#{params[:controller]}_#{params[:action]}".gsub(/^[a-z0-9_]+/, "-") {
        render "head"
        div class: "container", &content
        render "foot"
    }
}



Je kan gewoon bestaande methodes/helpers aanroepen. Via method_missing vang je calls naar niet-bestaande methodes af (body, head, html, div, enz) en roep je content_tag aan met de methodname, meegegeven args en block.

Simpel te implementeren, plain Ruby en ziet er naar mijn mening beter uit dan zowel ERB als HAML.

Een simpele tabel:

Ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
table class: "table" {
    thead {
        tr {
            th User.human_attribute_name "name"
            th User.human_attribute_name "email"
            th
        }
    }
    tbody {
        @users.each do |user|
            tr {
                td link_to(user.name, user)
                td user.email
                td link_to(user.name, user, method: "delete")
            }
        end
    }
}

git pull

Door Gamebuster op dinsdag 10 september 2013 13:18 - Reacties (8)
Categorie: if(post.relatedTo("programming")), Views: 2.956

http://i.imgur.com/VZIEked.gif

It's that time of the month again...

Cookie Clicker "AI contest" preview

Door Gamebuster op vrijdag 6 september 2013 11:18 - Reacties (23)
Categorie: quite useless, Views: 7.034

Cookie Clicker?
Zie video:


De game:
http://orteil.dashnet.org/cookieclicker/

AI Contest
Mijn idee was om een contest te houden wie de meest efficiente bot kan maken voor cookie clicker om zo snel mogelijk de Miljoen te houden. De voorwaarden hieronder zijn dat de bot maar 1 klik per frame mag doen (op de standaard fps van 30 in de game) en alleen maar acties uit te voeren die je ook als speler kan uitvoeren. (oftewel, koekje klikken, upgrades kopen of items kopen/verkopen)

Ik heb hier vlugjes een API voor gemaakt die alle "legale" data en methodes wrapt. Je kan via CCAPI.step() een methode meegeven die iedere frame wordt uitgevoerd. In de callback mag je 1 actie uitvoeren (kopen, cookie klikken, enz) en je mag wat data ophalen (prijzen van cookies e.d.)

Voorbeeld van het API en het gebruik ervan:
http://pastebin.com/dcWqDhsY

Ik wil dit verder documenteren om het wat toegankelijker te maken :) Het record van mijn bot is nu zo'n 28 minuten voor een miljoen koekjes.