toystore 0.8.3 → 0.9.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/.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
|