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/caching.rb CHANGED
@@ -2,19 +2,17 @@ module Toy
2
2
  module Caching
3
3
  extend ActiveSupport::Concern
4
4
 
5
- module InstanceMethods
6
- def cache_key(*suffixes)
7
- cache_key = case
8
- when new_record?
9
- "#{self.class.name}:new"
10
- when timestamp = self[:updated_at]
11
- "#{self.class.name}:#{id}-#{timestamp.utc.to_s(:number)}"
12
- else
13
- "#{self.class.name}:#{id}"
14
- end
15
- cache_key += ":#{suffixes.join(':')}" unless suffixes.empty?
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
- module InstanceMethods
12
- def save(*)
13
- run_callbacks(:save) { super }
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
- block = embedded_records.inject(block) do |chain, record|
28
- if record.class.respond_to?("_#{callback}_callbacks")
29
- lambda { record.run_callbacks(callback, &chain) }
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
- private
19
+ private
38
20
 
39
- def create
40
- run_callbacks(:create) { super }
41
- end
21
+ def create
22
+ run_callbacks(:create) { super }
23
+ end
42
24
 
43
- def update
44
- run_callbacks(:update) { super }
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
@@ -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
- def modularized_extensions(*extensions)
50
- extensions.flatten.compact.map do |extension|
51
- Proc === extension ? Module.new(&extension) : extension
52
- end
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
- module InstanceMethods
7
- def initialize(*)
8
- super
9
- if new_record?
10
- # never register initial id assignment as a change
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
- def save(*)
33
- super.tap do
34
- @previously_changed = changes
35
- @changed_attributes.clear if @changed_attributes
36
- end
14
+ def initialize_copy(*)
15
+ super.tap do
16
+ @previously_changed = {}
17
+ @changed_attributes = {}
37
18
  end
19
+ end
38
20
 
39
- def write_attribute(name, value)
40
- name = name.to_s
41
- current = read_attribute(name)
42
- attribute_will_change!(name) if current != value
43
- super
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
@@ -1,5 +1,7 @@
1
1
  module Toy
2
2
  module Equality
3
+ extend ActiveSupport::Concern
4
+
3
5
  def eql?(other)
4
6
  return true if self.class.eql?(other.class) && id == other.id
5
7
  return true if other.respond_to?(:target) &&
@@ -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
- 1 => true,
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
- 0 => false,
22
- 0.0 => false,
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.nil? ? nil : !!value
39
+ to_store(value)
36
40
  end
37
41
  end
38
42
  end
@@ -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
- included do
10
- identity_map_on
6
+ def self.enabled=(flag)
7
+ Thread.current[:toystore_identity_map_enabled] = flag
11
8
  end
12
9
 
13
- module ClassMethods
14
- def identity_map
15
- Toy.identity_map
16
- end
10
+ def self.enabled
11
+ Thread.current[:toystore_identity_map_enabled]
12
+ end
17
13
 
18
- def identity_map_on?
19
- @identity_map_on == true
20
- end
14
+ def self.enabled?
15
+ enabled == true
16
+ end
21
17
 
22
- def identity_map_off?
23
- !identity_map_on?
24
- end
18
+ def self.repository
19
+ Thread.current[:toystore_identity_map] ||= {}
20
+ end
25
21
 
26
- def identity_map_on
27
- @identity_map_on = true
28
- end
22
+ def self.clear
23
+ repository.clear
24
+ end
29
25
 
30
- def identity_map_off
31
- @identity_map_on = false
32
- end
26
+ def self.include?(object)
27
+ repository.keys.include?(object.id)
28
+ end
33
29
 
34
- def without_identity_map(&block)
35
- begin
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
- return nil unless identity_map_on?
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 = identity_map[id]
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 do |result|
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
- return unless self.class.identity_map_on?
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
- return unless self.class.identity_map_on?
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
- def list_method
22
- :lists
23
- end
18
+ def proxy_class
19
+ Toy::Proxies::List
20
+ end
24
21
 
25
- def create_accessors
26
- model.class_eval """
27
- def #{name}
28
- #{instance_variable} ||= self.class.#{list_method}[:#{name}].new_proxy(self)
29
- end
22
+ def list_method
23
+ :lists
24
+ end
30
25
 
31
- def #{name}=(records)
32
- #{name}.replace(records)
33
- end
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
- if options[:dependent]
37
- model.class_eval """
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