Skip to content

Commit

Permalink
Added toy store example.
Browse files Browse the repository at this point in the history
  • Loading branch information
jnunemaker committed Apr 19, 2012
1 parent 6fa9cbc commit 9aef2e3
Showing 1 changed file with 160 additions and 0 deletions.
160 changes: 160 additions & 0 deletions examples/plain_old_object_on_roids.rb
@@ -0,0 +1,160 @@
require 'pp'
require 'pathname'
require 'rubygems'
require 'adapter/memory'

root_path = Pathname(__FILE__).dirname.join('..').expand_path
lib_path = root_path.join('lib')
$:.unshift(lib_path)
require 'toystore'

#################################################################
# An example of all the goodies you get by including Toy::Store #
# Note that you also get all of the goodies in Toy::Object. #
#################################################################

class Person
include Toy::Store

attribute :name, String
attribute :age, Integer, :default => 0
end

# Persistence
john = Person.create(:name => 'John', :age => 30)
pp john
pp john.persisted?

# Mass Assignment Security
Person.attribute :role, String, :default => 'guest'
Person.attr_accessible :name, :age

person = Person.new(:name => 'Hacker', :age => 13, :role => 'admin')
pp person.role # "guest"

# Querying
pp Person.get(john.id)
pp Person.get_multi(john.id)
pp Person.get('NOT HERE') # nil
pp Person.get_or_new('NOT HERE') # new person with id of 'NOT HERE'

begin
Person.get!('NOT HERE')
rescue Toy::NotFound
puts "Could not find person with id of 'NOT HERE'"
end

# Reloading
pp john.reload

# Callbacks
class Person
def add_fifty_to_age
self.age += 50
end
end

class Person
before_create :add_fifty_to_age
end

pp Person.create(:age => 10).age # 60

# Validations
class Person
validates_presence_of :name
end

person = Person.new
pp person.valid? # false
pp person.errors[:name] # ["can't be blank"]

# Lists (array key stored as attribute)
class Skill
include Toy::Store

attribute :name, String
attribute :truth, Boolean
end

class Person
list :skills, Skill
end

john.skills = [Skill.create(:name => 'Programming', :truth => true)]
john.skills << Skill.create(:name => 'Mechanic', :truth => false)

pp john.skills.map(&:id) == john.skill_ids # true

# References (think foreign keyish)
class Person
reference :mom, Person
end

mom = Person.create(:name => 'Mum')
john.mom = mom
john.save
pp john.reload.mom_id == mom.id # true

# Identity Map
Toy::IdentityMap.use do
frank = Person.create(:name => 'Frank')

pp Person.get(frank.id).equal?(frank) # true
pp Person.get(frank.id).object_id == frank.object_id # true
end

# Or you can turn it on globally
Toy::IdentityMap.enabled = true
frank = Person.create(:name => 'Frank')

pp Person.get(frank.id).equal?(frank) # true
pp Person.get(frank.id).object_id == frank.object_id # true

# All persistence runs through an adapter.
# All of the above examples used the default in-memory adapter.
# Looks something like this:
Person.adapter :memory, {}

puts "Adapter: #{Person.adapter.inspect}"

# You can make a new adapter to your awesome new/old data store
# Always use #key_for, #encode, and #decode. Feel free to override
# them if you like, but always use them. Default encode/decode is
# most likely marshaling, but you can use anything.
Adapter.define(:append_only_array) do
def read(key)
if (record = client.reverse.detect { |row| row[0] == key_for(key) })
decode(record)
end
end

def write(key, value)
key = key_for(key)
value = encode(value)
client << [key, value]
value
end

def delete(key)
key = key_for(key)
client.delete_if { |row| row[0] == key }
end

def clear
client.clear
end
end

client = []
Person.adapter :append_only_array, client

pp "Client: #{Person.adapter.client.equal?(client)}"

person = Person.create(:name => 'Phil', :age => 55)
person.age = 56
person.save

pp client

pp Person.get(person.id) # Phil with age 56

0 comments on commit 9aef2e3

Please sign in to comment.