toystore 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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