ampere 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|