ambry 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.md +5 -0
- data/Gemfile +2 -0
- data/Guide.md +320 -0
- data/MIT-LICENSE +18 -0
- data/README.md +97 -0
- data/Rakefile +39 -0
- data/ambry.gemspec +25 -0
- data/extras/bench.rb +107 -0
- data/extras/cookie_demo.rb +111 -0
- data/extras/countries.rb +70 -0
- data/lib/ambry.rb +54 -0
- data/lib/ambry/abstract_key_set.rb +106 -0
- data/lib/ambry/active_model.rb +122 -0
- data/lib/ambry/adapter.rb +53 -0
- data/lib/ambry/adapters/cookie.rb +55 -0
- data/lib/ambry/adapters/file.rb +38 -0
- data/lib/ambry/adapters/yaml.rb +17 -0
- data/lib/ambry/hash_proxy.rb +55 -0
- data/lib/ambry/mapper.rb +66 -0
- data/lib/ambry/model.rb +164 -0
- data/lib/ambry/version.rb +9 -0
- data/lib/generators/norman_generator.rb +22 -0
- data/lib/rack/norman.rb +21 -0
- data/spec/active_model_spec.rb +115 -0
- data/spec/adapter_spec.rb +48 -0
- data/spec/cookie_adapter_spec.rb +81 -0
- data/spec/file_adapter_spec.rb +48 -0
- data/spec/fixtures.yml +18 -0
- data/spec/key_set_spec.rb +104 -0
- data/spec/mapper_spec.rb +97 -0
- data/spec/model_spec.rb +162 -0
- data/spec/spec_helper.rb +38 -0
- metadata +147 -0
data/spec/mapper_spec.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
MockAdapter = Struct.new(:db)
|
4
|
+
|
5
|
+
class Value
|
6
|
+
extend Ambry::Model
|
7
|
+
field :a
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Ambry::Mapper do
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
|
14
|
+
before do
|
15
|
+
Ambry.adapters.clear
|
16
|
+
@adapter = Ambry::Adapter.new
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
Ambry.adapters.clear
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should set default adapter name if unspecified" do
|
24
|
+
mapper = Ambry::Mapper.new "Class"
|
25
|
+
assert_equal Ambry.default_adapter_name, mapper.adapter_name
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should set adapter name if unspecified" do
|
29
|
+
Ambry::Adapter.new :name => :hello
|
30
|
+
mapper = Ambry::Mapper.new "Class", :hello
|
31
|
+
assert_equal :hello, mapper.adapter_name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "hash operations" do
|
36
|
+
|
37
|
+
before { load_fixtures }
|
38
|
+
after { Ambry.adapters.clear }
|
39
|
+
|
40
|
+
describe "#hash" do
|
41
|
+
it "should get a hash corresponding to the mapped class" do
|
42
|
+
assert_equal Person.mapper.adapter.db["Person"], Person.mapper.hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#[]" do
|
47
|
+
it "should return an attributes hash" do
|
48
|
+
assert_kind_of Hash, Person.mapper["moe@3stooges.com"]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should raise NotFoundError if key doesn't exist" do
|
52
|
+
assert_raises Ambry::NotFoundError do
|
53
|
+
Person.mapper["BADKEY"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#[]=" do
|
59
|
+
it "should return the value" do
|
60
|
+
value = Person.mapper[:a] = Value.new(:a => "b")
|
61
|
+
assert_equal "b", value.a
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set value#to_hash as value for key" do
|
65
|
+
value = Person.mapper[:bogus] = Value.new(:a => "b")
|
66
|
+
assert_equal "b", Person.mapper[:bogus][:a]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should freeze the value" do
|
70
|
+
value = Person.mapper[:bogus] = Value.new(:a => "b")
|
71
|
+
assert Person.mapper[:bogus].frozen?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#get" do
|
76
|
+
it "should return a model instance" do
|
77
|
+
assert_kind_of Person, Person.mapper.get("moe@3stooges.com")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#key_set" do
|
82
|
+
it "should return a Ambry::KeySet with all keys" do
|
83
|
+
ks = Person.mapper.key_set
|
84
|
+
assert_kind_of Ambry::AbstractKeySet, ks
|
85
|
+
assert_equal Person.count, ks.count
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#put" do
|
90
|
+
it "should add to hash and return the value" do
|
91
|
+
instance = Value.new(:a => "b")
|
92
|
+
assert value = Value.mapper.put(instance)
|
93
|
+
assert_equal instance, value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Ambry::Model do
|
4
|
+
|
5
|
+
before { load_fixtures }
|
6
|
+
after { Ambry.adapters.clear }
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
|
10
|
+
it "can be called with no arguments" do
|
11
|
+
assert Person.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be called with a block" do
|
15
|
+
p = Person.new do |person|
|
16
|
+
person.name = "joe"
|
17
|
+
end
|
18
|
+
assert_equal "joe", p.name
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can be called with attributes and a block" do
|
22
|
+
assert Person.new(:name => "foo") {|p| p.name = "bar"}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "calls the block after setting sttributes" do
|
26
|
+
p = Person.new(:name => "foo") {|p| p.name = "bar"}
|
27
|
+
assert_equal "bar", p.name
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can set attributes from a hash" do
|
31
|
+
p = Person.new :name => "joe"
|
32
|
+
assert_equal "joe", p.name
|
33
|
+
end
|
34
|
+
|
35
|
+
# This means your custom accessors will be invoked.
|
36
|
+
it "invokes attr writers" do
|
37
|
+
Person.any_instance.expects(:name=).once
|
38
|
+
Person.new(:name => "joe")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Don't loop through params that potentially came from the Internet,
|
42
|
+
# because we need to cast keys to Symbol, and that could leak memory.
|
43
|
+
it "iterates over attribute names, not params" do
|
44
|
+
Person.attribute_names.expects(:each)
|
45
|
+
Person.new(:name => "joe")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".mapper" do
|
50
|
+
it "lazy-loads mapper if it's not set" do
|
51
|
+
Person.instance_variable_set :@mapper, nil
|
52
|
+
assert Person.mapper
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".use" do
|
57
|
+
it "sets a new mapper for the specified adapter" do
|
58
|
+
Person.instance_variable_set :@mapper, nil
|
59
|
+
Person.use :main
|
60
|
+
refute_nil Person.mapper
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe ".create" do
|
65
|
+
it "should add an instance to the database" do
|
66
|
+
Person.create(:name => "Ted Healy", :email => "ted@3stooges.com")
|
67
|
+
assert_equal "Ted Healy", Person.get("ted@3stooges.com").name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
describe "an attribute reader" do
|
73
|
+
it "reads (first) from an instance var" do
|
74
|
+
p = Person.first
|
75
|
+
p.instance_variable_set :@name, "foo"
|
76
|
+
p.instance_variable_set :@attributes, nil
|
77
|
+
assert_equal "foo", p.name
|
78
|
+
end
|
79
|
+
|
80
|
+
# This also provides an easy way to check if a model instance has been
|
81
|
+
# edited. However most of the time we don't need this because Ambry is
|
82
|
+
# not intended for frequent writes.
|
83
|
+
it "reads (second) from an attribute array" do
|
84
|
+
p = Person.first
|
85
|
+
assert_nil p.instance_variable_get :@name
|
86
|
+
refute_nil p.instance_variable_get :@attributes
|
87
|
+
refute_nil p.name
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "an attribute writer" do
|
92
|
+
|
93
|
+
# The attributes hash is never written to, only replaced.
|
94
|
+
it "only sets instance vars" do
|
95
|
+
p = Person.first
|
96
|
+
p.name = "foo"
|
97
|
+
assert_equal "foo", p.instance_variable_get(:@name)
|
98
|
+
refute_equal "foo", p.instance_variable_get(:@attributes)[:name]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#==" do
|
103
|
+
it "returns true if the class and id are the same" do
|
104
|
+
p = Person.first
|
105
|
+
p2 = Person.new(:email => p.email)
|
106
|
+
assert_equal p, p2
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#to_hash" do
|
111
|
+
it "returns a hash of the model's attributes" do
|
112
|
+
p = Person.new(:name => "joe")
|
113
|
+
assert_equal "joe", p.to_hash[:name]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#to_id" do
|
118
|
+
it "returns the key attribute" do
|
119
|
+
p = Person.first
|
120
|
+
assert_equal p.email, p.to_id
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#id_changed?" do
|
125
|
+
it "should be true if the id changed" do
|
126
|
+
p = Person.get("moe@3stooges.com")
|
127
|
+
refute p.id_changed?
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should be false if the id didn't change" do
|
131
|
+
p = Person.get("moe@3stooges.com")
|
132
|
+
p.email = "moe2@3stooges.com"
|
133
|
+
assert p.id_changed?
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#update" do
|
138
|
+
it "updates the database" do
|
139
|
+
p = Person.get("moe@3stooges.com")
|
140
|
+
original = p.name
|
141
|
+
p.update(:name => "Joe Schmoe")
|
142
|
+
p = Person.get("moe@3stooges.com")
|
143
|
+
refute_equal original, p.name
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should allow updating the key" do
|
147
|
+
count = Person.count
|
148
|
+
p = Person.get("moe@3stooges.com")
|
149
|
+
p.update(:email => "moe2@3stooges.com")
|
150
|
+
assert_equal count, Person.count
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#save" do
|
156
|
+
it "passes itself to Mapper#put" do
|
157
|
+
p = Person.new(:name => "hello")
|
158
|
+
Person.mapper.expects(:put)
|
159
|
+
p.save
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
if ENV["coverage"]
|
2
|
+
require "simplecov"
|
3
|
+
SimpleCov.start
|
4
|
+
end
|
5
|
+
require "rubygems"
|
6
|
+
require "bundler/setup"
|
7
|
+
require "ambry"
|
8
|
+
require "ambry/adapters/yaml"
|
9
|
+
require 'minitest/spec'
|
10
|
+
require "mocha"
|
11
|
+
require "fileutils"
|
12
|
+
require "ffaker"
|
13
|
+
|
14
|
+
class Person
|
15
|
+
extend Ambry::Model
|
16
|
+
field :email, :name
|
17
|
+
|
18
|
+
def self.stooges
|
19
|
+
with_index do
|
20
|
+
find_by_key {|k| k =~ /3stooges.com/}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
filters do
|
25
|
+
def non_howards
|
26
|
+
find {|p| p[:name] !~ /Howard/}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_fixtures
|
32
|
+
Ambry.adapters.clear
|
33
|
+
file = File.expand_path("../fixtures.yml", __FILE__)
|
34
|
+
Ambry::Adapters::YAML.new :file => file
|
35
|
+
Person.use :main
|
36
|
+
end
|
37
|
+
|
38
|
+
MiniTest::Unit.autorun
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ambry
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Norman Clarke
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-18 00:00:00.000000000 -03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ffaker
|
17
|
+
requirement: &70280928791740 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70280928791740
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: minitest
|
28
|
+
requirement: &70280928790160 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.2.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70280928790160
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mocha
|
39
|
+
requirement: &70280928788880 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70280928788880
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: activesupport
|
50
|
+
requirement: &70280928787220 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *70280928787220
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: activemodel
|
61
|
+
requirement: &70280928786280 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ~>
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '3.0'
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *70280928786280
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rake
|
72
|
+
requirement: &70280928785640 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *70280928785640
|
81
|
+
description: ! " Ambry is not an ORM, man! It's a database and ORM replacement
|
82
|
+
for (mostly)\n static models and small datasets. It provides ActiveModel compatibility,
|
83
|
+
and\n flexible searching and storage.\n"
|
84
|
+
email: norman@njclarke.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- Changelog.md
|
90
|
+
- Gemfile
|
91
|
+
- Guide.md
|
92
|
+
- MIT-LICENSE
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- ambry.gemspec
|
96
|
+
- extras/bench.rb
|
97
|
+
- extras/cookie_demo.rb
|
98
|
+
- extras/countries.rb
|
99
|
+
- lib/ambry.rb
|
100
|
+
- lib/ambry/abstract_key_set.rb
|
101
|
+
- lib/ambry/active_model.rb
|
102
|
+
- lib/ambry/adapter.rb
|
103
|
+
- lib/ambry/adapters/cookie.rb
|
104
|
+
- lib/ambry/adapters/file.rb
|
105
|
+
- lib/ambry/adapters/yaml.rb
|
106
|
+
- lib/ambry/hash_proxy.rb
|
107
|
+
- lib/ambry/mapper.rb
|
108
|
+
- lib/ambry/model.rb
|
109
|
+
- lib/ambry/version.rb
|
110
|
+
- lib/generators/norman_generator.rb
|
111
|
+
- lib/rack/norman.rb
|
112
|
+
- spec/active_model_spec.rb
|
113
|
+
- spec/adapter_spec.rb
|
114
|
+
- spec/cookie_adapter_spec.rb
|
115
|
+
- spec/file_adapter_spec.rb
|
116
|
+
- spec/fixtures.yml
|
117
|
+
- spec/key_set_spec.rb
|
118
|
+
- spec/mapper_spec.rb
|
119
|
+
- spec/model_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
has_rdoc: true
|
122
|
+
homepage: http://github.com/norman/ambry
|
123
|
+
licenses: []
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ! '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project: ! '[none]'
|
142
|
+
rubygems_version: 1.6.2
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: An ActiveModel-compatible ORM-like library for storing model instances in
|
146
|
+
an in-memory Hash.
|
147
|
+
test_files: []
|