cubbyhole 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,5 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  vendor/bundle
6
+ *.dir
7
+ *.pag
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ gemspec
5
5
 
6
6
  group :test do
7
7
  gem 'rspec'
8
+ gem 'ruby-debug'
8
9
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Cubbyhole - The zero config, non-production, activemodel compliant datastore
1
+ # Cubbyhole - The zero config, non-production, datastore
2
2
 
3
3
  Sinatra is dead simple, but it's more interesting to play with if you can store some data. The problem is that setting up ActiveRecord or DataMapper significantly complicates things.
4
4
 
@@ -7,7 +7,6 @@ Cubbyhole is designed to be absolutely zero config.
7
7
  ```ruby
8
8
  require 'cubbyhole'
9
9
 
10
-
11
10
  post = Post.create(:title => "Foo", :text => "Bar")
12
11
 
13
12
  Post.get(post.id).title # => Foo
data/example/Gemfile CHANGED
@@ -3,3 +3,4 @@ source :rubygems
3
3
  gem "cubbyhole", :path => ".."
4
4
  gem "sinatra"
5
5
  gem "haml"
6
+ gem "ruby-debug"
@@ -0,0 +1,113 @@
1
+ require 'cubbyhole/collection'
2
+
3
+ module Cubbyhole
4
+ class Base
5
+ METHOD_BLACKLIST = [:marshal_load, :marshal_dump, :_dump, :_load]
6
+
7
+ def self.create(params={})
8
+ new(params).save
9
+ end
10
+
11
+ def self.get(id)
12
+ backend[id.to_s]
13
+ end
14
+
15
+ def self.get!(id)
16
+ get(id) or raise "#{self.class} not found for id #{id}"
17
+ end
18
+
19
+ def self.next_id
20
+ @next_id ||= 0
21
+ id = @next_id
22
+ @next_id += 1
23
+ id
24
+ end
25
+
26
+ def self.all
27
+ sdbm.values.map{|x| Marshal.load(x) }
28
+ end
29
+
30
+ def self.first(atts = nil)
31
+ all(atts).first
32
+ end
33
+
34
+ def self.last(atts = nil)
35
+ all(atts).last
36
+ end
37
+
38
+ def self.all(atts = nil)
39
+ Collection.new(backend.keys.sort_by(&:to_i).map{|k| backend[k] }).all(atts)
40
+ end
41
+
42
+ def self.backend
43
+ require 'cubbyhole/sdbm'
44
+ @backend ||= SDBM.new(self.to_s)
45
+ end
46
+
47
+ def self.nuke
48
+ backend.clear
49
+ end
50
+
51
+ def initialize(params={})
52
+ @id = self.class.next_id
53
+ @params = params
54
+ @persisted = false
55
+ normalize_params!
56
+ end
57
+
58
+ attr_reader :id
59
+
60
+ def persisted?
61
+ @persisted
62
+ end
63
+
64
+ def save
65
+ @persisted = true
66
+ normalize_params!
67
+ self.class.backend[id.to_s] = self
68
+ self
69
+ end
70
+
71
+ def destroy
72
+ self.class.backend.delete(@id.to_s)
73
+ end
74
+
75
+ def method_missing(meth, *args, &blk)
76
+ return super if METHOD_BLACKLIST.include?(meth.to_sym)
77
+
78
+ key = meth.to_s
79
+
80
+ if key =~ /=$/
81
+ raise ArgumentError unless args.size == 1
82
+ @params[key.gsub(/=$/, "")] = args.first
83
+ else
84
+ return super if args.size != 0
85
+ @params[key]
86
+ end
87
+ end
88
+
89
+ def respond_to?(meth)
90
+ return super if METHOD_BLACKLIST.include?(meth.to_sym)
91
+ true
92
+ end
93
+
94
+ def attributes
95
+ @params.dup
96
+ end
97
+
98
+ def update_attributes(params)
99
+ @params.merge!(params)
100
+ normalize_params!
101
+ save
102
+ end
103
+
104
+ def normalize_params!
105
+ @params.default = nil
106
+
107
+ @params.keys.dup.each do |key|
108
+ @params[key.to_s] = @params.delete(key)
109
+ end
110
+ @params
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,43 @@
1
+ module Cubbyhole
2
+ class Collection < Array
3
+
4
+ def last(atts = nil)
5
+ if atts
6
+ all(atts).last
7
+ else
8
+ super()
9
+ end
10
+ end
11
+
12
+ def first(atts = nil)
13
+ if atts
14
+ all(atts).first
15
+ else
16
+ super()
17
+ end
18
+ end
19
+
20
+ def all(atts = nil)
21
+ if atts
22
+ Collection.new(where(atts))
23
+ else
24
+ self
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def where(atts)
31
+ select do |item|
32
+ matches = true
33
+ atts.each do |k, v|
34
+ if item.send(k).to_s != v.to_s
35
+ matches = false
36
+ end
37
+ end
38
+ matches
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ require 'sdbm'
2
+
3
+ module Cubbyhole
4
+ class SDBM
5
+ extend Forwardable
6
+ def_delegators :@sdbm, :keys, :delete, :clear
7
+
8
+ def initialize(name)
9
+ @sdbm = ::SDBM.new("cubbyhole.#{name}.sdbm")
10
+ end
11
+
12
+ def [](key)
13
+ if str = @sdbm[key]
14
+ Marshal.load(str)
15
+ end
16
+ end
17
+
18
+ def []=(key, val)
19
+ @sdbm[key] = Marshal.dump(val)
20
+ end
21
+
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Cubbyhole
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/cubbyhole.rb CHANGED
@@ -1,78 +1,6 @@
1
- require "cubbyhole/version"
1
+ require 'cubbyhole/version'
2
+ require 'cubbyhole/base'
2
3
 
3
4
  def Object.const_missing(name)
4
- eval "#{name} = Class.new(Cubbyhole::Base)"
5
- end
6
-
7
- module Cubbyhole
8
- class Base
9
- def self.create(params={})
10
- new(params).save
11
- end
12
-
13
- def self.get(id)
14
- objs[id]
15
- end
16
-
17
- def self.next_id
18
- @next_id ||= 0
19
- id = @next_id
20
- @next_id += 1
21
- id
22
- end
23
-
24
- def self.all
25
- objs.values
26
- end
27
-
28
- def self.objs
29
- @objs ||= {}
30
- end
31
-
32
- def initialize(params={})
33
- @id = self.class.next_id
34
- @params = params
35
- @persisted = false
36
- stringify_keys!
37
- end
38
-
39
- attr_reader :id
40
-
41
- def persisted?
42
- @persisted
43
- end
44
-
45
- def save
46
- @persisted = true
47
- stringify_keys!
48
- self.class.objs[@id] = self
49
- end
50
-
51
- def method_missing(meth, *args, &blk)
52
- key = meth.to_s
53
-
54
- if key =~ /=$/
55
- raise ArgumentError unless args.size == 1
56
- @params[key.gsub(/=$/, "")] = args.first
57
- else
58
- raise ArgumentError unless args.size == 0
59
- @params[key]
60
- end
61
- end
62
-
63
- def respond_to?(*args); true; end
64
-
65
- def update_attributes(params)
66
- @params.merge!(params)
67
- stringify_keys!
68
- save
69
- end
70
-
71
- def stringify_keys!
72
- @params.keys.each do |key|
73
- @params[key.to_s] = @params.delete(key)
74
- end
75
- @params
76
- end
77
- end
5
+ const_set(name, Class.new(Cubbyhole::Base))
78
6
  end
@@ -0,0 +1,42 @@
1
+ $:.push File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'cubbyhole'
4
+
5
+ describe Cubbyhole::Collection do
6
+
7
+ describe "with a bunch of things" do
8
+ before do
9
+ Thing.nuke
10
+ Thing.create(:name => "thing1", :color => "brown", :shape => "triangle")
11
+ Thing.create(:name => "thing2", :color => "green", :shape => "triangle")
12
+ Thing.create(:name => "thing3", :color => "brown", :shape => "triangle")
13
+ Thing.create(:name => "thing4", :color => "green", :shape => "square")
14
+ Thing.create(:name => "thing5", :color => "blue", :shape => "triangle")
15
+ end
16
+
17
+ it "can find them all" do
18
+ Thing.all.size.should eq 5
19
+ Thing.all(:color => "green").size.should eq 2
20
+ end
21
+
22
+ it "can find the first" do
23
+ Thing.first.name.should eq "thing1"
24
+ Thing.first(:color => "green").name.should eq "thing2"
25
+ end
26
+
27
+ it "can find the last" do
28
+ Thing.last.name.should eq "thing5"
29
+ Thing.last(:color => "brown").name.should eq "thing3"
30
+ end
31
+
32
+ it "can chain finds" do
33
+ browntriangles = Thing.all(:color => "brown").all(:shape => "triangle")
34
+ browntriangles.size.should eq 2
35
+ browntriangles.last.name.should eq "thing3"
36
+
37
+ bluetriangle = Thing.all(:shape => "triangle").first(:color => "blue")
38
+ bluetriangle.name.should eq "thing5"
39
+ end
40
+
41
+ end
42
+ end
@@ -56,4 +56,12 @@ describe Cubbyhole do
56
56
 
57
57
  MyModel.all.size.should == 3
58
58
  end
59
+
60
+ it "allows you to destroy objects" do
61
+ object = MyModel.create
62
+ id = object.id
63
+
64
+ object.destroy
65
+ MyModel.get(object.id).should be_nil
66
+ end
59
67
  end
@@ -0,0 +1,73 @@
1
+ $:.push File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'cubbyhole/base'
4
+
5
+ class BaseModel < Cubbyhole::Base
6
+ def self.backend
7
+ @backend ||= Hash.new
8
+ end
9
+ end
10
+
11
+ class MyModelModel < BaseModel; end
12
+ class MyOtherModel < BaseModel; end
13
+
14
+ describe "Cubbyhole::Base subclass with self.backend of Hash.new" do
15
+
16
+ it "allows you to set attrs on new" do
17
+ model = MyModelModel.new(:foo => "bar", :baz => "bang")
18
+ model.foo.should == "bar"
19
+ model.baz.should == "bang"
20
+ end
21
+
22
+ it "allows you to save and fetch objects" do
23
+ model = MyModelModel.new(:foo => "bar")
24
+ model.save
25
+
26
+ fetched = MyModelModel.get(model.id)
27
+ fetched.foo.should == "bar"
28
+ end
29
+
30
+ it "should not persist unsaved objects" do
31
+ model = MyModelModel.new(:foo => "bar")
32
+
33
+ MyModelModel.get(model.id).should be_nil
34
+ end
35
+
36
+ it "allows you to create saved objects" do
37
+ model = MyModelModel.create(:foo => "bar")
38
+
39
+ fetched = MyModelModel.get(model.id)
40
+ fetched.foo.should == "bar"
41
+ end
42
+
43
+ it "allows you to set and retrieve attributes" do
44
+ model = MyModelModel.new
45
+ model.foo.should == nil
46
+ model.foo = "bar"
47
+ model.foo.should == "bar"
48
+ end
49
+
50
+ it "allows you to update_attributes" do
51
+ model = MyModelModel.new(:foo => "bar")
52
+ model.save
53
+ model.update_attributes(:foo => "baz", :bar => "zot")
54
+
55
+ fetched = MyModelModel.get(model.id)
56
+ fetched.foo.should == "baz"
57
+ fetched.bar.should == "zot"
58
+ end
59
+
60
+ it "finds all objects" do
61
+ 3.times { MyOtherModel.create }
62
+
63
+ MyOtherModel.all.size.should == 3
64
+ end
65
+
66
+ it "allows you to destroy objects" do
67
+ object = MyOtherModel.create
68
+ id = object.id
69
+
70
+ object.destroy
71
+ MyOtherModel.get(object.id).should be_nil
72
+ end
73
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cubbyhole
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andy Delcambre
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-19 00:00:00 -07:00
18
+ date: 2011-10-05 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -41,8 +41,13 @@ files:
41
41
  - example/views/index.haml
42
42
  - example/views/new.haml
43
43
  - lib/cubbyhole.rb
44
+ - lib/cubbyhole/base.rb
45
+ - lib/cubbyhole/collection.rb
46
+ - lib/cubbyhole/sdbm.rb
44
47
  - lib/cubbyhole/version.rb
48
+ - spec/collections_spec.rb
45
49
  - spec/cubbyhole_spec.rb
50
+ - spec/hash_backend_spec.rb
46
51
  has_rdoc: true
47
52
  homepage: ""
48
53
  licenses: []
@@ -78,4 +83,6 @@ signing_key:
78
83
  specification_version: 3
79
84
  summary: A zero config data store
80
85
  test_files:
86
+ - spec/collections_spec.rb
81
87
  - spec/cubbyhole_spec.rb
88
+ - spec/hash_backend_spec.rb