ampere 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
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
- self.send("#{k}=", Ampere.connection.hget(@id, k))
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!{|r| r.class == String ? find(r) : r}
318
+ results = results.to_a.map{|r| r.class == String ? find(r) : r}
294
319
  nonindexed_fields.each do |key|
295
- results.select!{|r| r.send(key) == options[key]}
320
+ results.select!{|r|
321
+ r.send(key) == options[key]
322
+ }
296
323
  end
297
324
  end
298
325
 
@@ -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
- pending "Types not implemented yet."
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 an integer to the :make of a motorcycle, for some reason.
79
+ # Assign a string to the :title of a Post.
75
80
  (->{
76
- Motorcycle.create :make => 1234,
77
- :model => 'CB450SC',
78
- :year => 1986,
79
- :displacement => 450.0
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", :wip => true do
84
- pending "Types not implemented yet."
85
- cycle = Motorcycle.create :make => 'Honda',
86
- :model => 'CB450SC',
87
- :year => 1986,
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
- (->{cycle.year = "this is not a year"}).should raise_error
92
- (->{cycle.year = 1996}).should_not raise_error
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 # Post.new(:title => "Kitties!", :byline => "Max", :content => "Kitties are awesome.")
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 bit",
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.new :title => "foo",
179
- :byline => "bar",
180
- :content => "baz"
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)
@@ -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 => "17").count.should == 1
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
- pending
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
  ###
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "..", "spec_helper.rb")
2
2
 
3
- describe 'has_one relationships' do
3
+ describe 'has_one relationships', has_one:true do
4
4
  before :all do
5
5
  Redis.new.flushall
6
6
  Ampere.connect
@@ -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.0
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-06 00:00:00.000000000Z
12
+ date: 2012-01-18 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &70174558736960 !ruby/object:Gem::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: *70174558736960
24
+ version_requirements: *70220576682780
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: shoulda
27
- requirement: &70174558736420 !ruby/object:Gem::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: *70174558736420
35
+ version_requirements: *70220576678180
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: cucumber
38
- requirement: &70174558735860 !ruby/object:Gem::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: *70174558735860
46
+ version_requirements: *70220576676920
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &70174558735300 !ruby/object:Gem::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: *70174558735300
57
+ version_requirements: *70220576675420
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &70174558734720 !ruby/object:Gem::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: *70174558734720
68
+ version_requirements: *70220576674400
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
- requirement: &70174558734140 !ruby/object:Gem::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: *70174558734140
79
+ version_requirements: *70220576672900
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70174558733620 !ruby/object:Gem::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: *70174558733620
90
+ version_requirements: *70220576671880
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rdoc
93
- requirement: &70174558733120 !ruby/object:Gem::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: *70174558733120
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: -4494108612008764104
154
+ hash: 4395967643533566831
154
155
  required_rubygems_version: !ruby/object:Gem::Requirement
155
156
  none: false
156
157
  requirements: