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 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: