A cool, clear drink of  Ruby object persistence
Upcoming SlideShare
Loading in...5
×
 

A cool, clear drink of Ruby object persistence

on

  • 4,198 views

Introduction to a proof of concept library 'Aqua' that uses CouchDB and other document oriented back ends to transparently persist Ruby objects.

Introduction to a proof of concept library 'Aqua' that uses CouchDB and other document oriented back ends to transparently persist Ruby objects.

Statistics

Views

Total Views
4,198
Views on SlideShare
4,187
Embed Views
11

Actions

Likes
2
Downloads
23
Comments
0

1 Embed 11

http://www.slideshare.net 11

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

A cool, clear drink of  Ruby object persistence A cool, clear drink of Ruby object persistence Presentation Transcript

  • Aqua
    A cool, clear drink of
    Ruby object persistence
    Kane Baccigalupi
    RubyConf 09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Got unemployment?
    Relax with CouchDB
    Kane Baccigalupi
    RubyConf ‘09
    View slide
  • Aqua
    A cool, clear drink of Ruby object persistence
    ORMs are great,
    but normalization is expensive.
    # DataMapper
    class Mammal
    include DataMapper::Resource
    property :my_id, Serial
    has n, :legs
    end
    # ActiveRecord
    class Bird < ActiveRecord::Base
    # properties defined by migration
    has_many, :legs
    end
    Kane Baccigalupi
    RubyConf ‘09
    View slide
  • Aqua
    A cool, clear drink of Ruby object persistence
    CouchDB + Ruby ~=
    CouchRest
    # CouchRest
    class Reptile < CouchRest::ExtendedDocument
    use_database MY_DB
    unique_id :my_id
    property :legs # a collection!
    end
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    CouchRest is different from ORMs because:
    It allows collections
    Models are hashes
    Instance variables are discarded
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    What defines Ruby object state?
    Instance variables
    @my_variable
    Fundamental data
    Hash key-values, Array values, etc.
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Database abstractions
    focus on databases
    # DataMapper
    class Mammal
    include DataMapper::Resource
    property :my_id, Serial
    has n, :legs
    end
    # ActiveRecord
    class Bird < ActiveRecord::Base
    # properties defined by schema
    has_many, :legs
    end
    # CouchRest
    class Reptile < CouchRest::ExtendedDocument
    use_database MY_DB
    unique_id :my_id
    property :legs # a collection!
    end
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Aqua’s goal:
    Focus on objects
    object.commit!
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Because Ruby is awesome
    class Event < Range
    attr_accessor :name
    end
    rubyconf = Event.new(Date.parse('11/19/2009'), Date.parse('11/21/2009'))
    rubyconf.name = 'RubyConf 09'
    rubyconf.include?(Date.parse('11/20/2009')) # true
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    How does Aqua work?
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Just add Aqua
    class User
    aquatic
    # ...
    end
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Just add Aqua
    class User
    aquatic
    # ...
    end
    user = User.new
    # ... More stuff happens to the user
    # saving an object
    user.commit! # commit without the ! also works but raises no errors.
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Behind the scene
    user.commit!
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Behind the scene
    serialization
    user.commit!
    {
    "class"=>"User",
    "ivars"=>{
    "@username"=>"kane",
    "@email"=>"baccigalupi@gmail.com",
    "@password"=>"secret"
    }
    }
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Behind the scene
    serialization
    user.commit!
    {
    "class"=>"User",
    "ivars"=>{
    "@username"=>"kane",
    "@email"=>"baccigalupi@gmail.com",
    "@password"=>"secret"
    }
    }
    data post
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Objects ~= Documents,
    && Documents ~= Hashes
    # YAML for a Ruby User object
    --- &id001 !ruby/object:User
    email: baccigalupi@gmail.com
    password: secret
    username: kane
    # Aqua Serialization for same object
    {
    "class"=>"User",
    "ivars"=>{
    "@username"=>"kane",
    "@email"=>"baccigalupi@gmail.com",
    "@password"=>"secret"
    }
    }
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Sometimes state
    should not hang around.
    There is a method for that.
    class User
    aquatic
    attr_accessor :username, :email, :password
    hide_attributes :password
    end
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Going deeper with embedded objects …
    class Address
    # not an aquatic object, just plain ruby
    attr_accessor :name, :street, :city, :state, :zip
    end
    address = Address.new
    # . . .
    user = User.new
    user.addresses = [ address ]
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Ordinary objects
    get serialized
    inside aquatic
    objects
    {
    "class"=>"User",
    "ivars"=>{
    "@addresses"=>{
    "class"=>"Array",
    "init"=>[{
    "class"=>"Address",
    "ivars"=>{
    "@city"=>"San Francisco",
    "@name"=>"work",
    "@street"=>"P0 Box 58",
    "@state"=>"94102"
    }
    }]
    },
    "@username"=>"kane",
    "@email"=>"baccigalupi@gmail.com"
    }
    }
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Embedded aquatic objects are
    saved by reference.
    {
    "class"=>"User",
    "ivars"=>{
    # ...
    "@friends"=>{
    "class"=>"Array",
    "init"=>[{
    "class"=>"Aqua::Stub",
    "init"=>{"class"=>"User", "id"=>"32"}
    }]
    }
    }
    }
    class User
    aquatic
    # ...
    def friends
    @friends ||= []
    end
    end
    user.friends << alex
    # where alex is another user object
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Aqua::Stub~= Lazy Delegate
    • Gets the object from the db
    • Triggered by #method_missing
    • Stubs/caches methods
    {
    "class"=>"User",
    "ivars"=>{
    # ...
    "@friends"=>{
    "class"=>"Array",
    "init"=>[{
    "class"=>"Aqua::Stub",
    "init"=>{"class"=>"User", "id"=>"32"}
    }]
    }
    }
    }
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Stubbing methods in Aqua::Stub
    {
    "class"=>"User",
    "ivars"=>{
    # ...
    "@friends"=>{
    "class"=>"Array",
    "init"=>[{
    "class"=>"Aqua::Stub",
    "init"=>{
    "class"=>"User",
    "id"=>"32”,
    "methods"=>{"username"=>"alex"},
    }
    }]
    }
    }
    }
    class User
    aquatic :embed =>
    { :stub => :username }
    # ...
    end
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Stubbed behavior
    user.reload
    friend = user.friends.first
    friend.class # Aqua::Stub
    friend.username# ‘alex’
    # username was cached
    friend.email
    # this triggers the database call
    # for the friend object
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Got Files?
    {
    "class"=>"User",
    "ivars"=>{
    # ...
    "@avatar"=>{
    "class"=>"Aqua::FileStub”
    "init"=>{
    "methods"=>{
    "content_type"=>"image/png",
    "content_length"=>{
    "class"=>"Fixnum", "init"=>"26551”
    }
    }
    "id"=>"image_attach.png"
    },
    }
    }
    }
    class User
    aquatic
    # ...
    attr_accessor :avatar
    end
    user.avatar = my_pic
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Getting Objects:
    The basics
    User.load( some_id )
    user.reload
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    Indexed Searches
    class User
    aquatic
    # ...
    index_on :username
    end
    " // javascript map function
    function(doc) {
    if( doc['class'] == 'User' &&
    doc['ivars'] && doc['ivars']['@username'] ){
    emit( doc['ivars']['@username'], 1 );
    }
    }
    "
    User.query(:username, ’kane') # returns an array of all users named kane
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    What’s next?
    More querying ease
    • Search on nested variables
    • Criteria pattern ???
    • Custom dsl ???
    • Much coding love
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    What’s next?
    Mixins
    • Validations
    • Attribute constraints for class, size, etc.
    • Collections & relationships
    • ActiveRecord conversion ???
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    What’s next?
    Serializing Code
    • Lambdas and Procs
    • Singleton methods
    • Classes (are objects too)
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    What’s next?
    Repository Layer
    • In memory
    • Stores objects, not serializations
    • commits objects as needed
    Kane Baccigalupi
    RubyConf ‘09
  • Aqua
    A cool, clear drink of Ruby object persistence
    More Info
    Rdocs: ruby-aqua.org
    Get the gem: sudo gem install aqua
    Explore the code: github.com/baccigalupi/aqua
    Kane Baccigalupi
    RubyConf ‘09