RubyConf 2007 First Day Afternoon

Nathaniel Talbott: Why Camping Matters

“I don’t know about you, but I am totally psyched about this conference!” Nathaniel has spoken at every RubyConf.

 bacon, egg & cheese biscuit, west egg cafe

Photo by laurafries.com

Every talk needs a metaphor, and this talk’s will be the bacon, egg, and cheese biscuit.

Bacon

The bacon is the connection to the creator, and to chunky bacon. It’s a 4k micro framework created by _why.

A whole Camping app goes in a single file and is a typical MVC.

Camping.goes :Blog

module Blog::Controllers
  class Index < R '/' # route to /
    def get
      "Hello Rubyconf!"
    end
  end
end

...
$ camping blog.rb
# blah blah, up on localhost:3301

Hooray, Hello World!. Let’s start doing more MVC:

Camping.goes :Blog

module Blog::Controllers
  class Index < R '/' # route to /
    def get
      render :index
    end
  end
  class Add < R '/add'
    render :add
  end
end

module Blog::Views
  def index
    # this is markaby
    a "add post", :href => R(Add)
  end
  def add
    form :method => :post do
      fieldset do
        label "Title: "
        input :name => :title; br
        label "Body"
        textarea :name => :body; br
      end
    end
  end
end

Camping is nice when making a sketch of the app, and eliminates all the unnecessary crap. To that extent, it’s wonderful for rapid prototyping. We’ve already got most of a Blog skeleton. Now, time for M of MVC.

Camping.goes :Blog

module Blog::Controllers
  class Index < R '/' # route to /
    def get
      render :index
    end
  end
  class Add < R '/add'
    def get
      render :add
    end
    def post
      Post.create!(@input)
      redirect Index
    end
  end
end

module Blog::Views
  def index
    # this is markaby
    a "add post", :href => R(Add)
  end
  def add
    form :method => :post do
      fieldset do
        label "Title: "
        input :name => :title; br
        label "Body"
        textarea :name => :body; br
      end
    end
  end
end  

# This is ActiveRecord under the covers, that's _not_ part of the 4k
module Blog::Models
  class Post < Base; end 

  # Migrations go inline
  class CreatePost < V 1
    def self.up
      create_table :blog_posts do |t|
        t.column :title, :string
        t.column :body, :text
      end
    end
  end
end

def Blog.create;

Cool, we’ve got something working. It’d be nice if we knew what was there…

module Blog::Views
  def index
    @posts.each do |e|
      h2{e.title}
      p e.body
      hr
    end

    # this is markaby
    a "add post", :href => R(Add)
  end
end

Permalinks:

class View < R '/view/(\d+)'
  def get(id)
    @post = Post.find(id)
    render :view
  end
end  

[As you can see, this all happened very fast, as we're only 17 minutes in so far.] Nathaniel adds comments in the next 4 minutes.

Egg

So, that’s really most of Camping. To keep the metaphor going, we need to break some eggs (over Rails). Some differences between Rails & Camping:

  • Convention over configuration vs. minimalizism (nothing to configure)
  • Opinionated vs. wackyness (“Camping isn’t so much opinionated as it is… strange.”)
  • Boring vs. different
  • Just like always, but better vs. “More flexible than a wet noodle”
  • Lots and lots of helpers vs. diy
  • Rails vs. Ruby
  • Daunting to hack on vs. hackable (if odd)
  • Encourages conformance vs. encourages experimentation

Cheese

Actually hacking on stuff is fun. That’s why Camping & any other cool, out-there framework or language is there: “we need to feed our inner hacker!” Keys to feeding your inner hacker:

  • Needs to be regular (daily would really be great)
  • Eat a variety of foods (different is good: Rails Monday, Camping Tuesday)
  • You have to feed on things that you’re passionate about

Biscuit

The biscuit is the Community. Why do people who have been to both RailsConf and RubyConf prefer RubyConf? [A show of hands confirmed this.] RubyConf is still small, and it’s the hobbyist conference. Both of those are not true of RailsConf. We, the Ruby community, need both conferences, with RailsConf bringing the momentum and RubyConf bringing the vitality.

Questions

Testing: There’s a testing framework for Camping called Mosquito.

Production: Nathaniel does use it in production, but not for clients.
Intranet apps would be great.

Nathan Sobo: Treetop: Bringing the Elegance of Ruby to Syntactic
Analysis

Earlier in the day, a significant but small number of folks raised their hands when asked if they had ever written a parser. However, many of us have written ad-hoc parsers on other stuff (in regexes, usually). Why don’t regular programmers use the same tools as language designers for creating parsers? Because the tools for making parsers have a really high barrier to entry, even though regexes and loops make for brittle software. Hopefully, some new tools will lower this barrier to entry. Treetop is an attempt at this.

What is a Context Free (Generative) Grammar? A grammar is a program, a program that generates every possible string in a language. However, there’s a problem with this model of grammars, as sometimes there’s ambiguity (think of if/else with ambigous nesting). Instead, do Parsing Expression Grammars [PEG], which Treetop uses, and work on recognizing language rather than generating it.

PEGs are just a generalization of ur-regexes, but are more powerful because they can do recursion. Here’s something for (((a))):

# Treetop, not Ruby
grammar ParenLanguage
  rule nested_parens
    '(' nested_parens ')' / [a-z]
  end
end  

# use in Ruby like so
load_grammar 'paren_language'
parser = ParenLanguageParser.new
tree = parser.parse("(((a)))")

The tree above is an OO view of the parse.

Some livecoding

Let’s parse the language of arithmetic.

(5 + 2) * (10 - 5)

First, draw a tree over the thing you want to parse.

Here’s what I captured from what he livecode:

dir = File.dirname(__FILE__)
require "#{dir}/test_header"

load_grammar "#{dir}/aritmetic"

class ArithmeticGrammarTest < Test::Unit::TestCase
  include GrammarTestHelper

  def setup
    @parser = ArithmeticParser.new
  end
  def test_numbers_simple
    assert @parser.parse('0').success?
    assert_equal 0, @parser.parse('0').eval
    assert @parser.parse('123').success?
  end

  def test_numbers_use_helpers
    assert 0, parse('0').eval
  end

  def test_variables
    assert_equal 2, ... something ..
  end

  test_multiplicative
    assert_equal 20,  parse('x * 10').eval({'x' => 2})
    assert_equal 4 * 3 * 2, parse('4 * 3 * 2 * 1').eval...
  end

  def test_additive
    assert_equal 5 + 2 * 10 - 5, parse('5 + x * 10 - y').eval({'x' => 2, 'y' => 5})
  end 

  def test_parentheses
    assert_equal (5 + 2) * (10 - 5), parse('(5 + x) * (10 - y)').eval({'x' => 2, 'y' => 5})
  end
end

# different file
grammar Arithmetic
  rule primary
    variable
    /
    number
    /
    '(' space additive space ')' {
      eval(...)
    }
  end  

  rule space
    ' '*
  end  

  rule additive
    operand_1:multiplicative space additive_op space operand_2:additive {
      def eval(env)
        additive_op.apply(operand_1.eval(env), operand_2.eval(env))
      end
    }
    /
    primary
  end

  rule additive_op
    '+'
  end

  rule multiplicative
    operand_1:primary space '*' space operand_2:multiplicative {
      def eval(env)
        operand_1.eval(env) * operand_2.eval(env)
      end
    }
    /
    primary
  end

  rule variable
    [a-z]+ {
      def eval(env)
        env[name]
      end
      def name
        text_value
      end
    }
  end  

  rule number
    ([1-9] [0-9]* / '0') {
      def eval(env)
        text_value.to_i
      end
    }
  end
end

Note that we didn’t lex anywhere above, and that the stuff above is composable. Grammars can be opened up an have other Grammars included (include Arithmetic, then override some part of it!)).

[Just showed up a Turing-complete Lambda Calculus language parser in 132 lines]

Imagine (using each others PEGs):

grammar RubyWithSQLStrings
  include Ruby
  include SQL

  rule expression
    ruby_expression
  end  

  rule ruby_string
    quote sql_expression quote / super
  end
end 

We didn’t cover lookahead, but there’s both negative and positive. Here’s negative (a quote, a bunch of not quotes, followed by quote):

'"' (!'"' .)* '"'

Memoization makes all of this stuff work, although it wasn’t an option in the past.

Ryan Davis: Hurting Code for Fun and Profit

On Ruby Sadism, Asceticism, & Introspection.

Start with a story: Once upon a time, a developer went to a New Place. The New Place had legacy code (any code that you didn’t write yourself). Every piece of legacy code reference 5 other files and everything is a rats nest. The developer is mad. He does what is “right” and kills all of the people responsible.

OR: Developer finds the dependencies, the rats nest, and gets angry. But, this time he pulls out tools and instead of maiming the people, he hurts the code. He shows the code who is boss.

 People will press charges if you hurt them.

Photo by candescence

People will press charges when you hurt them, code won’t.

Why Hurt Code

Hurting code is fun, and may make your code cleaner, more readable, and easier to test. If you make fixing code fun, you’ll do it much more often. An obvious example of sadism is killing a bug by writing a new test.

For some reason, people love complexity. Asceticism is characterized by strict self-discipline. Test-first is an example of asceticism. YAGNI is an example of abstenstion. Resist indulgence! (needless complexity, overly-clever code, code that you don’t need right now, “technical debt”)

“A developer’s obligation is to make sure that the code as written makes the clearest possible statement as to how the solution was understood at the time of writing.” –Ward Cunningham

Introspection-oriented development

How to do it?

  • Ask yourself constantly: How do I do better? How did I overlook that bug? Am I wrong?
  • Improve yourself: read 1 nerd book per month (which is 12x industry average)
  • c2.com & other wikis with smart people
  • Get rid of high-flow mailing lists, meaningless blogs in feedreader, bad sites
  • Grow: Learn a language a year, learn your tools much better, examine your habits, study something wierd
  • Push yourself: Write lots; throw away; write more (they weren’t kidding when they said “practice makes perfect”)
  • Push yourself more: Be competetive, challenge the status quo
  • Feel: Have an opinion, have passion (zentest, flog & heckle all came from love) (image_science came from hate)
  • Feedback: Figure out how to get better

Tools

Flog can help find code that will be hard to test and understand.

Coverage tools are good at finding gaping holes, but not anything about quality.

Heckle (“the most sadistic tools I’ve written”) mutates your implementation to make sure that your tests are good.

Comments are closed.