chimera 0.0.1
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/History.txt +4 -0
- data/Manifest.txt +57 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +114 -0
- data/Rakefile +30 -0
- data/doc/NOTES +11 -0
- data/doc/examples/config.yml +16 -0
- data/doc/redis6379.conf +132 -0
- data/lib/chimera.rb +33 -0
- data/lib/chimera/associations.rb +146 -0
- data/lib/chimera/attributes.rb +52 -0
- data/lib/chimera/base.rb +95 -0
- data/lib/chimera/config.rb +9 -0
- data/lib/chimera/error.rb +12 -0
- data/lib/chimera/finders.rb +49 -0
- data/lib/chimera/geo_indexes.rb +76 -0
- data/lib/chimera/indexes.rb +177 -0
- data/lib/chimera/persistence.rb +70 -0
- data/lib/chimera/redis_objects.rb +345 -0
- data/lib/redis.rb +373 -0
- data/lib/redis/counter.rb +94 -0
- data/lib/redis/dist_redis.rb +149 -0
- data/lib/redis/hash_ring.rb +135 -0
- data/lib/redis/helpers/core_commands.rb +46 -0
- data/lib/redis/helpers/serialize.rb +25 -0
- data/lib/redis/list.rb +122 -0
- data/lib/redis/lock.rb +83 -0
- data/lib/redis/objects.rb +100 -0
- data/lib/redis/objects/counters.rb +132 -0
- data/lib/redis/objects/lists.rb +45 -0
- data/lib/redis/objects/locks.rb +71 -0
- data/lib/redis/objects/sets.rb +46 -0
- data/lib/redis/objects/values.rb +56 -0
- data/lib/redis/pipeline.rb +21 -0
- data/lib/redis/set.rb +156 -0
- data/lib/redis/value.rb +35 -0
- data/lib/riak_raw.rb +100 -0
- data/lib/typhoeus.rb +55 -0
- data/lib/typhoeus/.gitignore +1 -0
- data/lib/typhoeus/easy.rb +253 -0
- data/lib/typhoeus/filter.rb +28 -0
- data/lib/typhoeus/hydra.rb +210 -0
- data/lib/typhoeus/multi.rb +34 -0
- data/lib/typhoeus/remote.rb +306 -0
- data/lib/typhoeus/remote_method.rb +108 -0
- data/lib/typhoeus/remote_proxy_object.rb +48 -0
- data/lib/typhoeus/request.rb +124 -0
- data/lib/typhoeus/response.rb +39 -0
- data/lib/typhoeus/service.rb +20 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/models.rb +49 -0
- data/test/test_chimera.rb +238 -0
- data/test/test_helper.rb +7 -0
- metadata +243 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Request
|
3
|
+
attr_accessor :method, :params, :body, :headers, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification
|
4
|
+
attr_reader :url
|
5
|
+
|
6
|
+
def initialize(url, options = {})
|
7
|
+
@method = options[:method] || :get
|
8
|
+
@params = options[:params]
|
9
|
+
@body = options[:body]
|
10
|
+
@timeout = options[:timeout]
|
11
|
+
@headers = options[:headers] || {}
|
12
|
+
@user_agent = options[:user_agent] || Typhoeus::USER_AGENT
|
13
|
+
@cache_timeout = options[:cache_timeout]
|
14
|
+
@follow_location = options[:follow_location]
|
15
|
+
@max_redirects = options[:max_redirects]
|
16
|
+
@proxy = options[:proxy]
|
17
|
+
@disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
|
18
|
+
|
19
|
+
if @method == :post
|
20
|
+
@url = url
|
21
|
+
else
|
22
|
+
@url = @params ? "#{url}?#{params_string}" : url
|
23
|
+
end
|
24
|
+
@on_complete = nil
|
25
|
+
@after_complete = nil
|
26
|
+
@handled_response = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def host
|
30
|
+
slash_location = @url.index('/', 8)
|
31
|
+
if slash_location
|
32
|
+
@url.slice(0, slash_location)
|
33
|
+
else
|
34
|
+
query_string_location = @url.index('?')
|
35
|
+
return query_string_location ? @url.slice(0, query_string_location) : @url
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def headers
|
40
|
+
@headers["User-Agent"] = @user_agent
|
41
|
+
@headers
|
42
|
+
end
|
43
|
+
|
44
|
+
def params_string
|
45
|
+
params.keys.sort.collect do |k|
|
46
|
+
value = params[k]
|
47
|
+
if value.is_a? Hash
|
48
|
+
value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
|
49
|
+
elsif value.is_a? Array
|
50
|
+
key = Rack::Utils.escape(k.to_s)
|
51
|
+
value.collect { |v| "#{key}=#{Rack::Utils.escape(v.to_s)}" }.join('&')
|
52
|
+
else
|
53
|
+
"#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(params[k].to_s)}"
|
54
|
+
end
|
55
|
+
end.flatten.join("&")
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_complete(&block)
|
59
|
+
@on_complete = block
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_complete=(proc)
|
63
|
+
@on_complete = proc
|
64
|
+
end
|
65
|
+
|
66
|
+
def after_complete(&block)
|
67
|
+
@after_complete = block
|
68
|
+
end
|
69
|
+
|
70
|
+
def after_complete=(proc)
|
71
|
+
@after_complete = proc
|
72
|
+
end
|
73
|
+
|
74
|
+
def call_handlers
|
75
|
+
if @on_complete
|
76
|
+
@handled_response = @on_complete.call(response)
|
77
|
+
call_after_complete
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def call_after_complete
|
82
|
+
@after_complete.call(@handled_response) if @after_complete
|
83
|
+
end
|
84
|
+
|
85
|
+
def handled_response=(val)
|
86
|
+
@handled_response = val
|
87
|
+
end
|
88
|
+
|
89
|
+
def handled_response
|
90
|
+
@handled_response || response
|
91
|
+
end
|
92
|
+
|
93
|
+
def cache_key
|
94
|
+
Digest::SHA1.hexdigest(url)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.run(url, params)
|
98
|
+
r = new(url, params)
|
99
|
+
Typhoeus::Hydra.hydra.queue r
|
100
|
+
Typhoeus::Hydra.hydra.run
|
101
|
+
r.response
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.get(url, params = {})
|
105
|
+
run(url, params.merge(:method => :get))
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.post(url, params = {})
|
109
|
+
run(url, params.merge(:method => :post))
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.put(url, params = {})
|
113
|
+
run(url, params.merge(:method => :put))
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.delete(url, params = {})
|
117
|
+
run(url, params.merge(:method => :delete))
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.head(url, params = {})
|
121
|
+
run(url, params.merge(:method => :head))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Response
|
3
|
+
attr_accessor :request
|
4
|
+
attr_reader :code, :headers, :body, :time,
|
5
|
+
:requested_url, :requested_remote_method,
|
6
|
+
:requested_http_method, :start_time
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@code = params[:code]
|
10
|
+
@headers = params[:headers]
|
11
|
+
@body = params[:body]
|
12
|
+
@time = params[:time]
|
13
|
+
@requested_url = params[:requested_url]
|
14
|
+
@requested_http_method = params[:requested_http_method]
|
15
|
+
@start_time = params[:start_time]
|
16
|
+
@request = params[:request]
|
17
|
+
end
|
18
|
+
|
19
|
+
def headers_hash
|
20
|
+
headers.split("\n").map {|o| o.strip}.inject({}) do |hash, o|
|
21
|
+
if o.empty?
|
22
|
+
hash
|
23
|
+
else
|
24
|
+
i = o.index(":") || o.size
|
25
|
+
key = o.slice(0, i)
|
26
|
+
value = o.slice(i + 1, o.size)
|
27
|
+
value = value.strip unless value.nil?
|
28
|
+
if hash.has_key? key
|
29
|
+
hash[key] = [hash[key], value].flatten
|
30
|
+
else
|
31
|
+
hash[key] = value
|
32
|
+
end
|
33
|
+
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Service
|
3
|
+
def initialize(host, port)
|
4
|
+
@host = host
|
5
|
+
@port = port
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(resource, params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def put(resource, params)
|
12
|
+
end
|
13
|
+
|
14
|
+
def post(resource, params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(resource, params)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/chimera.rb'}"
|
9
|
+
puts "Loading chimera gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/models.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
class User < Chimera::Base
|
2
|
+
use_config :default # this is implied even if not here
|
3
|
+
|
4
|
+
attribute :name
|
5
|
+
attribute :age
|
6
|
+
attribute :occupation
|
7
|
+
attribute :interests
|
8
|
+
attribute :home_coordinate # [37.2,122.1]
|
9
|
+
attribute :ssn
|
10
|
+
attribute :updated_at
|
11
|
+
attribute :favorite_car, :model, :class => :car
|
12
|
+
|
13
|
+
# User.find_with_index(:home_coordinate, {:coordinate => [37.2,122.1], :steps => 5})
|
14
|
+
index :home_coordinate, :type => :geo, :step_size => 0.05
|
15
|
+
|
16
|
+
# User.find_with_index(:occupation, { :q => "developer", :type => :intersect } ) # fuzzy search. :intersect or :union
|
17
|
+
index :occupation, :type => :search
|
18
|
+
|
19
|
+
# User.find_with_index(:ssn, "12345") # exact search, enforces unique constraint
|
20
|
+
index :ssn, :type => :unique
|
21
|
+
|
22
|
+
# User.find_with_index(:name, "Ben") # like :search but exact
|
23
|
+
index :name, :type => :find
|
24
|
+
|
25
|
+
association :friends, :user
|
26
|
+
association :cars, :car
|
27
|
+
|
28
|
+
redis_object :num_logins, :counter
|
29
|
+
|
30
|
+
validates_presence_of :name
|
31
|
+
end
|
32
|
+
|
33
|
+
class Car < Chimera::Base
|
34
|
+
attribute :color
|
35
|
+
attribute :make
|
36
|
+
attribute :model
|
37
|
+
attribute :year
|
38
|
+
attribute :mileage
|
39
|
+
attribute :comments
|
40
|
+
attribute :sku
|
41
|
+
attribute :curr_location
|
42
|
+
|
43
|
+
index :year, :type => :find
|
44
|
+
index :comments, :type => :search
|
45
|
+
index :sku, :type => :unique
|
46
|
+
index :curr_location, :type => :geo, :step_size => 0.05
|
47
|
+
|
48
|
+
validates_presence_of :make, :model, :year
|
49
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestChimera < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Car.each { |c| c.destroy }
|
6
|
+
Car.connection(:redis).flush_all
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_geo_indexes
|
10
|
+
c = Car.new
|
11
|
+
c.make = "Porsche"
|
12
|
+
c.model = "911"
|
13
|
+
c.year = 2010
|
14
|
+
c.sku = 1000
|
15
|
+
c.id = Car.new_uuid
|
16
|
+
c.curr_location = [37.12122, 121.43392]
|
17
|
+
assert c.save
|
18
|
+
|
19
|
+
c2 = Car.new
|
20
|
+
c2.make = "Toyota"
|
21
|
+
c2.model = "Hilux"
|
22
|
+
c2.year = 2010
|
23
|
+
c2.sku = 1001
|
24
|
+
c2.curr_location = [37.12222, 121.43792]
|
25
|
+
c2.id = Car.new_uuid
|
26
|
+
assert c2.save
|
27
|
+
|
28
|
+
found = Car.find_with_index(:curr_location, {:coordinate => [37.12222, 121.43792], :steps => 5})
|
29
|
+
assert_equal [c,c2].sort, found.sort
|
30
|
+
|
31
|
+
c2.curr_location = [38.0, 122.0]
|
32
|
+
assert c2.save
|
33
|
+
|
34
|
+
found = Car.find_with_index(:curr_location, {:coordinate => [37.12222, 121.43792], :steps => 5})
|
35
|
+
assert_equal [c].sort, found.sort
|
36
|
+
|
37
|
+
found = Car.find_with_index(:curr_location, {:coordinate => [38.0-0.05, 122.0+0.05], :steps => 5})
|
38
|
+
assert_equal [c2].sort, found.sort
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_search_indexes
|
42
|
+
c = Car.new
|
43
|
+
c.make = "Porsche"
|
44
|
+
c.model = "911"
|
45
|
+
c.year = 2010
|
46
|
+
c.sku = 1000
|
47
|
+
c.comments = "cat dog chicken dolphin whale panther"
|
48
|
+
c.id = Car.new_uuid
|
49
|
+
assert c.save
|
50
|
+
|
51
|
+
c2 = Car.new
|
52
|
+
c2.make = "Porsche"
|
53
|
+
c2.model = "911"
|
54
|
+
c2.year = 2010
|
55
|
+
c2.sku = 1001
|
56
|
+
c2.comments = "cat dog chicken"
|
57
|
+
c2.id = Car.new_uuid
|
58
|
+
assert c2.save
|
59
|
+
|
60
|
+
c3 = Car.new
|
61
|
+
c3.make = "Porsche"
|
62
|
+
c3.model = "911"
|
63
|
+
c3.year = 2010
|
64
|
+
c3.sku = 1002
|
65
|
+
c3.comments = "dog chicken dolphin whale"
|
66
|
+
c3.id = Car.new_uuid
|
67
|
+
assert c3.save
|
68
|
+
|
69
|
+
assert_equal [c,c2,c3].sort, Car.find_with_index(:comments, "dog").sort
|
70
|
+
assert_equal [c,c2].sort, Car.find_with_index(:comments, "cat").sort
|
71
|
+
assert_equal [c,c2].sort, Car.find_with_index(:comments, "cat").sort
|
72
|
+
|
73
|
+
assert_equal [c,c2,c3].sort, Car.find_with_index(:comments, {:q => "dog dolphin", :type => :union}).sort
|
74
|
+
assert_equal [c,c3].sort, Car.find_with_index(:comments, {:q => "dog dolphin", :type => :intersect}).sort
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_indexes
|
78
|
+
c = Car.new
|
79
|
+
c.make = "Nissan"
|
80
|
+
c.model = "RX7"
|
81
|
+
c.year = 2010
|
82
|
+
c.sku = 1001
|
83
|
+
c.comments = "really fast car. it's purple too!"
|
84
|
+
c.id = Car.new_uuid
|
85
|
+
assert c.save
|
86
|
+
|
87
|
+
assert !c.new?
|
88
|
+
|
89
|
+
assert_equal [c], Car.find_with_index(:comments, "fast")
|
90
|
+
assert_equal [c], Car.find_with_index(:comments, "purple")
|
91
|
+
assert_equal [], Car.find_with_index(:comments, "blue")
|
92
|
+
|
93
|
+
assert_equal [c], Car.find_with_index(:year, 2010)
|
94
|
+
assert_equal [c], Car.find_with_index(:sku, 1001)
|
95
|
+
|
96
|
+
c2 = Car.new
|
97
|
+
c2.make = "Honda"
|
98
|
+
c2.model = "Accord"
|
99
|
+
c2.year = 2010
|
100
|
+
c2.sku = 1001
|
101
|
+
c2.id = Car.new_uuid
|
102
|
+
assert_raise(Chimera::Error::UniqueConstraintViolation) { c2.save }
|
103
|
+
c2.sku = 1002
|
104
|
+
assert c2.save
|
105
|
+
|
106
|
+
c3 = Car.new
|
107
|
+
c3.make = "Honda"
|
108
|
+
c3.model = "Civic"
|
109
|
+
c3.year = 2010
|
110
|
+
c3.sku = 1003
|
111
|
+
c3.id = Car.new_uuid
|
112
|
+
assert c3.save
|
113
|
+
|
114
|
+
assert_equal 3, Car.find_with_index(:year, 2010).size
|
115
|
+
assert Car.find_with_index(:year, 2010).include?(c)
|
116
|
+
assert Car.find_with_index(:year, 2010).include?(c2)
|
117
|
+
assert Car.find_with_index(:year, 2010).include?(c3)
|
118
|
+
|
119
|
+
count = 0
|
120
|
+
Car.find_with_index(:all) { |car| count += 1 }
|
121
|
+
assert_equal 3, count
|
122
|
+
|
123
|
+
count = 0
|
124
|
+
Car.each { |car| count += 1 }
|
125
|
+
assert_equal 3, count
|
126
|
+
|
127
|
+
c2.destroy
|
128
|
+
|
129
|
+
count = 0
|
130
|
+
Car.find_with_index(:all) { |car| count += 1 }
|
131
|
+
assert_equal 2, count
|
132
|
+
|
133
|
+
count = 0
|
134
|
+
Car.each { |car| count += 1 }
|
135
|
+
assert_equal 2, count
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_associations
|
139
|
+
u = User.new
|
140
|
+
u.id = User.new_uuid
|
141
|
+
u.name = "Ben"
|
142
|
+
assert u.save
|
143
|
+
|
144
|
+
assert_equal 0, u.friends.size
|
145
|
+
|
146
|
+
chris = User.new
|
147
|
+
chris.id = User.new_uuid
|
148
|
+
chris.name = "Chris"
|
149
|
+
assert chris.save
|
150
|
+
|
151
|
+
assert_equal 0, u.friends.size
|
152
|
+
u.friends << chris
|
153
|
+
assert_equal 1, u.friends.size
|
154
|
+
chris.destroy
|
155
|
+
assert_equal 0, u.friends.size
|
156
|
+
|
157
|
+
c = Car.new
|
158
|
+
c.make = "Nissan"
|
159
|
+
c.model = "RX7"
|
160
|
+
c.year = 2010
|
161
|
+
c.sku = 1001
|
162
|
+
c.comments = "really fast car. it's purple too!"
|
163
|
+
c.id = Car.new_uuid
|
164
|
+
assert c.save
|
165
|
+
|
166
|
+
assert_equal 0, u.cars.size
|
167
|
+
u.cars << c
|
168
|
+
assert_equal 1, u.cars.size
|
169
|
+
assert_equal [c], u.cars.all
|
170
|
+
assert_equal 1, c.association_memberships.all_associations.size
|
171
|
+
u.cars.remove(c)
|
172
|
+
assert_equal 0, c.association_memberships.all_associations.size
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_model_attribute
|
176
|
+
u = User.new
|
177
|
+
u.id = User.new_uuid
|
178
|
+
u.name = "Ben"
|
179
|
+
assert u.save
|
180
|
+
assert_nil u.favorite_car
|
181
|
+
|
182
|
+
c = Car.new
|
183
|
+
c.make = "Nissan"
|
184
|
+
c.model = "RX7"
|
185
|
+
c.year = 2010
|
186
|
+
c.sku = 1001
|
187
|
+
c.comments = "really fast car. it's purple too!"
|
188
|
+
c.id = Car.new_uuid
|
189
|
+
assert c.save
|
190
|
+
|
191
|
+
u.favorite_car = c
|
192
|
+
assert u.save
|
193
|
+
assert_equal c, u.favorite_car
|
194
|
+
u = User.find(u.id)
|
195
|
+
assert_equal c, u.favorite_car
|
196
|
+
u.favorite_car = nil
|
197
|
+
assert u.save
|
198
|
+
assert_nil u.favorite_car
|
199
|
+
|
200
|
+
u.favorite_car = c
|
201
|
+
assert u.save
|
202
|
+
assert_equal c, u.favorite_car
|
203
|
+
c.destroy
|
204
|
+
assert_equal c, u.favorite_car
|
205
|
+
u = User.find(u.id)
|
206
|
+
assert_nil u.favorite_car
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_redis_objects
|
210
|
+
u = User.new
|
211
|
+
u.id = User.new_uuid
|
212
|
+
u.name = "Ben"
|
213
|
+
assert u.save
|
214
|
+
|
215
|
+
assert_equal false, User.connection(:redis).exists(u.num_logins.key)
|
216
|
+
assert_equal 0, u.num_logins.count
|
217
|
+
u.num_logins.incr
|
218
|
+
assert_equal 1, u.num_logins.count
|
219
|
+
assert_equal true, User.connection(:redis).exists(u.num_logins.key)
|
220
|
+
u.num_logins.incr_by 10
|
221
|
+
assert_equal 11, u.num_logins.count
|
222
|
+
|
223
|
+
u.destroy
|
224
|
+
|
225
|
+
assert_equal false, User.connection(:redis).exists(u.num_logins.key)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_rich_attributes
|
229
|
+
u = User.new
|
230
|
+
u.id = User.new_uuid
|
231
|
+
u.updated_at = Time.now.utc
|
232
|
+
assert u.updated_at.is_a?(Time)
|
233
|
+
u.name = "ben"
|
234
|
+
assert u.save
|
235
|
+
u = User.find(u.id)
|
236
|
+
assert u.updated_at.is_a?(Time)
|
237
|
+
end
|
238
|
+
end
|