toystore 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/.gitignore
CHANGED
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
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.
|
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.
|
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"}
|
data/examples/identity_map.rb
CHANGED
@@ -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
|
-
|
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"
|
data/examples/memcached.rb
CHANGED
data/examples/memory.rb
CHANGED
data/examples/mongo.rb
CHANGED
data/examples/redis.rb
CHANGED
data/examples/riak.rb
CHANGED
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
|
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
|
-
|
23
|
+
IdentityMap.clear
|
28
24
|
plugins.clear
|
29
25
|
models.clear
|
30
26
|
end
|
31
27
|
|
32
|
-
# Clears all the
|
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.
|
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
|
-
|
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, :
|
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 &&
|
data/lib/toy/attributes.rb
CHANGED
@@ -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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
35
|
+
def id
|
36
|
+
read_attribute(:id)
|
37
|
+
end
|
63
38
|
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
63
|
+
def [](key)
|
64
|
+
read_attribute(key)
|
65
|
+
end
|
95
66
|
|
96
|
-
|
97
|
-
|
98
|
-
|
67
|
+
def []=(key, value)
|
68
|
+
write_attribute(key, value)
|
69
|
+
end
|
99
70
|
|
100
|
-
|
101
|
-
def read_attribute(key)
|
102
|
-
@attributes ||= {}
|
103
|
-
@attributes[key.to_s]
|
104
|
-
end
|
71
|
+
private
|
105
72
|
|
106
|
-
|
107
|
-
|
108
|
-
|
73
|
+
def read_attribute(key)
|
74
|
+
@attributes ||= {}
|
75
|
+
@attributes[key.to_s]
|
76
|
+
end
|
109
77
|
|
110
|
-
|
111
|
-
|
112
|
-
|
78
|
+
def write_attribute(key, value)
|
79
|
+
@attributes[key.to_s] = attribute_definition(key).try(:from_store, value)
|
80
|
+
end
|
113
81
|
|
114
|
-
|
115
|
-
|
116
|
-
|
82
|
+
def attribute_definition(key)
|
83
|
+
self.class.attributes[key.to_s]
|
84
|
+
end
|
117
85
|
|
118
|
-
|
119
|
-
|
120
|
-
|
86
|
+
def attribute_method?(key)
|
87
|
+
self.class.attribute?(key)
|
88
|
+
end
|
121
89
|
|
122
|
-
|
123
|
-
|
124
|
-
|
90
|
+
def attribute(key)
|
91
|
+
read_attribute(key)
|
92
|
+
end
|
125
93
|
|
126
|
-
|
127
|
-
|
128
|
-
|
94
|
+
def attribute=(key, value)
|
95
|
+
write_attribute(key, value)
|
96
|
+
end
|
129
97
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|