Git Product home page Git Product logo

toystore's Introduction

Toystore

An object mapper for any adapter that can read, write, delete, and clear data.

Examples

The project comes with two main includes that you can use -- Toy::Object and Toy::Store.

Toy::Object comes with all the goods you need for plain old ruby objects -- attributes, dirty attribute tracking, equality, inheritance, serialization, cloning, logging and pretty inspecting.

Toy::Store includes Toy::Object and adds identity, persistence and querying through adapters, mass assignment, callbacks, validations and a few simple associations (lists and references).

Toy::Object

First, join me in a whirlwind tour of Toy::Object.

class Person
  include Toy::Object

  attribute :name, String
  attribute :age,  Integer
end

# Pretty class inspecting
pp Person

john  = Person.new(:name => 'John',  :age => 30)
steve = Person.new(:name => 'Steve', :age => 31)

# Pretty inspecting
pp john

# Attribute dirty tracking
john.name = 'NEW NAME!'
pp john.changes       # {"name"=>["John", "NEW NAME!"], "age"=>[nil, 30]}
pp john.name_changed? # true

# Equality goodies
pp john.eql?(john)  # true
pp john.eql?(steve) # false
pp john == john     # true
pp john == steve    # false

# Cloning
pp john.clone

# Inheritance
class AwesomePerson < Person
end

pp Person.attributes.keys.sort          # ["age", "name"]
pp AwesomePerson.attributes.keys.sort   # ["age", "name", "type"]

# Serialization
puts john.to_json
puts john.to_xml

Ok, that was definitely awesome. Please continue on your personal journey to a blown mind (very similar to a beautiful mind).

Toy::Store

Toy::Store is a unique bird that builds on top of Toy::Object. Below is a quick sample of what it can do.

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.read(john.id)
pp Person.read_multiple([john.id])
pp Person.read('NOT HERE') # nil

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

# Reloading
pp john.reload

# Callbacks
class Person
  before_create :add_fifty_to_age

  def add_fifty_to_age
    self.age += 50
  end
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.read(frank.id).equal?(frank)                # true
  pp Person.read(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.read(frank.id).equal?(frank)                # true
pp Person.read(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
Adapter.define(:append_only_array) do
  def read(key)
    if (record = client.reverse.detect { |row| row[0] == key })
      record
    end
  end

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

  def delete(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.read(person.id) # Phil with age 56

If that doesn't excite you, nothing will. At this point, you are probably wishing for more.

Luckily, there is an entire directory full of examples and I created a few power user guides, which I will kindly link next.

Instrumentation

ToyStore comes with a log subscriber and automatic metriks instrumentation. By default these work with ActiveSupport::Notifications, but only require the pieces of ActiveSupport that are needed and only do so if you actually attempt to require the instrumentation files listed below.

To use the log subscriber:

# Gemfile
gem 'activesupport'

# config/initializers/toystore.rb (or wherever you want it)
require 'toy/instrumentation/log_subscriber'

To use the metriks instrumentation:

# Gemfile
gem 'activesupport'
gem 'metriks'

# config/initializers/toystore.rb (or wherever you want it)
require 'toy/instrumentation/metriks'

ToyStore Power User Guides

Changelog

As of 0.8.3, I started keeping a changelog. All significant updates will be summarized there.

Compatibility

  • Rails 3.0., 3.1., 3.2.*, Sinatra, etc. No Rails 2 (because it uses Active Model).
  • Ruby 1.9.3 only

Mailing List

https://groups.google.com/forum/#!forum/toystoreadapter

Contributing

  • Fork the project.
  • Make your feature addition or bug fix in a topic branch.
  • Add tests for it. This is important so we don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or changelog. (if you want to have your own version, that is fine, but bump version in a commit by itself so we can ignore when we pull)
  • Send a pull request.

toystore's People

Contributors

bkeepers avatar gdagley avatar gtaglang avatar jnunemaker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

toystore's Issues

ruby 2.0.0 and/or 2.1, rails 4 compatibility?

First of all, I love the gem and would like to continue using it in my projects (yes, I am using toystore in production) because it gives me the ability to create typecasted copies of API model-objects which can also be stored/cached flexibly on a backend of my choice.

Is this repository still maintained? If yes it would be awesome if you could at least add travis testing for ruby 2.0.0 and 2.1. As many already did, I am planning to move on to rails 4.0 on production too, so it would be great if you could at least check for compatibility there as well and update the gemspec if it is given.

If on the other hand the repository won't be maintained any more, perhaps you have an idea which alternatives could be possibly used then.

Thanks!!

Define #hash

Toystore defines #eql?, but not hash, which is used in Array#uniq. The ruby docs for #hash say:

This function must have the property that a.eql?(b) implies a.hash == b.hash.

Lazy loading of adapter

Right now you need an instance that is all setup and ready to go to pass to the adapter method. I'm thinking we should allow a block which will get yielded and memoized on first call. This will allow for lazy loading of things.

class User
  include Toy::Store
  adapter { some_adapter_instance }
end

Rails 3.2 compatibility?

Any specific reason why the gemspec reads:
activemodel (> 3.0, < 3.2)
activesupport (
> 3.0, < 3.2)
?

Toystore switching to 1.9 only

Anyone have any problems with this? I'm getting real tired of 1.8 and don't feel like supporting it anymore. Planning on doing it barring some massive backlash in which case I may do it anyway. :P

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.