ampere 1.1.1 → 1.2.0
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/CHANGELOG.md +15 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +36 -26
- data/README.md +25 -11
- data/Rakefile +10 -0
- data/VERSION +1 -1
- data/ampere.gemspec +83 -9
- data/example/.gitignore +5 -0
- data/example/.rspec +1 -0
- data/example/Gemfile +21 -0
- data/example/Gemfile.lock +143 -0
- data/example/README +261 -0
- data/example/Rakefile +7 -0
- data/example/app/assets/images/rails.png +0 -0
- data/example/app/assets/javascripts/application.js +9 -0
- data/example/app/assets/javascripts/posts.js.coffee +3 -0
- data/example/app/assets/stylesheets/application.css +7 -0
- data/example/app/assets/stylesheets/posts.css.scss +3 -0
- data/example/app/assets/stylesheets/scaffolds.css.scss +56 -0
- data/example/app/controllers/application_controller.rb +3 -0
- data/example/app/controllers/posts_controller.rb +83 -0
- data/example/app/helpers/application_helper.rb +2 -0
- data/example/app/helpers/posts_helper.rb +2 -0
- data/example/app/mailers/.gitkeep +0 -0
- data/example/app/models/.gitkeep +0 -0
- data/example/app/models/post.rb +7 -0
- data/example/app/views/layouts/application.html.erb +14 -0
- data/example/app/views/posts/_form.html.erb +25 -0
- data/example/app/views/posts/edit.html.erb +6 -0
- data/example/app/views/posts/index.html.erb +25 -0
- data/example/app/views/posts/new.html.erb +5 -0
- data/example/app/views/posts/show.html.erb +15 -0
- data/example/config/ampere.yml +11 -0
- data/example/config/application.rb +54 -0
- data/example/config/boot.rb +6 -0
- data/example/config/environment.rb +5 -0
- data/example/config/environments/development.rb +30 -0
- data/example/config/environments/production.rb +60 -0
- data/example/config/environments/test.rb +39 -0
- data/example/config/initializers/backtrace_silencers.rb +7 -0
- data/example/config/initializers/inflections.rb +10 -0
- data/example/config/initializers/mime_types.rb +5 -0
- data/example/config/initializers/secret_token.rb +7 -0
- data/example/config/initializers/session_store.rb +8 -0
- data/example/config/initializers/wrap_parameters.rb +10 -0
- data/example/config/locales/en.yml +5 -0
- data/example/config/routes.rb +60 -0
- data/example/config.ru +4 -0
- data/example/db/seeds.rb +7 -0
- data/example/lib/assets/.gitkeep +0 -0
- data/example/lib/tasks/.gitkeep +0 -0
- data/example/log/.gitkeep +0 -0
- data/example/public/404.html +26 -0
- data/example/public/422.html +26 -0
- data/example/public/500.html +26 -0
- data/example/public/favicon.ico +0 -0
- data/example/public/index.html +241 -0
- data/example/public/robots.txt +5 -0
- data/example/script/rails +6 -0
- data/example/spec/controllers/posts_controller_spec.rb +164 -0
- data/example/spec/helpers/posts_helper_spec.rb +15 -0
- data/example/spec/models/post_spec.rb +5 -0
- data/example/spec/requests/posts_spec.rb +11 -0
- data/example/spec/routing/posts_routing_spec.rb +35 -0
- data/example/spec/spec_helper.rb +34 -0
- data/example/spec/views/posts/edit.html.erb_spec.rb +20 -0
- data/example/spec/views/posts/index.html.erb_spec.rb +23 -0
- data/example/spec/views/posts/new.html.erb_spec.rb +20 -0
- data/example/spec/views/posts/show.html.erb_spec.rb +17 -0
- data/example/vendor/assets/stylesheets/.gitkeep +0 -0
- data/example/vendor/plugins/.gitkeep +0 -0
- data/lib/ampere/collection.rb +6 -0
- data/lib/ampere/keys.rb +37 -0
- data/lib/ampere/model.rb +117 -58
- data/lib/ampere/timestamps.rb +23 -0
- data/lib/ampere.rb +17 -1
- data/lib/rails/generators/ampere/config/config_generator.rb +15 -0
- data/lib/rails/generators/ampere/config/templates/ampere.yml +11 -0
- data/lib/rails/generators/ampere/model/model_generator.rb +27 -0
- data/lib/rails/generators/ampere/model/templates/model.rb.tt +10 -0
- data/lib/rails/railtie.rb +49 -0
- data/lib/rails/tasks/ampere.rake +7 -0
- data/spec/models/model_spec.rb +12 -2
- data/spec/models/timestamps_spec.rb +45 -0
- data/spec/module/collections_spec.rb +5 -0
- data/spec/spec_helper.rb +1 -0
- metadata +153 -29
data/lib/ampere/model.rb
CHANGED
@@ -1,14 +1,26 @@
|
|
1
1
|
module Ampere
|
2
|
+
# Including the `Ampere::Model` module into one of your classes mixes in all
|
3
|
+
# the class and instance methods of an Ampere model. See individual methods
|
4
|
+
# for more information.
|
2
5
|
module Model
|
3
|
-
|
4
6
|
def self.included(base)
|
5
7
|
base.extend(ClassMethods)
|
6
8
|
|
9
|
+
base.extend(Keys)
|
10
|
+
|
7
11
|
base.class_eval do
|
12
|
+
extend(::ActiveModel::Callbacks)
|
13
|
+
define_model_callbacks :create, :update, :save
|
14
|
+
|
8
15
|
include(::ActiveModel::Validations)
|
16
|
+
include(Rails.application.routes.url_helpers) if defined?(Rails)
|
17
|
+
include(ActionController::UrlFor) if defined?(Rails)
|
18
|
+
|
19
|
+
include(Ampere::Keys)
|
9
20
|
|
10
21
|
attr_reader :id
|
11
|
-
|
22
|
+
attr_reader :destroyed
|
23
|
+
|
12
24
|
attr_accessor :fields
|
13
25
|
attr_accessor :field_defaults
|
14
26
|
attr_accessor :indices
|
@@ -27,9 +39,9 @@ module Ampere
|
|
27
39
|
# or have been stored and have the same ID, then they are equal.
|
28
40
|
def ==(other)
|
29
41
|
super or
|
30
|
-
other.instance_of?(self.class) and
|
42
|
+
(other.instance_of?(self.class) and
|
31
43
|
not id.nil? and
|
32
|
-
other.id == id
|
44
|
+
other.id == id)
|
33
45
|
end
|
34
46
|
|
35
47
|
# Returns a Hash with all the fields and their values.
|
@@ -43,9 +55,15 @@ module Ampere
|
|
43
55
|
|
44
56
|
# Deletes this instance out of the database.
|
45
57
|
def destroy
|
58
|
+
@destroyed = true
|
46
59
|
self.class.delete(@id)
|
47
60
|
end
|
48
61
|
|
62
|
+
# Returns true if this record has been deleted
|
63
|
+
def destroyed?
|
64
|
+
@destroyed
|
65
|
+
end
|
66
|
+
|
49
67
|
# Delegates to ==().
|
50
68
|
def eql?(other)
|
51
69
|
self == other
|
@@ -61,18 +79,27 @@ module Ampere
|
|
61
79
|
#
|
62
80
|
# Post.new :title => "Kitties: Are They Awesome?"
|
63
81
|
def initialize(hash = {}, unmarshal = false)
|
82
|
+
@destroyed = false
|
83
|
+
|
64
84
|
hash.each do |k, v|
|
65
85
|
if k == 'id' then
|
66
86
|
@id = unmarshal ? Marshal.load(v) : v
|
87
|
+
elsif k =~ /_id$/
|
88
|
+
self.send("#{k}=", v.to_i)
|
67
89
|
else
|
68
|
-
self.send("#{k}=",
|
90
|
+
self.send("#{k}=", unmarshal ? Marshal.load(v) : v)
|
69
91
|
end
|
70
92
|
end
|
71
93
|
end
|
72
94
|
|
73
95
|
# Returns true if this record has not yet been saved.
|
74
96
|
def new?
|
75
|
-
@id.nil? or not Ampere.connection.exists(@id)
|
97
|
+
@id.nil? or not Ampere.connection.exists(key_for_find(self.class, @id))
|
98
|
+
end
|
99
|
+
alias :new_record? :new?
|
100
|
+
|
101
|
+
def persisted?
|
102
|
+
not @id.nil?
|
76
103
|
end
|
77
104
|
|
78
105
|
# Reloads this record from the database.
|
@@ -82,9 +109,9 @@ module Ampere
|
|
82
109
|
end
|
83
110
|
|
84
111
|
self.class.fields.each do |k|
|
85
|
-
v = Ampere.connection.hget(@id, k)
|
112
|
+
v = Ampere.connection.hget(key_for_find(self.class, @id), k)
|
86
113
|
if k =~ /_id$/ then
|
87
|
-
self.send("#{k}=", v)
|
114
|
+
self.send("#{k}=", v.to_i)
|
88
115
|
else
|
89
116
|
self.send("#{k}=", Marshal.load(v))
|
90
117
|
end
|
@@ -94,50 +121,67 @@ module Ampere
|
|
94
121
|
|
95
122
|
# Saves this record to the database.
|
96
123
|
def save
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
elsif index.class == Array then
|
124
|
-
key = index.map{|i| instance_variable_get("@#{i}")}.join(':')
|
125
|
-
val = ([@id] | (Ampere.connection.hget("ampere.index.#{self.class.to_s.downcase}.#{index}", key) or "")
|
124
|
+
run_callbacks :save do
|
125
|
+
run_callbacks :create do
|
126
|
+
self.class.unique_indices.each do |idx|
|
127
|
+
# For each uniquely-indexed field, look up the index for that field,
|
128
|
+
# and throw an exception if this record's value for that field is in
|
129
|
+
# the index already.
|
130
|
+
if Ampere.connection.hexists(key_for_index(idx), instance_variable_get("@#{idx}")) then
|
131
|
+
raise "Cannot save non-unique value for #{idx}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Grab a fresh GUID from Redis by incrementing the "__guid" key
|
136
|
+
if @id.nil? then
|
137
|
+
@id = Ampere.connection.incr('__guid')
|
138
|
+
end
|
139
|
+
|
140
|
+
self.attributes.each do |k, v|
|
141
|
+
Ampere.connection.hset(key_for_find(self.class, @id), k, k =~ /_id$/ ? v : Marshal.dump(v))
|
142
|
+
end
|
143
|
+
|
144
|
+
self.class.indices.each do |index|
|
145
|
+
if index.class == String or index.class == Symbol then
|
146
|
+
Ampere.connection.hset(
|
147
|
+
key_for_index(index),
|
148
|
+
instance_variable_get("@#{index}"),
|
149
|
+
([@id] | (Ampere.connection.hget(key_for_index(index), instance_variable_get("@#{index}")) or "")
|
126
150
|
.split(/:/)).join(":")
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
151
|
+
)
|
152
|
+
elsif index.class == Array then
|
153
|
+
key = index.map{|i| instance_variable_get("@#{i}")}.join(':')
|
154
|
+
val = ([@id] | (Ampere.connection.hget(key_for_index(index), key) or "")
|
155
|
+
.split(/:/)).join(":")
|
156
|
+
Ampere.connection.hset(
|
157
|
+
key_for_index(index.join(':')),
|
158
|
+
key,
|
159
|
+
val
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
self
|
132
164
|
end
|
133
165
|
end
|
134
|
-
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_key #:nodoc:
|
169
|
+
# @id.nil? ? [] : [@id.to_i]
|
170
|
+
if destroyed?
|
171
|
+
[ @id.to_i ]
|
172
|
+
else
|
173
|
+
persisted? ? [ @id.to_i ] : nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_param #:nodoc:
|
178
|
+
@id.to_s
|
135
179
|
end
|
136
180
|
|
137
181
|
def update_attribute(key, value)
|
138
|
-
raise "Cannot update
|
182
|
+
raise "Cannot update nonexistent field '#{key}'!" unless self.class.fields.include?(key.to_sym)
|
139
183
|
self.send("#{key}=", value)
|
140
|
-
Ampere.connection.hset(@id, key, Marshal.dump(value))
|
184
|
+
Ampere.connection.hset(key_for_find(self.class, @id), key, Marshal.dump(value))
|
141
185
|
end
|
142
186
|
|
143
187
|
def update_attributes(hash = {})
|
@@ -146,13 +190,14 @@ module Ampere
|
|
146
190
|
|
147
191
|
# The inefficient way I know how to do right now:
|
148
192
|
hash.each do |k, v|
|
149
|
-
|
193
|
+
self.send("#{k}=", v)
|
150
194
|
end
|
195
|
+
self.save
|
151
196
|
end
|
152
197
|
|
153
198
|
### Class methods
|
154
|
-
module ClassMethods
|
155
|
-
# Returns
|
199
|
+
module ClassMethods #:nodoc:
|
200
|
+
# Returns a lazy collection of all the records that have been stored.
|
156
201
|
def all
|
157
202
|
Ampere::Collection.new(self, Ampere.connection.keys("#{to_s.downcase}.*"))
|
158
203
|
end
|
@@ -176,10 +221,13 @@ module Ampere
|
|
176
221
|
def create(hash = {})
|
177
222
|
new(hash).save
|
178
223
|
end
|
224
|
+
alias :create! :create
|
179
225
|
|
180
226
|
# Deletes the record with the given ID.
|
181
227
|
def delete(id)
|
182
|
-
|
228
|
+
record = find(id)
|
229
|
+
Ampere.connection.del(key_for_find(self, id))
|
230
|
+
record
|
183
231
|
end
|
184
232
|
|
185
233
|
# Declares a field. See the README for more details.
|
@@ -229,7 +277,9 @@ module Ampere
|
|
229
277
|
|
230
278
|
# Finds the record with the given ID, or the first that matches the given conditions
|
231
279
|
def find(options = {})
|
232
|
-
if options.class == String then
|
280
|
+
if options.class == String or options.is_a?(Fixnum) then
|
281
|
+
options = key_for_find(self, options)
|
282
|
+
|
233
283
|
if Ampere.connection.exists(options) then
|
234
284
|
new(Ampere.connection.hgetall(options), true)
|
235
285
|
else
|
@@ -240,7 +290,11 @@ module Ampere
|
|
240
290
|
raise "Cannot find by #{options.class} yet"
|
241
291
|
end
|
242
292
|
end
|
243
|
-
|
293
|
+
|
294
|
+
def first
|
295
|
+
all.first
|
296
|
+
end
|
297
|
+
|
244
298
|
# Defines a has_one relationship with another model. See the README for more details.
|
245
299
|
def has_one(field_name, options = {})
|
246
300
|
referred_klass_name = (options[:class] or options['class'] or field_name)
|
@@ -268,16 +322,16 @@ module Ampere
|
|
268
322
|
my_klass_name = to_s.downcase
|
269
323
|
|
270
324
|
define_method(:"#{field_name}") do
|
271
|
-
(Ampere.connection.smembers(
|
325
|
+
(Ampere.connection.smembers(key_for_has_many(to_s.downcase, self.id, field_name))).map do |id|
|
272
326
|
eval(klass_name.to_s.capitalize).find(id)
|
273
327
|
end
|
274
328
|
end
|
275
329
|
|
276
330
|
define_method(:"#{field_name}=") do |val|
|
277
331
|
val.each do |v|
|
278
|
-
Ampere.connection.sadd(
|
332
|
+
Ampere.connection.sadd(key_for_has_many(to_s.downcase, self.id, field_name), v.id)
|
279
333
|
# Set pointer for belongs_to
|
280
|
-
Ampere.connection.hset(v.id, "#{my_klass_name}_id", self.send("id"))
|
334
|
+
Ampere.connection.hset(key_for_find(v.class, v.id), "#{my_klass_name}_id", self.send("id"))
|
281
335
|
end
|
282
336
|
end
|
283
337
|
end
|
@@ -309,7 +363,11 @@ module Ampere
|
|
309
363
|
def indices
|
310
364
|
@indices
|
311
365
|
end
|
312
|
-
|
366
|
+
|
367
|
+
def last
|
368
|
+
all.last
|
369
|
+
end
|
370
|
+
|
313
371
|
def unique_indices
|
314
372
|
@unique_indices
|
315
373
|
end
|
@@ -328,11 +386,11 @@ module Ampere
|
|
328
386
|
unless indexed_fields.empty?
|
329
387
|
indexed_fields.map {|key|
|
330
388
|
if key.class == String or key.class == Symbol then
|
331
|
-
Ampere.connection.hget(
|
389
|
+
Ampere.connection.hget(key_for_index(key), options[key]).split(/:/) #.map {|id| find(id)}
|
332
390
|
else
|
333
391
|
# Compound index
|
334
392
|
Ampere.connection.hget(
|
335
|
-
|
393
|
+
key_for_index(key.join(':')),
|
336
394
|
key.map{|k| options[k]}.join(':')
|
337
395
|
).split(/:/) #.map {|id| find(id)}
|
338
396
|
end
|
@@ -364,11 +422,12 @@ module Ampere
|
|
364
422
|
|
365
423
|
private
|
366
424
|
|
367
|
-
def compound_indices_for(query)
|
425
|
+
def compound_indices_for(query) #:nodoc:
|
368
426
|
compound_indices.select{|ci|
|
369
427
|
(query.keys - ci).empty?
|
370
428
|
}
|
371
429
|
end
|
430
|
+
|
372
431
|
end
|
373
432
|
|
374
433
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Ampere
|
2
|
+
module Timestamps
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
field :created_at
|
6
|
+
field :updated_at
|
7
|
+
|
8
|
+
define_model_callbacks :create, :update, :save
|
9
|
+
|
10
|
+
before_create do
|
11
|
+
@updated_at = Time.now
|
12
|
+
if @created_at.nil? then
|
13
|
+
@created_at = Time.now
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
before_save do
|
18
|
+
@updated_at = Time.now
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/ampere.rb
CHANGED
@@ -3,26 +3,42 @@ require "active_record"
|
|
3
3
|
require "redis"
|
4
4
|
require "pp"
|
5
5
|
|
6
|
+
# The Ampere module contains methods to connect/disconnect and gives access to
|
7
|
+
# the Redis connection directly (though you really shouldn't need to use it).
|
6
8
|
module Ampere
|
7
9
|
@@connection = nil
|
8
10
|
|
11
|
+
# Open a new Redis connection. `options` is passed directly to the Redis.connect
|
12
|
+
# method.
|
9
13
|
def self.connect(options = {})
|
10
14
|
@@connection = Redis.connect(options)
|
11
15
|
end
|
12
16
|
|
17
|
+
# Closes the Redis connection.
|
13
18
|
def self.disconnect
|
14
19
|
return unless connected?
|
15
20
|
@@connection.quit
|
16
21
|
@@connection = nil
|
17
22
|
end
|
18
23
|
|
24
|
+
# Returns `true` if the Redis connection is active.
|
19
25
|
def self.connected?
|
20
26
|
!! @@connection
|
21
27
|
end
|
22
28
|
|
29
|
+
# Gives access to the Redis connection object.
|
23
30
|
def self.connection
|
24
31
|
@@connection
|
25
32
|
end
|
33
|
+
|
34
|
+
# Alias for Ampere.redis.flushall
|
35
|
+
def self.flush
|
36
|
+
@@connection.flushall if connected?
|
37
|
+
end
|
38
|
+
|
26
39
|
end
|
27
40
|
|
28
|
-
Dir[File.join(File.dirname(__FILE__), 'ampere', '**', '*.rb')].each {|f| require f}
|
41
|
+
Dir[File.join(File.dirname(__FILE__), 'ampere', '**', '*.rb')].each {|f| require f}
|
42
|
+
|
43
|
+
require File.join(File.dirname(__FILE__), "rails", "railtie.rb") if defined?(Rails)
|
44
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Ampere
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
desc "Installs a skeleton Ampere config file for you."
|
7
|
+
|
8
|
+
argument :prefix, :type => :string, :optional => true
|
9
|
+
|
10
|
+
def create_config_file
|
11
|
+
template 'ampere.yml', File.join('config', "ampere.yml")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Ampere #:nodoc:
|
2
|
+
module Generators #:nodoc:
|
3
|
+
class ModelGenerator < Rails::Generators::NamedBase #:nodoc:
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
desc "Creates an Ampere model"
|
7
|
+
argument :attributes, :type => :array, :default => [], :banner => "field field"
|
8
|
+
|
9
|
+
check_class_collision
|
10
|
+
|
11
|
+
def create_model_file
|
12
|
+
template "model.rb.tt", File.join("app/models", class_path, "#{file_name}.rb")
|
13
|
+
end
|
14
|
+
|
15
|
+
hook_for :test_framework
|
16
|
+
|
17
|
+
unless methods.include?(:module_namespacing)
|
18
|
+
|
19
|
+
# This is only defined on Rails edge at the moment, so include here now
|
20
|
+
# as per: https://github.com/mongoid/mongoid/issues/744
|
21
|
+
def module_namespacing(&block)
|
22
|
+
yield if block
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module Ampere
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
if config.respond_to?(:app_generators) then
|
6
|
+
config.app_generators.orm :ampere, :migration => false
|
7
|
+
else
|
8
|
+
config.generators.orm :ampere, :migration => false
|
9
|
+
end
|
10
|
+
|
11
|
+
console do
|
12
|
+
Ampere.connect
|
13
|
+
puts "[ampere] Connected."
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer 'railtie.initialize_redis_connection' do |app|
|
17
|
+
config_file = Rails.root.join("config", "ampere.yml")
|
18
|
+
|
19
|
+
options = {
|
20
|
+
'development' => {
|
21
|
+
'host' => '127.0.0.1',
|
22
|
+
'port' => 6379
|
23
|
+
},
|
24
|
+
'test' => {
|
25
|
+
'host' => '127.0.0.1',
|
26
|
+
'port' => 6379
|
27
|
+
},
|
28
|
+
'production' => {
|
29
|
+
'host' => '127.0.0.1',
|
30
|
+
'port' => 6379
|
31
|
+
},
|
32
|
+
}
|
33
|
+
|
34
|
+
if config_file.file?
|
35
|
+
options = YAML.load_file(config_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
Rails.logger.info "[ampere] Initializing redis connection redis://#{options[Rails.env]['host']}:#{options[Rails.env]['port']}"
|
39
|
+
|
40
|
+
Ampere.connect options[Rails.env]
|
41
|
+
end
|
42
|
+
|
43
|
+
rake_tasks do
|
44
|
+
load File.join(File.dirname(__FILE__), '..', 'rails', 'tasks', 'ampere.rake')
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/spec/models/model_spec.rb
CHANGED
@@ -177,7 +177,9 @@ describe "Base models", :model => true do
|
|
177
177
|
:content => "and it doesn't even make sense."
|
178
178
|
id = post.id
|
179
179
|
post.should_not be_nil
|
180
|
-
Post.delete(id)
|
180
|
+
deleted_post = Post.delete(id)
|
181
|
+
deleted_post.should eq(post)
|
182
|
+
deleted_post.title.should eq(post.title)
|
181
183
|
Post.find(id).should be_nil
|
182
184
|
end
|
183
185
|
|
@@ -186,7 +188,7 @@ describe "Base models", :model => true do
|
|
186
188
|
:byline => "Just seems like one big",
|
187
189
|
:content => "non sequitor."
|
188
190
|
id = another_post.id
|
189
|
-
another_post.destroy.should
|
191
|
+
another_post.destroy.should eq(another_post)
|
190
192
|
Post.find(id).should be_nil
|
191
193
|
end
|
192
194
|
|
@@ -207,9 +209,17 @@ describe "Base models", :model => true do
|
|
207
209
|
post = Post.create :title => "Another title",
|
208
210
|
:byline => "Max",
|
209
211
|
:content => "Some other content"
|
212
|
+
post.should be_persisted
|
210
213
|
Post.find(post.id).should == post
|
211
214
|
end
|
212
215
|
|
216
|
+
it "should return an integer for its ID" do
|
217
|
+
post = Post.create :title => "On Motorcycles and Robots",
|
218
|
+
:byline => "Max",
|
219
|
+
:content => "Motorcycles and robots are awesome"
|
220
|
+
post.id.should be_a(Fixnum)
|
221
|
+
end
|
222
|
+
|
213
223
|
# # #
|
214
224
|
|
215
225
|
after :all do
|
@@ -0,0 +1,45 @@
|
|
1
|
+
describe Ampere::Timestamps do
|
2
|
+
before :all do
|
3
|
+
Ampere.connect
|
4
|
+
|
5
|
+
Ampere.connection.flushall
|
6
|
+
|
7
|
+
class Comment
|
8
|
+
include Ampere::Model
|
9
|
+
include Ampere::Timestamps
|
10
|
+
|
11
|
+
field :body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when included in models' do
|
16
|
+
it 'sets created_at for newly-created record' do
|
17
|
+
Timecop.freeze(Time.now) do
|
18
|
+
time = Time.now
|
19
|
+
|
20
|
+
c = Comment.create body: "I am intrigued by your ideas, and would like to subscribe to your newsletter."
|
21
|
+
c.created_at.should eq(time)
|
22
|
+
c.updated_at.should eq(time)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets updated_at when changing records' do
|
27
|
+
c = Comment.create body: "I am intrigued by your ideas, and would like to subscribe to your newsletter."
|
28
|
+
created_at = c.created_at
|
29
|
+
|
30
|
+
time = 0
|
31
|
+
|
32
|
+
Timecop.freeze(Time.now + 30) do
|
33
|
+
time = Time.now
|
34
|
+
|
35
|
+
c.body = "Theodore Roosevelt riding a moose, therefore your argument is invalid."
|
36
|
+
c.save
|
37
|
+
end
|
38
|
+
|
39
|
+
c.updated_at.should eq(time)
|
40
|
+
c.created_at.should eq(created_at)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -72,6 +72,11 @@ describe 'Collections', :collections => true do
|
|
72
72
|
republicans.to_a.map(&:name).should == ["Ulysses S. Grant", "Abraham Lincoln"]
|
73
73
|
end
|
74
74
|
|
75
|
+
it 'should give its first and last elements non-lazily' do
|
76
|
+
President.first.name.should eq("Millard Fillmore")
|
77
|
+
President.last.name.should eq("Jimmy Carter")
|
78
|
+
end
|
79
|
+
|
75
80
|
###
|
76
81
|
|
77
82
|
after :all do
|