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.
Files changed (88) hide show
  1. data/.gitignore +1 -2
  2. data/Changelog.md +9 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +71 -0
  5. data/Guardfile +15 -0
  6. data/README.md +28 -0
  7. data/examples/attributes_abbreviation.rb +1 -2
  8. data/examples/attributes_virtual.rb +1 -2
  9. data/examples/identity_map.rb +7 -12
  10. data/examples/memcached.rb +1 -1
  11. data/examples/memory.rb +1 -1
  12. data/examples/mongo.rb +1 -1
  13. data/examples/redis.rb +1 -1
  14. data/examples/riak.rb +1 -1
  15. data/lib/toy.rb +40 -39
  16. data/lib/toy/attribute.rb +1 -6
  17. data/lib/toy/attributes.rb +61 -90
  18. data/lib/toy/caching.rb +11 -13
  19. data/lib/toy/callbacks.rb +12 -31
  20. data/lib/toy/cloneable.rb +20 -0
  21. data/lib/toy/collection.rb +8 -7
  22. data/lib/toy/dirty.rb +17 -36
  23. data/lib/toy/dirty_store.rb +32 -0
  24. data/lib/toy/equality.rb +2 -0
  25. data/lib/toy/extensions/boolean.rb +22 -18
  26. data/lib/toy/identity_map.rb +39 -62
  27. data/lib/toy/list.rb +23 -22
  28. data/lib/toy/logger.rb +2 -17
  29. data/lib/toy/mass_assignment_security.rb +3 -5
  30. data/lib/toy/middleware/identity_map.rb +23 -4
  31. data/lib/toy/object.rb +16 -0
  32. data/lib/toy/persistence.rb +72 -62
  33. data/lib/toy/proxies/list.rb +19 -18
  34. data/lib/toy/proxies/proxy.rb +7 -6
  35. data/lib/toy/querying.rb +2 -4
  36. data/lib/toy/reference.rb +28 -26
  37. data/lib/toy/reloadable.rb +17 -0
  38. data/lib/toy/serialization.rb +25 -25
  39. data/lib/toy/store.rb +3 -11
  40. data/lib/toy/validations.rb +9 -28
  41. data/lib/toy/version.rb +1 -1
  42. data/perf/reads.rb +7 -9
  43. data/perf/writes.rb +6 -8
  44. data/spec/helper.rb +3 -1
  45. data/spec/support/constants.rb +1 -4
  46. data/spec/support/identity_map_matcher.rb +5 -5
  47. data/spec/support/objects.rb +38 -0
  48. data/spec/toy/attribute_spec.rb +1 -1
  49. data/spec/toy/attributes_spec.rb +1 -153
  50. data/spec/toy/callbacks_spec.rb +1 -45
  51. data/spec/toy/cloneable_spec.rb +47 -0
  52. data/spec/toy/dirty_spec.rb +12 -44
  53. data/spec/toy/dirty_store_spec.rb +47 -0
  54. data/spec/toy/equality_spec.rb +5 -19
  55. data/spec/toy/extensions/boolean_spec.rb +2 -0
  56. data/spec/toy/identity/uuid_key_factory_spec.rb +2 -2
  57. data/spec/toy/identity_map_spec.rb +45 -37
  58. data/spec/toy/identity_spec.rb +1 -1
  59. data/spec/toy/inspect_spec.rb +1 -1
  60. data/spec/toy/lists_spec.rb +20 -5
  61. data/spec/toy/logger_spec.rb +1 -29
  62. data/spec/toy/mass_assignment_security_spec.rb +16 -5
  63. data/spec/toy/middleware/identity_map_spec.rb +68 -2
  64. data/spec/toy/persistence_spec.rb +88 -30
  65. data/spec/toy/reference_spec.rb +0 -1
  66. data/spec/toy/references_spec.rb +20 -0
  67. data/spec/toy/reloadable_spec.rb +81 -0
  68. data/spec/toy/serialization_spec.rb +1 -110
  69. data/spec/toy/validations_spec.rb +0 -21
  70. data/spec/toy_spec.rb +4 -5
  71. data/test/lint_test.rb +1 -1
  72. metadata +21 -26
  73. data/.autotest +0 -11
  74. data/LOGGING.rdoc +0 -12
  75. data/README.rdoc +0 -27
  76. data/examples/models.rb +0 -51
  77. data/lib/toy/dolly.rb +0 -30
  78. data/lib/toy/embedded_list.rb +0 -45
  79. data/lib/toy/embedded_lists.rb +0 -68
  80. data/lib/toy/index.rb +0 -74
  81. data/lib/toy/indices.rb +0 -56
  82. data/lib/toy/proxies/embedded_list.rb +0 -79
  83. data/spec/toy/dolly_spec.rb +0 -76
  84. data/spec/toy/embedded_list_spec.rb +0 -607
  85. data/spec/toy/embedded_lists_spec.rb +0 -172
  86. data/spec/toy/index_spec.rb +0 -230
  87. data/spec/toy/indices_spec.rb +0 -141
  88. 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
- module InstanceMethods
21
- def logger
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
- module InstanceMethods
7
- def attributes=(attrs, guard_protected_attributes=true)
8
- attrs = sanitize_for_mass_assignment(attrs || {}) if guard_protected_attributes
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.identity_map.clear
10
- @app.call(env)
11
- ensure
12
- Toy.identity_map.clear
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
@@ -3,15 +3,20 @@ module Toy
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
- def store(name=nil, client=nil, options={})
7
- assert_client(name, client)
8
- @store = Adapter[name].new(client, options) if !name.nil? && !client.nil?
9
- assert_store(name, client)
10
- @store
11
- end
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
- def has_store?
14
- !@store.nil?
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
- private
30
- def assert_client(name, client)
31
- raise(ArgumentError, 'Client is required') if !name.nil? && client.nil?
32
- end
35
+ def adapter
36
+ self.class.adapter
37
+ end
33
38
 
34
- def assert_store(name, client)
35
- raise(StandardError, "No store has been set") if name.nil? && client.nil? && !has_store?
36
- end
39
+ def initialize(attrs={})
40
+ @_new_record = true
41
+ super
37
42
  end
38
43
 
39
- module InstanceMethods
40
- def store
41
- self.class.store
42
- end
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
- def new_record?
45
- @_new_record == true
46
- end
51
+ def initialize_copy(other)
52
+ super
53
+ @_new_record = true
54
+ @_destroyed = false
55
+ end
47
56
 
48
- def destroyed?
49
- @_destroyed == true
50
- end
57
+ def new_record?
58
+ @_new_record == true
59
+ end
51
60
 
52
- def persisted?
53
- !new_record? && !destroyed?
54
- end
61
+ def destroyed?
62
+ @_destroyed == true
63
+ end
55
64
 
56
- def save(*)
57
- new_record? ? create : update
58
- end
65
+ def persisted?
66
+ !new_record? && !destroyed?
67
+ end
59
68
 
60
- def update_attributes(attrs)
61
- self.attributes = attrs
62
- save
63
- end
69
+ def save(*)
70
+ new_record? ? create : update
71
+ end
64
72
 
65
- def destroy
66
- delete
67
- end
73
+ def update_attributes(attrs)
74
+ self.attributes = attrs
75
+ save
76
+ end
68
77
 
69
- def delete
70
- @_destroyed = true
71
- log_operation(:del, self.class.name, store, id)
72
- store.delete(id)
73
- end
78
+ def destroy
79
+ delete
80
+ end
74
81
 
75
- private
76
- def create
77
- persist!
78
- end
82
+ def delete
83
+ @_destroyed = true
84
+ adapter.delete(id)
85
+ end
79
86
 
80
- def update
81
- persist!
82
- end
87
+ private
83
88
 
84
- def persist
85
- @_new_record = false
86
- end
89
+ def create
90
+ persist!
91
+ end
87
92
 
88
- def persist!
89
- attrs = persisted_attributes
90
- attrs.delete('id') # no need to persist id as that is key
91
- store.write(id, attrs)
92
- log_operation(:set, self.class.name, store, id, attrs)
93
- persist
94
- each_embedded_object { |doc| doc.send(:persist) }
95
- true
96
- end
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
@@ -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
- def target_ids
79
- proxy_owner.send(proxy_key)
80
- end
74
+ def find_target
75
+ return [] if target_ids.blank?
76
+ proxy_class.get_multi(target_ids)
77
+ end
81
78
 
82
- def target_ids=(value)
83
- ids = value.map do |item|
84
- if item.is_a?(proxy_class)
85
- item.id
86
- elsif item.is_a?(Hash)
87
- item['id']
88
- else
89
- item
90
- end
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
@@ -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
- def method_missing(method, *args, &block)
55
- target.send(method, *args, &block)
56
- end
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
- log_operation(:get, self, store, id)
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
- log_operation(:key, self, store, id)
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
- def target_id
105
- proxy_owner.send(proxy_key)
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
- def target_id=(value)
109
- proxy_owner.send("#{proxy_key}=", value)
110
- end
105
+ def target_id
106
+ proxy_owner.send(proxy_key)
107
+ end
111
108
 
112
- def method_missing(method, *args, &block)
113
- target.send(method, *args, &block)
114
- end
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
- def #{name}=(record)
125
- #{name}.replace(record)
126
- end
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
- def #{name}?
129
- #{name}.present?
130
- end
131
- """
132
- end
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