ampere 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/ampere.gemspec +88 -0
- data/lib/ampere/model.rb +37 -10
- data/spec/models/model_spec.rb +31 -22
- data/spec/models/queries_spec.rb +1 -1
- data/spec/models/relationships/belongs_to_spec.rb +9 -1
- data/spec/models/relationships/has_one_spec.rb +1 -1
- data/spec/module/collections_spec.rb +1 -0
- metadata +20 -19
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/ampere.gemspec
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "ampere"
|
8
|
+
s.version = "0.1.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Max Thom Stahl"]
|
12
|
+
s.date = "2012-01-18"
|
13
|
+
s.description = "An ActiveRecord/Mongoid-esque object model for the Redis key/value data store."
|
14
|
+
s.email = "max@villainousindustri.es"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"ampere.gemspec",
|
30
|
+
"features/ampere.feature",
|
31
|
+
"features/step_definitions/ampere_steps.rb",
|
32
|
+
"features/support/env.rb",
|
33
|
+
"lib/ampere.rb",
|
34
|
+
"lib/ampere/collection.rb",
|
35
|
+
"lib/ampere/model.rb",
|
36
|
+
"spec/models/indices_spec.rb",
|
37
|
+
"spec/models/model_spec.rb",
|
38
|
+
"spec/models/queries_spec.rb",
|
39
|
+
"spec/models/relationships/belongs_to_spec.rb",
|
40
|
+
"spec/models/relationships/has_many_spec.rb",
|
41
|
+
"spec/models/relationships/has_one_spec.rb",
|
42
|
+
"spec/models/updates_spec.rb",
|
43
|
+
"spec/module/ampere_spec.rb",
|
44
|
+
"spec/module/collections_spec.rb",
|
45
|
+
"spec/spec_helper.rb",
|
46
|
+
"test/helper.rb",
|
47
|
+
"test/test_ampere.rb"
|
48
|
+
]
|
49
|
+
s.homepage = "http://github.com/mstahl/ampere"
|
50
|
+
s.licenses = ["EPL"]
|
51
|
+
s.require_paths = ["lib"]
|
52
|
+
s.rubygems_version = "1.8.10"
|
53
|
+
s.summary = "A pure Ruby ORM for Redis."
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
s.specification_version = 3
|
57
|
+
|
58
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
59
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<cucumber>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
63
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
64
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
65
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
66
|
+
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
69
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
70
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
73
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
74
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
75
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
76
|
+
end
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
79
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
80
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
81
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
82
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
83
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
84
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/lib/ampere/model.rb
CHANGED
@@ -5,6 +5,7 @@ module Ampere
|
|
5
5
|
@fields = []
|
6
6
|
@field_defaults = {}
|
7
7
|
@indices = []
|
8
|
+
@field_types = {}
|
8
9
|
|
9
10
|
### Instance methods
|
10
11
|
|
@@ -45,12 +46,12 @@ module Ampere
|
|
45
46
|
# Initialize an instance like this:
|
46
47
|
#
|
47
48
|
# Post.new :title => "Kitties: Are They Awesome?"
|
48
|
-
def initialize(hash = {})
|
49
|
+
def initialize(hash = {}, unmarshal = false)
|
49
50
|
hash.each do |k, v|
|
50
51
|
if k == 'id' then
|
51
|
-
@id = v
|
52
|
+
@id = unmarshal ? Marshal.load(v) : v
|
52
53
|
else
|
53
|
-
self.send("#{k}=", v)
|
54
|
+
self.send("#{k}=", (unmarshal and not k =~ /_id$/) ? Marshal.load(v) : v)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
@@ -67,7 +68,12 @@ module Ampere
|
|
67
68
|
end
|
68
69
|
|
69
70
|
self.class.fields.each do |k|
|
70
|
-
|
71
|
+
v = Ampere.connection.hget(@id, k)
|
72
|
+
if k =~ /_id$/ then
|
73
|
+
self.send("#{k}=", v)
|
74
|
+
else
|
75
|
+
self.send("#{k}=", Marshal.load(v))
|
76
|
+
end
|
71
77
|
end
|
72
78
|
self
|
73
79
|
end
|
@@ -80,7 +86,7 @@ module Ampere
|
|
80
86
|
end
|
81
87
|
|
82
88
|
self.attributes.each do |k, v|
|
83
|
-
Ampere.connection.hset(@id, k, v)
|
89
|
+
Ampere.connection.hset(@id, k, k =~ /_id$/ ? v : Marshal.dump(v))
|
84
90
|
end
|
85
91
|
|
86
92
|
self.class.indices.each do |index|
|
@@ -108,7 +114,7 @@ module Ampere
|
|
108
114
|
def update_attribute(key, value)
|
109
115
|
raise "Cannot update a nonexistent field!" unless self.class.fields.include?(key)
|
110
116
|
self.send("#{key}=", value)
|
111
|
-
Ampere.connection.hset(@id, key, value)
|
117
|
+
Ampere.connection.hset(@id, key, Marshal.dump(value))
|
112
118
|
end
|
113
119
|
|
114
120
|
def update_attributes(hash = {})
|
@@ -158,17 +164,31 @@ module Ampere
|
|
158
164
|
@fields ||= []
|
159
165
|
@field_defaults ||= {}
|
160
166
|
@indices ||= []
|
167
|
+
@field_types ||= {}
|
161
168
|
|
162
169
|
@fields << name
|
163
170
|
|
164
|
-
attr_accessor :"#{name}"
|
171
|
+
# attr_accessor :"#{name}"
|
165
172
|
|
166
173
|
# Handle default value
|
167
174
|
@field_defaults[name] = options[:default]
|
168
175
|
|
176
|
+
# Handle type, if any
|
177
|
+
if options[:type] then
|
178
|
+
@field_types[:"#{name}"] = options[:type].to_s
|
179
|
+
end
|
180
|
+
|
169
181
|
define_method :"#{name}" do
|
170
182
|
instance_variable_get("@#{name}") or self.class.field_defaults[name]
|
171
183
|
end
|
184
|
+
|
185
|
+
define_method :"#{name}=" do |val|
|
186
|
+
if not self.class.field_types[:"#{name}"] or val.is_a?(eval(self.class.field_types[:"#{name}"])) then
|
187
|
+
instance_variable_set("@#{name}", val)
|
188
|
+
else
|
189
|
+
raise "Cannot set field of type #{self.class.field_types[name.to_sym]} with #{val.class} value"
|
190
|
+
end
|
191
|
+
end
|
172
192
|
end
|
173
193
|
|
174
194
|
def self.fields
|
@@ -179,11 +199,15 @@ module Ampere
|
|
179
199
|
@field_defaults
|
180
200
|
end
|
181
201
|
|
202
|
+
def self.field_types
|
203
|
+
@field_types
|
204
|
+
end
|
205
|
+
|
182
206
|
# Finds the record with the given ID, or the first that matches the given conditions
|
183
207
|
def self.find(options = {})
|
184
208
|
if options.class == String then
|
185
209
|
if Ampere.connection.exists(options) then
|
186
|
-
new(Ampere.connection.hgetall(options))
|
210
|
+
new(Ampere.connection.hgetall(options), true)
|
187
211
|
else
|
188
212
|
nil
|
189
213
|
end
|
@@ -239,6 +263,7 @@ module Ampere
|
|
239
263
|
@fields ||= []
|
240
264
|
@field_defaults ||= {}
|
241
265
|
@indices ||= []
|
266
|
+
@field_types ||= {}
|
242
267
|
if field_name.class == String or field_name.class == Symbol then
|
243
268
|
raise "Can't index a nonexistent field!" unless @fields.include?(field_name)
|
244
269
|
elsif field_name.class == Array then
|
@@ -290,9 +315,11 @@ module Ampere
|
|
290
315
|
|
291
316
|
unless nonindexed_fields.empty?
|
292
317
|
results = all if results.nil?
|
293
|
-
results.map
|
318
|
+
results = results.to_a.map{|r| r.class == String ? find(r) : r}
|
294
319
|
nonindexed_fields.each do |key|
|
295
|
-
results.select!{|r|
|
320
|
+
results.select!{|r|
|
321
|
+
r.send(key) == options[key]
|
322
|
+
}
|
296
323
|
end
|
297
324
|
end
|
298
325
|
|
data/spec/models/model_spec.rb
CHANGED
@@ -59,11 +59,16 @@ describe "Base models", :model => true do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
it "should set field types for fields that have a type" do
|
63
|
+
Post.field_types.should_not be_nil
|
64
|
+
Post.field_types[:pageviews].should_not be_nil
|
65
|
+
Post.field_types[:pageviews].should == 'Integer'
|
66
|
+
end
|
67
|
+
|
62
68
|
it "shouldn't care what the value types are assigned to a field with no type defined" do
|
63
|
-
|
64
|
-
# Assign a string to the :make of a motorcycle.
|
69
|
+
# Assign an int to the :title of a Post.
|
65
70
|
(->{
|
66
|
-
Post.create :title =>
|
71
|
+
Post.create :title => 1234,
|
67
72
|
:byline => "",
|
68
73
|
:content => "",
|
69
74
|
:pageviews => 1234
|
@@ -71,25 +76,24 @@ describe "Base models", :model => true do
|
|
71
76
|
|
72
77
|
}).should_not raise_error
|
73
78
|
|
74
|
-
# Assign
|
79
|
+
# Assign a string to the :title of a Post.
|
75
80
|
(->{
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
Post.create :title => "1234",
|
82
|
+
:byline => "",
|
83
|
+
:content => "",
|
84
|
+
:pageviews => 1234
|
80
85
|
}).should_not raise_error
|
81
86
|
end
|
82
87
|
|
83
|
-
it "should, given a field's type, only accept values for that field of that type"
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
:displacement => 450.0
|
88
|
+
it "should, given a field's type, only accept values for that field of that type" do
|
89
|
+
post = Post.create :title => "",
|
90
|
+
:byline => "",
|
91
|
+
:content => "",
|
92
|
+
:pageviews => 1234
|
89
93
|
|
90
94
|
# Try to assign a string to :year, raising an error.
|
91
|
-
(->{
|
92
|
-
(->{
|
95
|
+
(->{post.pageviews = "this is not an integer"}).should raise_error
|
96
|
+
(->{post.pageviews = 4321}).should_not raise_error
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
@@ -141,9 +145,15 @@ describe "Base models", :model => true do
|
|
141
145
|
foo = Post.create :title => "Kitties!", :byline => "Max", :content => "Kitties are awesome."
|
142
146
|
bar = Post.create :title => "Doggies!", :byline => "Max", :content => "Doggies are cool."
|
143
147
|
|
144
|
-
foo.should == foo
|
148
|
+
foo.should == foo
|
145
149
|
foo.should_not == bar
|
146
150
|
|
151
|
+
foo.should eql(foo)
|
152
|
+
foo.should_not eql(bar)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should also be able to determine the hash of a record, for equivalence testing" do
|
156
|
+
Post.new(title: "Guinea Pigs", byline: "Max", content: "Guinea pigs are super cute.").hash.is_a?(Fixnum).should be_true
|
147
157
|
end
|
148
158
|
|
149
159
|
it "should be able to tell when it's new" do
|
@@ -167,7 +177,7 @@ describe "Base models", :model => true do
|
|
167
177
|
|
168
178
|
it "should be destroyable by itself" do
|
169
179
|
another_post = Post.create :title => "This one too, probably.",
|
170
|
-
:byline => "Just seems like one
|
180
|
+
:byline => "Just seems like one big",
|
171
181
|
:content => "non sequitor."
|
172
182
|
id = another_post.id
|
173
183
|
another_post.destroy.should == 1
|
@@ -175,10 +185,9 @@ describe "Base models", :model => true do
|
|
175
185
|
end
|
176
186
|
|
177
187
|
it "should be findable by ID" do
|
178
|
-
post = Post.
|
179
|
-
|
180
|
-
|
181
|
-
post.save
|
188
|
+
post = Post.create :title => "foo",
|
189
|
+
:byline => "bar",
|
190
|
+
:content => "baz"
|
182
191
|
Post.find(post.id).should == post
|
183
192
|
# Since we're using GUIDs, this should also be true:
|
184
193
|
post2 = Post.find(post.id)
|
data/spec/models/queries_spec.rb
CHANGED
@@ -77,7 +77,7 @@ describe 'queries', :queries => true do
|
|
77
77
|
|
78
78
|
it 'should be able to find by two non-indexed fields at once' do
|
79
79
|
# :breed and :age are not indexed
|
80
|
-
Kitty.where(:breed => "Domestic shorthair", :age =>
|
80
|
+
Kitty.where(:breed => "Domestic shorthair", :age => 17).count.should == 1
|
81
81
|
end
|
82
82
|
|
83
83
|
it 'should be able to find by a mix of indexed and non-indexed fields' do
|
@@ -88,7 +88,15 @@ describe 'belongs_to relationships', :belongs_to => true do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'sets belongs_to pointer for has_many relationship' do
|
91
|
-
|
91
|
+
@car.passengers = @car.passengers + [@driver]
|
92
|
+
@car.passengers = @car.passengers + [@passenger]
|
93
|
+
@car.save
|
94
|
+
|
95
|
+
@driver.reload
|
96
|
+
@passenger.reload
|
97
|
+
|
98
|
+
@driver.car.should == @car
|
99
|
+
@passenger.car.should == @car
|
92
100
|
end
|
93
101
|
|
94
102
|
###
|
@@ -27,6 +27,7 @@ describe 'Collections', :collections => true do
|
|
27
27
|
democrats.class.should == Ampere::Collection
|
28
28
|
democrats.model.should == President
|
29
29
|
democrats.raw_array.length.should == 3
|
30
|
+
democrats.length.should == 3
|
30
31
|
end
|
31
32
|
|
32
33
|
it 'should be accessible via [] like an Array' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ampere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-18 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70220576682780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70220576682780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: shoulda
|
27
|
-
requirement: &
|
27
|
+
requirement: &70220576678180 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70220576678180
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: cucumber
|
38
|
-
requirement: &
|
38
|
+
requirement: &70220576676920 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70220576676920
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
|
-
requirement: &
|
49
|
+
requirement: &70220576675420 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.0.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70220576675420
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
requirement: &
|
60
|
+
requirement: &70220576674400 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.6.4
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70220576674400
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: simplecov
|
71
|
-
requirement: &
|
71
|
+
requirement: &70220576672900 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70220576672900
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &70220576671880 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70220576671880
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rdoc
|
93
|
-
requirement: &
|
93
|
+
requirement: &70220576670820 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70220576670820
|
102
102
|
description: An ActiveRecord/Mongoid-esque object model for the Redis key/value data
|
103
103
|
store.
|
104
104
|
email: max@villainousindustri.es
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- README.md
|
118
118
|
- Rakefile
|
119
119
|
- VERSION
|
120
|
+
- ampere.gemspec
|
120
121
|
- features/ampere.feature
|
121
122
|
- features/step_definitions/ampere_steps.rb
|
122
123
|
- features/support/env.rb
|
@@ -150,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
151
|
version: '0'
|
151
152
|
segments:
|
152
153
|
- 0
|
153
|
-
hash:
|
154
|
+
hash: 4395967643533566831
|
154
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
156
|
none: false
|
156
157
|
requirements:
|