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/caching.rb
CHANGED
@@ -2,19 +2,17 @@ module Toy
|
|
2
2
|
module Caching
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
cache_key
|
17
|
-
end
|
5
|
+
def cache_key(*suffixes)
|
6
|
+
cache_key = case
|
7
|
+
when new_record?
|
8
|
+
"#{self.class.name}:new"
|
9
|
+
when timestamp = self[:updated_at]
|
10
|
+
"#{self.class.name}:#{id}-#{timestamp.utc.to_s(:number)}"
|
11
|
+
else
|
12
|
+
"#{self.class.name}:#{id}"
|
13
|
+
end
|
14
|
+
cache_key += ":#{suffixes.join(':')}" unless suffixes.empty?
|
15
|
+
cache_key
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
data/lib/toy/callbacks.rb
CHANGED
@@ -8,41 +8,22 @@ module Toy
|
|
8
8
|
define_model_callbacks :save, :create, :update, :destroy
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def destroy
|
17
|
-
run_callbacks(:destroy) { super }
|
18
|
-
end
|
19
|
-
|
20
|
-
def run_callbacks(callback, &block)
|
21
|
-
callback = :create if callback == :update && !persisted?
|
22
|
-
|
23
|
-
embedded_records = self.class.embedded_lists.keys.inject([]) do |records, key|
|
24
|
-
records += send(key).target
|
25
|
-
end
|
11
|
+
def save(*)
|
12
|
+
run_callbacks(:save) { super }
|
13
|
+
end
|
26
14
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
31
|
-
chain
|
32
|
-
end
|
33
|
-
end
|
34
|
-
super callback, &block
|
35
|
-
end
|
15
|
+
def destroy
|
16
|
+
run_callbacks(:destroy) { super }
|
17
|
+
end
|
36
18
|
|
37
|
-
|
19
|
+
private
|
38
20
|
|
39
|
-
|
40
|
-
|
41
|
-
|
21
|
+
def create
|
22
|
+
run_callbacks(:create) { super }
|
23
|
+
end
|
42
24
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
25
|
+
def update
|
26
|
+
run_callbacks(:update) { super }
|
46
27
|
end
|
47
28
|
end
|
48
29
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Toy
|
2
|
+
module Cloneable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def initialize_copy(other)
|
6
|
+
instance_variables.each do |name|
|
7
|
+
instance_variable_set(name, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
@attributes = {}
|
11
|
+
|
12
|
+
other.attributes.except('id').each do |key, value|
|
13
|
+
value = value.duplicable? ? value.clone : value
|
14
|
+
send("#{key}=", value)
|
15
|
+
end
|
16
|
+
|
17
|
+
write_attribute(:id, self.class.next_key(self))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/toy/collection.rb
CHANGED
@@ -42,14 +42,15 @@ module Toy
|
|
42
42
|
alias :== :eql?
|
43
43
|
|
44
44
|
private
|
45
|
-
def proxy_class
|
46
|
-
raise('Not Implemented')
|
47
|
-
end
|
48
45
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
def proxy_class
|
47
|
+
raise('Not Implemented')
|
48
|
+
end
|
49
|
+
|
50
|
+
def modularized_extensions(*extensions)
|
51
|
+
extensions.flatten.compact.map do |extension|
|
52
|
+
Proc === extension ? Module.new(&extension) : extension
|
53
53
|
end
|
54
|
+
end
|
54
55
|
end
|
55
56
|
end
|
data/lib/toy/dirty.rb
CHANGED
@@ -2,46 +2,27 @@ module Toy
|
|
2
2
|
module Dirty
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
include ActiveModel::Dirty
|
5
|
+
include Attributes
|
6
|
+
include Cloneable
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@changed_attributes.delete('id')
|
12
|
-
else
|
13
|
-
@previously_changed = {}
|
14
|
-
@changed_attributes.clear if @changed_attributes
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize_copy(*)
|
19
|
-
super.tap do
|
20
|
-
@previously_changed = {}
|
21
|
-
@changed_attributes = {}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def reload
|
26
|
-
super.tap do
|
27
|
-
@previously_changed = {}
|
28
|
-
@changed_attributes = {}
|
29
|
-
end
|
30
|
-
end
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
# never register initial id assignment as a change
|
11
|
+
@changed_attributes.delete('id') if @changed_attributes
|
12
|
+
end
|
31
13
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
14
|
+
def initialize_copy(*)
|
15
|
+
super.tap do
|
16
|
+
@previously_changed = {}
|
17
|
+
@changed_attributes = {}
|
37
18
|
end
|
19
|
+
end
|
38
20
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
21
|
+
def write_attribute(name, value)
|
22
|
+
name = name.to_s
|
23
|
+
current = read_attribute(name)
|
24
|
+
attribute_will_change!(name) if current != value
|
25
|
+
super
|
45
26
|
end
|
46
27
|
end
|
47
28
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Toy
|
2
|
+
module DirtyStore
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveModel::Dirty
|
5
|
+
include Reloadable
|
6
|
+
include Persistence
|
7
|
+
include Querying
|
8
|
+
|
9
|
+
def initialize_from_database(*)
|
10
|
+
super
|
11
|
+
|
12
|
+
@previously_changed = {}
|
13
|
+
@changed_attributes.clear if @changed_attributes
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def reload
|
19
|
+
super.tap do
|
20
|
+
@previously_changed = {}
|
21
|
+
@changed_attributes = {}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def save(*)
|
26
|
+
super.tap do
|
27
|
+
@previously_changed = changes
|
28
|
+
@changed_attributes.clear if @changed_attributes
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/toy/equality.rb
CHANGED
@@ -2,24 +2,28 @@ module Toy
|
|
2
2
|
module Extensions
|
3
3
|
module Boolean
|
4
4
|
Mapping = {
|
5
|
-
true => true,
|
6
|
-
'true' => true,
|
7
|
-
'TRUE' => true,
|
8
|
-
'True' => true,
|
9
|
-
't' => true,
|
10
|
-
'T' => true,
|
11
|
-
'1' => true,
|
12
|
-
|
5
|
+
true => true,
|
6
|
+
'true' => true,
|
7
|
+
'TRUE' => true,
|
8
|
+
'True' => true,
|
9
|
+
't' => true,
|
10
|
+
'T' => true,
|
11
|
+
'1' => true,
|
12
|
+
'on' => true,
|
13
|
+
'ON' => true,
|
14
|
+
1 => true,
|
13
15
|
1.0 => true,
|
14
|
-
false => false,
|
15
|
-
'false' => false,
|
16
|
-
'FALSE' => false,
|
17
|
-
'False' => false,
|
18
|
-
'f' => false,
|
19
|
-
'F' => false,
|
20
|
-
'0' => false,
|
21
|
-
|
22
|
-
|
16
|
+
false => false,
|
17
|
+
'false' => false,
|
18
|
+
'FALSE' => false,
|
19
|
+
'False' => false,
|
20
|
+
'f' => false,
|
21
|
+
'F' => false,
|
22
|
+
'0' => false,
|
23
|
+
'off' => false,
|
24
|
+
'OFF' => false,
|
25
|
+
0 => false,
|
26
|
+
0.0 => false,
|
23
27
|
nil => nil
|
24
28
|
}
|
25
29
|
|
@@ -32,7 +36,7 @@ module Toy
|
|
32
36
|
end
|
33
37
|
|
34
38
|
def from_store(value, *)
|
35
|
-
value
|
39
|
+
to_store(value)
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
data/lib/toy/identity_map.rb
CHANGED
@@ -1,62 +1,62 @@
|
|
1
1
|
module Toy
|
2
|
-
def self.identity_map
|
3
|
-
Thread.current[:toystore_identity_map] ||= {}
|
4
|
-
end
|
5
2
|
|
6
3
|
module IdentityMap
|
7
4
|
extend ActiveSupport::Concern
|
8
5
|
|
9
|
-
|
10
|
-
|
6
|
+
def self.enabled=(flag)
|
7
|
+
Thread.current[:toystore_identity_map_enabled] = flag
|
11
8
|
end
|
12
9
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
10
|
+
def self.enabled
|
11
|
+
Thread.current[:toystore_identity_map_enabled]
|
12
|
+
end
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
def self.enabled?
|
15
|
+
enabled == true
|
16
|
+
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def self.repository
|
19
|
+
Thread.current[:toystore_identity_map] ||= {}
|
20
|
+
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
def self.clear
|
23
|
+
repository.clear
|
24
|
+
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def self.include?(object)
|
27
|
+
repository.keys.include?(object.id)
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
original_identity_map_on = @identity_map_on
|
37
|
-
identity_map_off
|
38
|
-
yield
|
39
|
-
ensure
|
40
|
-
@identity_map_on = original_identity_map_on
|
41
|
-
end
|
42
|
-
end
|
30
|
+
def self.use
|
31
|
+
old, self.enabled = enabled, true
|
43
32
|
|
33
|
+
yield if block_given?
|
34
|
+
ensure
|
35
|
+
self.enabled = old
|
36
|
+
clear
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.without
|
40
|
+
old, self.enabled = enabled, false
|
41
|
+
|
42
|
+
yield if block_given?
|
43
|
+
ensure
|
44
|
+
self.enabled = old
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
44
48
|
def get(id)
|
45
49
|
get_from_identity_map(id) || super
|
46
50
|
end
|
47
51
|
|
48
52
|
def get_from_identity_map(id)
|
49
|
-
|
50
|
-
if record = identity_map[id]
|
51
|
-
log_operation(:img, self.name, store, id)
|
52
|
-
record
|
53
|
-
end
|
53
|
+
IdentityMap.repository[id] if IdentityMap.enabled?
|
54
54
|
end
|
55
55
|
|
56
56
|
def load(id, attrs)
|
57
57
|
return nil if attrs.nil?
|
58
58
|
|
59
|
-
if instance =
|
59
|
+
if IdentityMap.enabled? && instance = IdentityMap.repository[id]
|
60
60
|
instance
|
61
61
|
else
|
62
62
|
super.tap { |doc| doc.add_to_identity_map }
|
@@ -64,14 +64,8 @@ module Toy
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def identity_map
|
68
|
-
Toy.identity_map
|
69
|
-
end
|
70
|
-
|
71
67
|
def save(*)
|
72
|
-
super.tap
|
73
|
-
add_to_identity_map if result
|
74
|
-
end
|
68
|
+
super.tap { |result| add_to_identity_map if result }
|
75
69
|
end
|
76
70
|
|
77
71
|
def delete(*)
|
@@ -79,28 +73,11 @@ module Toy
|
|
79
73
|
end
|
80
74
|
|
81
75
|
def add_to_identity_map
|
82
|
-
|
83
|
-
identity_map[id] = self
|
84
|
-
log_operation(:ims, self.class.name, store, id)
|
76
|
+
IdentityMap.repository[id] = self if IdentityMap.enabled?
|
85
77
|
end
|
86
78
|
|
87
79
|
def remove_from_identity_map
|
88
|
-
|
89
|
-
identity_map.delete(id)
|
90
|
-
log_operation(:imd, self.class.name, store, id)
|
80
|
+
IdentityMap.repository.delete(id) if IdentityMap.enabled?
|
91
81
|
end
|
92
|
-
|
93
|
-
private
|
94
|
-
def has_embedded_objects?
|
95
|
-
self.class.embedded_lists.any?
|
96
|
-
end
|
97
|
-
|
98
|
-
def each_embedded_object(&block)
|
99
|
-
if has_embedded_objects?
|
100
|
-
self.class.embedded_lists.keys.inject([]) do |objects, name|
|
101
|
-
objects.concat(send(name).to_a.compact)
|
102
|
-
end.each { |object| block.call(object) }
|
103
|
-
end
|
104
|
-
end
|
105
82
|
end
|
106
83
|
end
|
data/lib/toy/list.rb
CHANGED
@@ -14,33 +14,34 @@ module Toy
|
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
|
-
def proxy_class
|
18
|
-
Toy::Proxies::List
|
19
|
-
end
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
def proxy_class
|
19
|
+
Toy::Proxies::List
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#{instance_variable} ||= self.class.#{list_method}[:#{name}].new_proxy(self)
|
29
|
-
end
|
22
|
+
def list_method
|
23
|
+
:lists
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
def create_accessors
|
27
|
+
model.class_eval """
|
28
|
+
def #{name}
|
29
|
+
#{instance_variable} ||= self.class.#{list_method}[:#{name}].new_proxy(self)
|
30
|
+
end
|
35
31
|
|
36
|
-
|
37
|
-
|
38
|
-
after_destroy :destroy_#{name}
|
39
|
-
def destroy_#{name}
|
40
|
-
#{name}.each { |o| o.destroy }
|
41
|
-
end
|
42
|
-
"""
|
32
|
+
def #{name}=(records)
|
33
|
+
#{name}.replace(records)
|
43
34
|
end
|
35
|
+
"""
|
36
|
+
|
37
|
+
if options[:dependent]
|
38
|
+
model.class_eval """
|
39
|
+
after_destroy :destroy_#{name}
|
40
|
+
def destroy_#{name}
|
41
|
+
#{name}.each { |o| o.destroy }
|
42
|
+
end
|
43
|
+
"""
|
44
44
|
end
|
45
|
+
end
|
45
46
|
end
|
46
47
|
end
|