toystore 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -2
- data/Changelog.md +9 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +71 -0
- data/Guardfile +15 -0
- data/README.md +28 -0
- data/examples/attributes_abbreviation.rb +1 -2
- data/examples/attributes_virtual.rb +1 -2
- data/examples/identity_map.rb +7 -12
- data/examples/memcached.rb +1 -1
- data/examples/memory.rb +1 -1
- data/examples/mongo.rb +1 -1
- data/examples/redis.rb +1 -1
- data/examples/riak.rb +1 -1
- data/lib/toy.rb +40 -39
- data/lib/toy/attribute.rb +1 -6
- data/lib/toy/attributes.rb +61 -90
- data/lib/toy/caching.rb +11 -13
- data/lib/toy/callbacks.rb +12 -31
- data/lib/toy/cloneable.rb +20 -0
- data/lib/toy/collection.rb +8 -7
- data/lib/toy/dirty.rb +17 -36
- data/lib/toy/dirty_store.rb +32 -0
- data/lib/toy/equality.rb +2 -0
- data/lib/toy/extensions/boolean.rb +22 -18
- data/lib/toy/identity_map.rb +39 -62
- data/lib/toy/list.rb +23 -22
- data/lib/toy/logger.rb +2 -17
- data/lib/toy/mass_assignment_security.rb +3 -5
- data/lib/toy/middleware/identity_map.rb +23 -4
- data/lib/toy/object.rb +16 -0
- data/lib/toy/persistence.rb +72 -62
- data/lib/toy/proxies/list.rb +19 -18
- data/lib/toy/proxies/proxy.rb +7 -6
- data/lib/toy/querying.rb +2 -4
- data/lib/toy/reference.rb +28 -26
- data/lib/toy/reloadable.rb +17 -0
- data/lib/toy/serialization.rb +25 -25
- data/lib/toy/store.rb +3 -11
- data/lib/toy/validations.rb +9 -28
- data/lib/toy/version.rb +1 -1
- data/perf/reads.rb +7 -9
- data/perf/writes.rb +6 -8
- data/spec/helper.rb +3 -1
- data/spec/support/constants.rb +1 -4
- data/spec/support/identity_map_matcher.rb +5 -5
- data/spec/support/objects.rb +38 -0
- data/spec/toy/attribute_spec.rb +1 -1
- data/spec/toy/attributes_spec.rb +1 -153
- data/spec/toy/callbacks_spec.rb +1 -45
- data/spec/toy/cloneable_spec.rb +47 -0
- data/spec/toy/dirty_spec.rb +12 -44
- data/spec/toy/dirty_store_spec.rb +47 -0
- data/spec/toy/equality_spec.rb +5 -19
- data/spec/toy/extensions/boolean_spec.rb +2 -0
- data/spec/toy/identity/uuid_key_factory_spec.rb +2 -2
- data/spec/toy/identity_map_spec.rb +45 -37
- data/spec/toy/identity_spec.rb +1 -1
- data/spec/toy/inspect_spec.rb +1 -1
- data/spec/toy/lists_spec.rb +20 -5
- data/spec/toy/logger_spec.rb +1 -29
- data/spec/toy/mass_assignment_security_spec.rb +16 -5
- data/spec/toy/middleware/identity_map_spec.rb +68 -2
- data/spec/toy/persistence_spec.rb +88 -30
- data/spec/toy/reference_spec.rb +0 -1
- data/spec/toy/references_spec.rb +20 -0
- data/spec/toy/reloadable_spec.rb +81 -0
- data/spec/toy/serialization_spec.rb +1 -110
- data/spec/toy/validations_spec.rb +0 -21
- data/spec/toy_spec.rb +4 -5
- data/test/lint_test.rb +1 -1
- metadata +21 -26
- data/.autotest +0 -11
- data/LOGGING.rdoc +0 -12
- data/README.rdoc +0 -27
- data/examples/models.rb +0 -51
- data/lib/toy/dolly.rb +0 -30
- data/lib/toy/embedded_list.rb +0 -45
- data/lib/toy/embedded_lists.rb +0 -68
- data/lib/toy/index.rb +0 -74
- data/lib/toy/indices.rb +0 -56
- data/lib/toy/proxies/embedded_list.rb +0 -79
- data/spec/toy/dolly_spec.rb +0 -76
- data/spec/toy/embedded_list_spec.rb +0 -607
- data/spec/toy/embedded_lists_spec.rb +0 -172
- data/spec/toy/index_spec.rb +0 -230
- data/spec/toy/indices_spec.rb +0 -141
- data/specs.watchr +0 -52
data/lib/toy/logger.rb
CHANGED
@@ -3,28 +3,13 @@ module Toy
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
OperationsToLogValueFor = [:get, :set, :del]
|
7
|
-
|
8
6
|
def logger
|
9
7
|
Toy.logger
|
10
8
|
end
|
11
|
-
|
12
|
-
def log_operation(operation, model, adapter, key, value=nil)
|
13
|
-
if logger && logger.debug?
|
14
|
-
logger.debug("TOYSTORE #{operation.to_s.upcase} #{model} :#{adapter.name} #{key.inspect}")
|
15
|
-
logger.debug(" #{value.inspect}") if !value.nil? && OperationsToLogValueFor.include?(operation)
|
16
|
-
end
|
17
|
-
end
|
18
9
|
end
|
19
10
|
|
20
|
-
|
21
|
-
|
22
|
-
Toy.logger
|
23
|
-
end
|
24
|
-
|
25
|
-
def log_operation(*args)
|
26
|
-
self.class.log_operation(*args)
|
27
|
-
end
|
11
|
+
def logger
|
12
|
+
Toy.logger
|
28
13
|
end
|
29
14
|
end
|
30
15
|
end
|
@@ -3,11 +3,9 @@ module Toy
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
include ActiveModel::MassAssignmentSecurity
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
super(attrs)
|
10
|
-
end
|
6
|
+
def attributes=(attrs, guard_protected_attributes=true)
|
7
|
+
attrs = sanitize_for_mass_assignment(attrs || {}) if guard_protected_attributes
|
8
|
+
super(attrs)
|
11
9
|
end
|
12
10
|
end
|
13
11
|
end
|
@@ -1,15 +1,34 @@
|
|
1
1
|
module Toy
|
2
2
|
module Middleware
|
3
3
|
class IdentityMap
|
4
|
+
class Body
|
5
|
+
def initialize(target, original)
|
6
|
+
@target = target
|
7
|
+
@original = original
|
8
|
+
end
|
9
|
+
|
10
|
+
def each(&block)
|
11
|
+
@target.each(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
@target.close if @target.respond_to?(:close)
|
16
|
+
ensure
|
17
|
+
Toy::IdentityMap.enabled = @original
|
18
|
+
Toy::IdentityMap.clear
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
4
22
|
def initialize(app)
|
5
23
|
@app = app
|
6
24
|
end
|
7
25
|
|
8
26
|
def call(env)
|
9
|
-
Toy.
|
10
|
-
|
11
|
-
|
12
|
-
|
27
|
+
Toy::IdentityMap.clear
|
28
|
+
enabled = Toy::IdentityMap.enabled
|
29
|
+
Toy::IdentityMap.enabled = true
|
30
|
+
status, headers, body = @app.call(env)
|
31
|
+
[status, headers, Body.new(body, enabled)]
|
13
32
|
end
|
14
33
|
end
|
15
34
|
end
|
data/lib/toy/object.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Toy
|
2
|
+
module Object
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend ActiveModel::Naming
|
7
|
+
include ActiveModel::Conversion
|
8
|
+
include Attributes
|
9
|
+
include Cloneable
|
10
|
+
include Dirty
|
11
|
+
include Equality
|
12
|
+
include Inspect
|
13
|
+
include Logger
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/toy/persistence.rb
CHANGED
@@ -3,15 +3,20 @@ module Toy
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
def adapter(name=nil, client=nil, options={})
|
7
|
+
missing_client = !name.nil? && client.nil?
|
8
|
+
raise(ArgumentError, 'Client is required') if missing_client
|
9
|
+
|
10
|
+
needs_default_adapter = name.nil? && client.nil?
|
11
|
+
assigning_adapter = !name.nil? && !client.nil?
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
if needs_default_adapter
|
14
|
+
@adapter ||= Adapter[:memory].new({}, options)
|
15
|
+
elsif assigning_adapter
|
16
|
+
@adapter = Adapter[name].new(client, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
@adapter
|
15
20
|
end
|
16
21
|
|
17
22
|
def create(attrs={})
|
@@ -25,75 +30,80 @@ module Toy
|
|
25
30
|
def destroy(*ids)
|
26
31
|
ids.each { |id| get(id).try(:destroy) }
|
27
32
|
end
|
33
|
+
end
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
35
|
+
def adapter
|
36
|
+
self.class.adapter
|
37
|
+
end
|
33
38
|
|
34
|
-
|
35
|
-
|
36
|
-
|
39
|
+
def initialize(attrs={})
|
40
|
+
@_new_record = true
|
41
|
+
super
|
37
42
|
end
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
def initialize_from_database(attrs={})
|
45
|
+
@_new_record = false
|
46
|
+
initialize_attributes_with_defaults
|
47
|
+
send("attributes=", attrs, false)
|
48
|
+
self
|
49
|
+
end
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
def initialize_copy(other)
|
52
|
+
super
|
53
|
+
@_new_record = true
|
54
|
+
@_destroyed = false
|
55
|
+
end
|
47
56
|
|
48
|
-
|
49
|
-
|
50
|
-
|
57
|
+
def new_record?
|
58
|
+
@_new_record == true
|
59
|
+
end
|
51
60
|
|
52
|
-
|
53
|
-
|
54
|
-
|
61
|
+
def destroyed?
|
62
|
+
@_destroyed == true
|
63
|
+
end
|
55
64
|
|
56
|
-
|
57
|
-
|
58
|
-
|
65
|
+
def persisted?
|
66
|
+
!new_record? && !destroyed?
|
67
|
+
end
|
59
68
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
69
|
+
def save(*)
|
70
|
+
new_record? ? create : update
|
71
|
+
end
|
64
72
|
|
65
|
-
|
66
|
-
|
67
|
-
|
73
|
+
def update_attributes(attrs)
|
74
|
+
self.attributes = attrs
|
75
|
+
save
|
76
|
+
end
|
68
77
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
store.delete(id)
|
73
|
-
end
|
78
|
+
def destroy
|
79
|
+
delete
|
80
|
+
end
|
74
81
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
82
|
+
def delete
|
83
|
+
@_destroyed = true
|
84
|
+
adapter.delete(id)
|
85
|
+
end
|
79
86
|
|
80
|
-
|
81
|
-
persist!
|
82
|
-
end
|
87
|
+
private
|
83
88
|
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
def create
|
90
|
+
persist!
|
91
|
+
end
|
87
92
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
def update
|
94
|
+
persist!
|
95
|
+
end
|
96
|
+
|
97
|
+
def persist
|
98
|
+
@_new_record = false
|
99
|
+
end
|
100
|
+
|
101
|
+
def persist!
|
102
|
+
attrs = persisted_attributes
|
103
|
+
attrs.delete('id') # no need to persist id as that is key
|
104
|
+
adapter.write(id, attrs)
|
105
|
+
persist
|
106
|
+
true
|
97
107
|
end
|
98
108
|
end
|
99
109
|
end
|
data/lib/toy/proxies/list.rb
CHANGED
@@ -70,28 +70,29 @@ module Toy
|
|
70
70
|
end
|
71
71
|
|
72
72
|
private
|
73
|
-
def find_target
|
74
|
-
return [] if target_ids.blank?
|
75
|
-
proxy_class.get_multi(target_ids)
|
76
|
-
end
|
77
73
|
|
78
|
-
|
79
|
-
|
80
|
-
|
74
|
+
def find_target
|
75
|
+
return [] if target_ids.blank?
|
76
|
+
proxy_class.get_multi(target_ids)
|
77
|
+
end
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
79
|
+
def target_ids
|
80
|
+
proxy_owner.send(proxy_key)
|
81
|
+
end
|
82
|
+
|
83
|
+
def target_ids=(value)
|
84
|
+
ids = value.map do |item|
|
85
|
+
if item.is_a?(proxy_class)
|
86
|
+
item.id
|
87
|
+
elsif item.is_a?(Hash)
|
88
|
+
item['id']
|
89
|
+
else
|
90
|
+
item
|
91
91
|
end
|
92
|
-
proxy_owner.send(:"#{proxy_key}=", ids)
|
93
|
-
reset
|
94
92
|
end
|
93
|
+
proxy_owner.send(:"#{proxy_key}=", ids)
|
94
|
+
reset
|
95
|
+
end
|
95
96
|
end
|
96
97
|
end
|
97
98
|
end
|
data/lib/toy/proxies/proxy.rb
CHANGED
@@ -47,13 +47,14 @@ module Toy
|
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
50
|
-
def find_target
|
51
|
-
raise('Not Implemented')
|
52
|
-
end
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
51
|
+
def find_target
|
52
|
+
raise('Not Implemented')
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method, *args, &block)
|
56
|
+
target.send(method, *args, &block)
|
57
|
+
end
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
data/lib/toy/querying.rb
CHANGED
@@ -4,8 +4,7 @@ module Toy
|
|
4
4
|
|
5
5
|
module ClassMethods
|
6
6
|
def get(id)
|
7
|
-
|
8
|
-
load(id, store.read(id))
|
7
|
+
load(id, adapter.read(id))
|
9
8
|
end
|
10
9
|
|
11
10
|
def get!(id)
|
@@ -25,8 +24,7 @@ module Toy
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def key?(id)
|
28
|
-
|
29
|
-
store.key?(id)
|
27
|
+
adapter.key?(id)
|
30
28
|
end
|
31
29
|
alias :has_key? :key?
|
32
30
|
|
data/lib/toy/reference.rb
CHANGED
@@ -95,40 +95,42 @@ module Toy
|
|
95
95
|
end
|
96
96
|
|
97
97
|
private
|
98
|
-
def assert_type(record)
|
99
|
-
unless record.instance_of?(proxy_class)
|
100
|
-
raise(ArgumentError, "#{proxy_class} expected, but was #{record.class}")
|
101
|
-
end
|
102
|
-
end
|
103
98
|
|
104
|
-
|
105
|
-
|
99
|
+
def assert_type(record)
|
100
|
+
unless record.instance_of?(proxy_class)
|
101
|
+
raise(ArgumentError, "#{proxy_class} expected, but was #{record.class}")
|
106
102
|
end
|
103
|
+
end
|
107
104
|
|
108
|
-
|
109
|
-
|
110
|
-
|
105
|
+
def target_id
|
106
|
+
proxy_owner.send(proxy_key)
|
107
|
+
end
|
111
108
|
|
112
|
-
|
113
|
-
|
114
|
-
|
109
|
+
def target_id=(value)
|
110
|
+
proxy_owner.send("#{proxy_key}=", value)
|
111
|
+
end
|
112
|
+
|
113
|
+
def method_missing(method, *args, &block)
|
114
|
+
target.send(method, *args, &block)
|
115
|
+
end
|
115
116
|
end
|
116
117
|
|
117
118
|
private
|
118
|
-
def create_accessors
|
119
|
-
model.class_eval """
|
120
|
-
def #{name}
|
121
|
-
#{instance_variable} ||= self.class.references[:#{name}].new_proxy(self)
|
122
|
-
end
|
123
119
|
|
124
|
-
|
125
|
-
|
126
|
-
|
120
|
+
def create_accessors
|
121
|
+
model.class_eval """
|
122
|
+
def #{name}
|
123
|
+
#{instance_variable} ||= self.class.references[:#{name}].new_proxy(self)
|
124
|
+
end
|
127
125
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
126
|
+
def #{name}=(record)
|
127
|
+
#{name}.replace(record)
|
128
|
+
end
|
129
|
+
|
130
|
+
def #{name}?
|
131
|
+
#{name}.present?
|
132
|
+
end
|
133
|
+
"""
|
134
|
+
end
|
133
135
|
end
|
134
136
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Toy
|
2
|
+
module Reloadable
|
3
|
+
def reload
|
4
|
+
if attrs = adapter.read(id)
|
5
|
+
attrs['id'] = id
|
6
|
+
instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
|
7
|
+
initialize_attributes_with_defaults
|
8
|
+
send(:attributes=, attrs, new_record?)
|
9
|
+
self.class.lists.each_key { |name| send(name).reset }
|
10
|
+
self.class.references.each_key { |name| send(name).reset }
|
11
|
+
else
|
12
|
+
raise NotFound.new(id)
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|