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/.gitignore CHANGED
@@ -4,5 +4,4 @@ testing/
4
4
  log
5
5
  tmp
6
6
  pkg
7
- .bundle
8
- Gemfile.lock
7
+ .bundle
data/Changelog.md ADDED
@@ -0,0 +1,9 @@
1
+ I will do my best to keep this up to date with significant changes here, starting in 0.8.3.
2
+
3
+ * 0.8.3 => 0.9.0
4
+ * [Changed from `store` to `adapter`](https://github.com/jnunemaker/toystore/pull/1)
5
+ * [Embedded objects were removed](https://github.com/jnunemaker/toystore/pull/2)
6
+ * [Defaulted `adapter` to memory and removed `has_adapter?`](https://github.com/jnunemaker/toystore/commit/64268705fcb22d82eb7ac3e934508770ceb1f101)
7
+ * [Introduced Toy::Object](https://github.com/jnunemaker/toystore/commit/f22fddff96b388db3bd22f36cc1cc29b28d0ae5e).
8
+ * [Default Identity Map to off](https://github.com/jnunemaker/toystore/compare/02b652b4dbd4a652bf3d788fbf8cf7d0bae805f6...5cec60be60f9bf749964d5c2d437189287d6d837)
9
+ * Removed several class methods related to identity map as well (identity_map_on/off/on?/off?/etc)
data/Gemfile CHANGED
@@ -2,6 +2,11 @@ source :rubygems
2
2
  gemspec
3
3
 
4
4
  group(:development) do
5
+ gem 'guard'
6
+ gem 'guard-rspec'
7
+ gem 'guard-bundler'
8
+ gem 'growl'
9
+
5
10
  gem 'rake', '~> 0.8.7'
6
11
  gem 'rspec', '~> 2.3'
7
12
  gem 'timecop', '~> 0.3.5'
data/Gemfile.lock ADDED
@@ -0,0 +1,71 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ toystore (0.8.3)
5
+ activemodel (~> 3.0, < 3.2)
6
+ activesupport (~> 3.0, < 3.2)
7
+ adapter (~> 0.5.1)
8
+ simple_uuid (~> 0.1.1)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ activemodel (3.1.3)
14
+ activesupport (= 3.1.3)
15
+ builder (~> 3.0.0)
16
+ i18n (~> 0.6)
17
+ activesupport (3.1.3)
18
+ multi_json (~> 1.0)
19
+ adapter (0.5.2)
20
+ bson (1.5.2)
21
+ bson_ext (1.5.2)
22
+ bson (= 1.5.2)
23
+ builder (3.0.0)
24
+ diff-lcs (1.1.3)
25
+ ffi (1.0.11)
26
+ growl (1.0.3)
27
+ guard (1.0.0)
28
+ ffi (>= 0.5.0)
29
+ thor (~> 0.14.6)
30
+ guard-bundler (0.1.3)
31
+ bundler (>= 1.0.0)
32
+ guard (>= 0.2.2)
33
+ guard-rspec (0.6.0)
34
+ guard (>= 0.10.0)
35
+ i18n (0.6.0)
36
+ log_buddy (0.5.0)
37
+ multi_json (1.0.4)
38
+ rack (1.4.0)
39
+ rack-test (0.6.1)
40
+ rack (>= 1.0)
41
+ rake (0.8.7)
42
+ rspec (2.8.0)
43
+ rspec-core (~> 2.8.0)
44
+ rspec-expectations (~> 2.8.0)
45
+ rspec-mocks (~> 2.8.0)
46
+ rspec-core (2.8.0)
47
+ rspec-expectations (2.8.0)
48
+ diff-lcs (~> 1.1.2)
49
+ rspec-mocks (2.8.0)
50
+ simple_uuid (0.1.2)
51
+ thor (0.14.6)
52
+ timecop (0.3.5)
53
+ tzinfo (0.3.31)
54
+
55
+ PLATFORMS
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ bson
60
+ bson_ext
61
+ growl
62
+ guard
63
+ guard-bundler
64
+ guard-rspec
65
+ log_buddy (~> 0.5.0)
66
+ rack-test
67
+ rake (~> 0.8.7)
68
+ rspec (~> 2.3)
69
+ timecop (~> 0.3.5)
70
+ toystore!
71
+ tzinfo (~> 0.3.23)
data/Guardfile ADDED
@@ -0,0 +1,15 @@
1
+ rspec_options = {
2
+ :all_after_pass => false,
3
+ :all_on_start => false,
4
+ }
5
+
6
+ guard 'rspec', rspec_options do
7
+ watch(%r{^spec/.+_spec\.rb$})
8
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
9
+ watch('spec/helper.rb') { "spec" }
10
+ end
11
+
12
+ guard 'bundler' do
13
+ watch('Gemfile')
14
+ watch(/^.+\.gemspec/)
15
+ end
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Toystore
2
+
3
+ An object mapper for any [adapter](https://github.com/jnunemaker/adapter) that can read, write, delete, and clear data.
4
+
5
+ See [examples/](https://github.com/jnunemaker/toystore/tree/master/examples) for potential direction.
6
+
7
+ ## ToyStore Power User Guides
8
+
9
+ * [Wiki Home](https://github.com/jnunemaker/toystore/wiki)
10
+ * [Identity](https://github.com/jnunemaker/toystore/wiki/Identity)
11
+ * [Types](https://github.com/jnunemaker/toystore/wiki/Types)
12
+ * [Exceptions](https://github.com/jnunemaker/toystore/wiki/Exceptions)
13
+
14
+ ## Changelog
15
+
16
+ As of 0.8.3, I started keeping a [changelog](https://github.com/jnunemaker/toystore/blob/master/Changelog.md). All significant updates will be summarized there.
17
+
18
+ ## Mailing List
19
+
20
+ https://groups.google.com/forum/#!forum/toystoreadapter
21
+
22
+ ## Note on Patches/Pull Requests
23
+
24
+ * Fork the project.
25
+ * Make your feature addition or bug fix in a topic branch.
26
+ * Add tests for it. This is important so we don't break it in a future version unintentionally.
27
+ * Commit, do not mess with rakefile, version, or changelog. (if you want to have your own version, that is fine, but bump version in a commit by itself so we can ignore when we pull)
28
+ * Send a pull request.
@@ -10,7 +10,6 @@ require 'toystore'
10
10
 
11
11
  class User
12
12
  include Toy::Store
13
- store :memory, {}
14
13
 
15
14
  attribute :email, String
16
15
  attribute :my_really_long_field_name, String, :abbr => :my
@@ -21,6 +20,6 @@ user = User.create({
21
20
  :my_really_long_field_name => 'something',
22
21
  })
23
22
 
24
- pp Marshal.load(User.store.client[user.id])
23
+ pp Marshal.load(User.adapter.client[user.id])
25
24
  # Abbreviated attributes are stored in the database as the abbreviation for when you want to conserve space. The abbreviation and the full attribute name work exactly the same in Ruby, the only difference is how they get persisted.
26
25
  # {"my"=>"something", "email"=>"nunemaker@gmail.com"}
@@ -10,7 +10,6 @@ require 'toystore'
10
10
 
11
11
  class User
12
12
  include Toy::Store
13
- store :memory, {}
14
13
 
15
14
  attribute :email, String
16
15
  attribute :crypted_password, String
@@ -36,6 +35,6 @@ user = User.create({
36
35
  :password_confirmation => 'testing',
37
36
  })
38
37
 
39
- pp Marshal.load(User.store.client[user.id])
38
+ pp Marshal.load(User.adapter.client[user.id])
40
39
  # Virtual attributes are never persisted. In the data store, only email and crypted_password are stored.
41
40
  # {"crypted_password"=>"testing", "email"=>"nunemaker@gmail.com"}
@@ -8,17 +8,16 @@ lib_path = root_path.join('lib')
8
8
  $:.unshift(lib_path)
9
9
  require 'toystore'
10
10
 
11
- # Identity map is turned on by default for Toystore. To turn it off for an entire model, just call identity_map_off.
12
- #
13
11
  # More Reading...
14
12
  # http://martinfowler.com/eaaCatalog/identityMap.html
15
13
  # http://en.wikipedia.org/wiki/Identity_map
16
14
 
15
+ # Identity map is turned off by default for Toystore so let's turn it on
16
+ Toy::IdentityMap.enabled = true
17
+ puts 'Identity map enabled'
18
+
17
19
  class User
18
20
  include Toy::Store
19
- store :memory, {}
20
-
21
- # identity_map_off # if uncommented, User would not use identity map
22
21
 
23
22
  attribute :name, String
24
23
  end
@@ -29,17 +28,13 @@ user = User.create(:name => 'John')
29
28
  # {"name"=>"John"}
30
29
  # ToyStore IMS User "08a1c54c-3393-11e0-8b37-89da41d2f675"
31
30
 
32
- User.get(user.id)
31
+ puts "With identity map - User.get(user.id).equal?(user): #{User.get(user.id).equal?(user)}"
33
32
  # User is retrieved from identity map instead of querying
34
33
  # ToyStore IMG User "08a1c54c-3393-11e0-8b37-89da41d2f675"
35
34
 
36
- User.without_identity_map do
37
- User.get(user.id)
35
+ Toy::IdentityMap.without do
36
+ puts "Without identity map - User.get(user.id).equal?(user): #{User.get(user.id).equal?(user)}"
38
37
  # User is queried from database
39
38
  # ToyStore GET User :memory "08a1c54c-3393-11e0-8b37-89da41d2f675"
40
39
  # {"name"=>"John"}
41
40
  end
42
-
43
- User.get(user.id)
44
- # User is retrieved from identity map instead of querying
45
- # ToyStore IMG User "08a1c54c-3393-11e0-8b37-89da41d2f675"
@@ -10,7 +10,7 @@ require 'toystore'
10
10
 
11
11
  class GameList
12
12
  include Toy::Store
13
- store :memcached, Memcached.new
13
+ adapter :memcached, Memcached.new
14
14
 
15
15
  attribute :source, Hash
16
16
  end
data/examples/memory.rb CHANGED
@@ -10,7 +10,7 @@ require 'toystore'
10
10
 
11
11
  class User
12
12
  include Toy::Store
13
- store :memory, {}
13
+ adapter :memory, {}
14
14
 
15
15
  attribute :name, String
16
16
  end
data/examples/mongo.rb CHANGED
@@ -10,7 +10,7 @@ require 'toystore'
10
10
 
11
11
  class User
12
12
  include Toy::Store
13
- store :mongo, Mongo::Connection.new.db('adapter')['testing']
13
+ adapter :mongo, Mongo::Connection.new.db('adapter')['testing']
14
14
 
15
15
  attribute :name, String
16
16
  end
data/examples/redis.rb CHANGED
@@ -10,7 +10,7 @@ require 'toystore'
10
10
 
11
11
  class User
12
12
  include Toy::Store
13
- store :redis, Redis.new
13
+ adapter :redis, Redis.new
14
14
 
15
15
  attribute :name, String
16
16
  end
data/examples/riak.rb CHANGED
@@ -10,7 +10,7 @@ require 'toystore'
10
10
 
11
11
  class GameList
12
12
  include Toy::Store
13
- store :riak, Riak::Client.new['adapter_example']
13
+ adapter :riak, Riak::Client.new['adapter_example']
14
14
 
15
15
  attribute :source, Hash
16
16
  end
data/lib/toy.rb CHANGED
@@ -5,15 +5,11 @@ require 'digest/sha1'
5
5
 
6
6
  root_path = Pathname(__FILE__).dirname.join('..').expand_path
7
7
 
8
- require 'adapter'
8
+ require 'adapter/memory'
9
9
  require 'simple_uuid'
10
10
  require 'active_model'
11
11
  require 'active_support/json'
12
- require 'active_support/core_ext/object'
13
- require 'active_support/core_ext/hash/keys'
14
- require 'active_support/core_ext/class/inheritable_attributes'
15
- require 'active_support/core_ext/string/conversions'
16
- require 'active_support/core_ext/string/inflections'
12
+ require 'active_support/core_ext'
17
13
 
18
14
  extensions_path = root_path.join('lib', 'toy', 'extensions')
19
15
  Dir[extensions_path + '**/*.rb'].each { |file| require(file) }
@@ -24,12 +20,12 @@ module Toy
24
20
  # Resets all tracking of things in memory. Useful for running
25
21
  # before each request in development mode with Rails and such.
26
22
  def reset
27
- identity_map.clear
23
+ IdentityMap.clear
28
24
  plugins.clear
29
25
  models.clear
30
26
  end
31
27
 
32
- # Clears all the stores for all the models. Useful in specs/tests/etc.
28
+ # Clears all the adapters for all the models. Useful in specs/tests/etc.
33
29
  # Do not use in production, harty harr harr.
34
30
  #
35
31
  # Note: that if your models are auto-loaded like in Rails, you will need
@@ -37,9 +33,9 @@ module Toy
37
33
  # not be aware of their existence.
38
34
  def clear
39
35
  models.each do |model|
40
- model.store.clear if model.has_store?
41
- model.identity_map.clear if model.identity_map_on?
36
+ model.adapter.clear
42
37
  end
38
+ IdentityMap.clear
43
39
  end
44
40
 
45
41
  def logger
@@ -65,38 +61,43 @@ module Toy
65
61
  module Middleware
66
62
  autoload 'IdentityMap', 'toy/middleware/identity_map'
67
63
  end
64
+
65
+ autoload 'Attribute', 'toy/attribute'
66
+ autoload 'Attribute', 'toy/attribute'
67
+ autoload 'Attributes', 'toy/attributes'
68
+ autoload 'Caching', 'toy/caching'
69
+ autoload 'Callbacks', 'toy/callbacks'
70
+ autoload 'Dirty', 'toy/dirty'
71
+ autoload 'DirtyStore', 'toy/dirty_store'
72
+ autoload 'Cloneable', 'toy/cloneable'
73
+ autoload 'Equality', 'toy/equality'
74
+ autoload 'Inspect', 'toy/inspect'
75
+ autoload 'Logger', 'toy/logger'
76
+ autoload 'MassAssignmentSecurity', 'toy/mass_assignment_security'
77
+ autoload 'Persistence', 'toy/persistence'
78
+ autoload 'Querying', 'toy/querying'
79
+ autoload 'Reloadable', 'toy/reloadable'
80
+ autoload 'Serialization', 'toy/serialization'
81
+ autoload 'Timestamps', 'toy/timestamps'
82
+ autoload 'Validations', 'toy/validations'
83
+
84
+ autoload 'Collection', 'toy/collection'
85
+ autoload 'List', 'toy/list'
86
+ autoload 'Lists', 'toy/lists'
87
+ autoload 'Reference', 'toy/reference'
88
+ autoload 'References', 'toy/references'
89
+ autoload 'Identity', 'toy/identity'
90
+
91
+ module Identity
92
+ autoload 'AbstractKeyFactory', 'toy/identity/abstract_key_factory'
93
+ autoload 'UUIDKeyFactory', 'toy/identity/uuid_key_factory'
94
+ end
68
95
  end
69
96
 
97
+ require 'toy/identity_map'
70
98
  require 'toy/exceptions'
71
- require 'toy/attribute'
72
- require 'toy/attributes'
73
- require 'toy/callbacks'
74
- require 'toy/dirty'
75
- require 'toy/dolly'
76
- require 'toy/equality'
77
- require 'toy/inspect'
78
- require 'toy/persistence'
79
- require 'toy/mass_assignment_security'
80
99
  require 'toy/plugins'
100
+ require 'toy/object'
81
101
  require 'toy/store'
82
- require 'toy/serialization'
83
- require 'toy/timestamps'
84
- require 'toy/validations'
85
- require 'toy/querying'
86
- require 'toy/identity_map'
87
102
 
88
- require 'toy/collection'
89
- require 'toy/embedded_list'
90
- require 'toy/embedded_lists'
91
- require 'toy/list'
92
- require 'toy/lists'
93
- require 'toy/reference'
94
- require 'toy/references'
95
-
96
- require 'toy/index'
97
- require 'toy/indices'
98
- require 'toy/identity/abstract_key_factory'
99
- require 'toy/identity/uuid_key_factory'
100
- require 'toy/identity'
101
- require 'toy/caching'
102
- require 'toy/logger'
103
+ Toy::IdentityMap.enabled = false
data/lib/toy/attribute.rb CHANGED
@@ -3,7 +3,7 @@ module Toy
3
3
  attr_reader :model, :name, :type, :options
4
4
 
5
5
  def initialize(model, name, type, options={})
6
- options.assert_valid_keys(:default, :embedded_list, :virtual, :abbr)
6
+ options.assert_valid_keys(:default, :virtual, :abbr)
7
7
 
8
8
  @model, @name, @type, @options = model, name.to_s, type, options
9
9
  @virtual = options.fetch(:virtual, false)
@@ -58,11 +58,6 @@ module Toy
58
58
  abbr? ? abbr : name
59
59
  end
60
60
 
61
- # Stores reference to related embedded list
62
- def embedded_list
63
- options[:embedded_list]
64
- end
65
-
66
61
  def eql?(other)
67
62
  self.class.eql?(other.class) &&
68
63
  model == other.model &&
@@ -4,6 +4,7 @@ module Toy
4
4
  include ActiveModel::AttributeMethods
5
5
 
6
6
  included do
7
+ include Identity
7
8
  attribute_method_suffix('', '=', '?')
8
9
  end
9
10
 
@@ -25,114 +26,84 @@ module Toy
25
26
  end
26
27
  end
27
28
 
28
- module InstanceMethods
29
- def initialize(attrs={})
30
- @_new_record = true unless defined?(@_new_record)
31
- initialize_attributes_with_defaults
32
- send(:attributes=, attrs, @_new_record)
33
- write_attribute :id, self.class.next_key(self) unless id?
34
- end
35
-
36
- def initialize_from_database(attrs={})
37
- @_new_record = false
38
- send(:initialize, attrs)
39
- self
40
- end
41
-
42
- def reload
43
- if attrs = store.read(id)
44
- attrs['id'] = id
45
- instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
46
- initialize_attributes_with_defaults
47
- send(:attributes=, attrs, new_record?)
48
- self.class.lists.each_key { |name| send(name).reset }
49
- self.class.references.each_key { |name| send(name).reset }
50
- else
51
- raise NotFound.new(id)
52
- end
53
- self
54
- end
55
-
56
- def id
57
- read_attribute(:id)
58
- end
29
+ def initialize(attrs={})
30
+ initialize_attributes_with_defaults
31
+ self.attributes = attrs
32
+ write_attribute :id, self.class.next_key(self) unless id?
33
+ end
59
34
 
60
- def attributes
61
- @attributes
62
- end
35
+ def id
36
+ read_attribute(:id)
37
+ end
63
38
 
64
- def persisted_attributes
65
- {}.tap do |attrs|
66
- self.class.attributes.each do |name, attribute|
67
- next if attribute.virtual?
68
- attrs[attribute.persisted_name] = attribute.to_store(read_attribute(attribute.name))
69
- end
70
- end.merge(embedded_attributes)
71
- end
39
+ def attributes
40
+ @attributes
41
+ end
72
42
 
73
- def embedded_attributes
74
- {}.tap do |attrs|
75
- self.class.embedded_lists.each_key do |name|
76
- attrs[name.to_s] = send(name).map(&:persisted_attributes)
77
- end
43
+ def persisted_attributes
44
+ {}.tap do |attrs|
45
+ self.class.attributes.each do |name, attribute|
46
+ next if attribute.virtual?
47
+ attrs[attribute.persisted_name] = attribute.to_store(read_attribute(attribute.name))
78
48
  end
79
49
  end
50
+ end
80
51
 
81
- def attributes=(attrs, *)
82
- return if attrs.nil?
83
- attrs.each do |key, value|
84
- if attribute_method?(key)
85
- write_attribute(key, value)
86
- elsif respond_to?("#{key}=")
87
- send("#{key}=", value)
88
- end
52
+ def attributes=(attrs, *)
53
+ return if attrs.nil?
54
+ attrs.each do |key, value|
55
+ if attribute_method?(key)
56
+ write_attribute(key, value)
57
+ elsif respond_to?("#{key}=")
58
+ send("#{key}=", value)
89
59
  end
90
60
  end
61
+ end
91
62
 
92
- def [](key)
93
- read_attribute(key)
94
- end
63
+ def [](key)
64
+ read_attribute(key)
65
+ end
95
66
 
96
- def []=(key, value)
97
- write_attribute(key, value)
98
- end
67
+ def []=(key, value)
68
+ write_attribute(key, value)
69
+ end
99
70
 
100
- private
101
- def read_attribute(key)
102
- @attributes ||= {}
103
- @attributes[key.to_s]
104
- end
71
+ private
105
72
 
106
- def write_attribute(key, value)
107
- @attributes[key.to_s] = attribute_definition(key).try(:from_store, value)
108
- end
73
+ def read_attribute(key)
74
+ @attributes ||= {}
75
+ @attributes[key.to_s]
76
+ end
109
77
 
110
- def attribute_definition(key)
111
- self.class.attributes[key.to_s]
112
- end
78
+ def write_attribute(key, value)
79
+ @attributes[key.to_s] = attribute_definition(key).try(:from_store, value)
80
+ end
113
81
 
114
- def attribute_method?(key)
115
- self.class.attribute?(key)
116
- end
82
+ def attribute_definition(key)
83
+ self.class.attributes[key.to_s]
84
+ end
117
85
 
118
- def attribute(key)
119
- read_attribute(key)
120
- end
86
+ def attribute_method?(key)
87
+ self.class.attribute?(key)
88
+ end
121
89
 
122
- def attribute=(key, value)
123
- write_attribute(key, value)
124
- end
90
+ def attribute(key)
91
+ read_attribute(key)
92
+ end
125
93
 
126
- def attribute?(key)
127
- read_attribute(key).present?
128
- end
94
+ def attribute=(key, value)
95
+ write_attribute(key, value)
96
+ end
129
97
 
130
- def initialize_attributes_with_defaults
131
- @attributes ||= {}
132
- self.class.defaulted_attributes.each do |attribute|
133
- @attributes[attribute.name.to_s] = attribute.default
134
- end
135
- end
98
+ def attribute?(key)
99
+ read_attribute(key).present?
100
+ end
101
+
102
+ def initialize_attributes_with_defaults
103
+ @attributes ||= {}
104
+ self.class.defaulted_attributes.each do |attribute|
105
+ @attributes[attribute.name.to_s] = attribute.default
106
+ end
136
107
  end
137
108
  end
138
109
  end