active_type 0.3.5 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36a9d94011bdc8c1f856f86a6e8727c486a5c913
4
- data.tar.gz: 4519e88999647fdfa0010d316c93a74121e3e713
3
+ metadata.gz: af57ff59af07cfdb0a8576c733da8aa2d0e254ce
4
+ data.tar.gz: e1e04618118baf2b5260e20ed3685d695930e756
5
5
  SHA512:
6
- metadata.gz: 73db269866a0b4cfc512636679733ea14e9c4d5b1130804b305eec33a771dace04ef08a31c91637c9e0a97a79b8b878a8d8be519eceded9a1b43492d49b7bfd9
7
- data.tar.gz: daacc8590bd0afd465eafdb0cca1967c4a8612a34180587d9e20cc65831b39456753ddba149c3e42d2d92708f047f6b2e4d1edf2d7c588ec7c98a0252e2f77a2
6
+ metadata.gz: 91477402f2df135aa9a2bef4a3b63f51c113be820940f83c350230af27b76dcc3c16d587c11874bd64320e1115f68b8fb25c7904e9d6579e3313853fddb8ad08
7
+ data.tar.gz: 7f9fa15fc5ed489c5bee1350f07b97852e32732017c4bb0535d53f4e3fb36c928f20bb9b44dcb5ab6f1ebce5cb892a60e3c382e5e92044e38ef51c823409fb7b
data/README.md CHANGED
@@ -271,6 +271,39 @@ Supported options for `nests_many` / `nests_one` are:
271
271
  ```
272
272
 
273
273
 
274
+ Casting
275
+ -------
276
+
277
+ When working with ActiveType you will often find it useful to cast an ActiveRecord instance to its extended `ActiveType::Record` variant.
278
+
279
+ Use `ActiveType.cast` for this:
280
+
281
+ ```
282
+ class User < ActiveRecord::Base
283
+ ...
284
+ end
285
+
286
+ class SignUp < ActiveType::Record[User]
287
+ ...
288
+ end
289
+
290
+ user = User.find(1)
291
+ sign_up = ActiveType.cast(SignUp)
292
+ sign_up.is_a?(SignUp) # => true
293
+ ```
294
+
295
+ This is basically like [`ActiveRecord#becomes`](http://apidock.com/rails/v4.2.1/ActiveRecord/Persistence/becomes), but with less bugs and more consistent behavior.
296
+
297
+ You can also cast an entire relation (scope) to a relation of an `ActiveType::Record`:
298
+
299
+ ```
300
+ adult_users = User.where('age >= 18')
301
+ adult_sign_ups = ActiveType.cast(adult_users, SignUp)
302
+ sign_up = adult_sign_ups.find(1)
303
+ sign_up.is_a?(SignUp) # => true
304
+ ```
305
+
306
+
274
307
  Supported Rails versions
275
308
  ------------------------
276
309
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_type (0.3.4)
4
+ active_type (0.4.0)
5
5
  activerecord (>= 3.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_type (0.3.4)
4
+ active_type (0.4.0)
5
5
  activerecord (>= 3.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_type (0.3.4)
4
+ active_type (0.4.0)
5
5
  activerecord (>= 3.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_type (0.3.4)
4
+ active_type (0.4.0)
5
5
  activerecord (>= 3.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_type (0.3.4)
4
+ active_type (0.4.0)
5
5
  activerecord (>= 3.2)
6
6
 
7
7
  GEM
@@ -0,0 +1,49 @@
1
+ module ActiveType
2
+ module Util
3
+
4
+ def cast(object, klass)
5
+ if object.is_a?(ActiveRecord::Relation)
6
+ cast_relation(object, klass)
7
+ elsif object.is_a?(ActiveRecord::Base)
8
+ cast_record(object, klass)
9
+ else
10
+ raise ArgumentError, "Don't know how to cast #{object.inspect}"
11
+ end
12
+ end
13
+
14
+ def scoped(klass_or_relation)
15
+ klass_or_relation.where(nil)
16
+ end
17
+
18
+ private
19
+
20
+ def cast_record(record, klass)
21
+ # record.becomes(klass).dup
22
+ klass.new do |casted|
23
+ # Rails 3.2, 4.2
24
+ casted.instance_variable_set(:@attributes, record.instance_variable_get(:@attributes))
25
+ # Rails 3.2
26
+ record.instance_variable_set(:@attributes_cache, record.instance_variable_get(:@attributes_cache))
27
+ # Rails 4.2
28
+ casted.instance_variable_set(:@changed_attributes, record.instance_variable_get(:@changed_attributes))
29
+ # Rails 3.2, 4.2
30
+ casted.instance_variable_set(:@new_record, record.new_record?)
31
+ # Rails 3.2, 4.2
32
+ casted.instance_variable_set(:@destroyed, record.destroyed?)
33
+ # Rails 3.2, 4.2
34
+ casted.instance_variable_set(:@errors, record.errors)
35
+ end
36
+ end
37
+
38
+ def cast_relation(relation, klass)
39
+ scoped(klass).merge(scoped(relation))
40
+ end
41
+
42
+ extend self
43
+
44
+ end
45
+
46
+ # Make Util methods available under the `ActiveType` namespace
47
+ # like `ActiveType.cast(...)`
48
+ extend Util
49
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveType
2
- VERSION = '0.3.5'
2
+ VERSION = '0.4.0'
3
3
  end
data/lib/active_type.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'active_type/version'
4
4
  require 'active_record'
5
+ require 'active_type/util'
5
6
  require 'active_type/record'
6
7
  require 'active_type/object'
7
8
 
@@ -10,4 +11,4 @@ if ActiveRecord::VERSION::STRING == '4.2.0'
10
11
  ActiveType is not compatible with ActiveRecord 4.2.0. Please upgrade to 4.2.1
11
12
  For details see https://github.com/makandra/active_type/issues/31
12
13
  MESSAGE
13
- end
14
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ module UtilSpec
4
+
5
+ class BaseRecord < ActiveRecord::Base
6
+ self.table_name = 'records'
7
+ end
8
+
9
+ class ExtendedRecord < ActiveType::Record[BaseRecord]
10
+
11
+ attribute :virtual_string
12
+ after_initialize :set_virtual_string
13
+
14
+ def set_virtual_string
15
+ self.virtual_string = "persisted_string is #{persisted_string}"
16
+ end
17
+
18
+ end
19
+
20
+ class Parent < ActiveRecord::Base
21
+ self.table_name = 'sti_records'
22
+ end
23
+
24
+ class Child < Parent
25
+ end
26
+
27
+ class ChildSibling < Parent
28
+ end
29
+
30
+ class ExtendedChild < ActiveType::Record[Child]
31
+ end
32
+
33
+ end
34
+
35
+ describe ActiveType::Util do
36
+
37
+ describe '.cast' do
38
+
39
+ describe 'for a relation' do
40
+
41
+ it 'casts a scope to a scope of another class' do
42
+ record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
43
+ base_scope = UtilSpec::BaseRecord.where(persisted_string: 'foo')
44
+ casted_scope = ActiveType::Util.cast(base_scope, UtilSpec::ExtendedRecord)
45
+ casted_scope.build.should be_a(UtilSpec::ExtendedRecord)
46
+ found_record = casted_scope.find(record.id)
47
+ found_record.persisted_string.should == 'foo'
48
+ found_record.should be_a(UtilSpec::ExtendedRecord)
49
+ end
50
+
51
+ it 'preserves existing scope conditions' do
52
+ match = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
53
+ no_match = UtilSpec::BaseRecord.create!(persisted_string: 'bar')
54
+ base_scope = UtilSpec::BaseRecord.where(persisted_string: 'foo')
55
+ casted_scope = ActiveType::Util.cast(base_scope, UtilSpec::ExtendedRecord)
56
+ casted_match = UtilSpec::ExtendedRecord.find(match.id)
57
+ casted_scope.to_a.should == [casted_match]
58
+ end
59
+
60
+ end
61
+
62
+ describe 'for a record type' do
63
+
64
+ it 'casts a base record to an extended record' do
65
+ base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
66
+ extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
67
+ extended_record.should be_a(UtilSpec::ExtendedRecord)
68
+ extended_record.should be_persisted
69
+ extended_record.id.should be_present
70
+ extended_record.id.should == base_record.id
71
+ extended_record.persisted_string.should == 'foo'
72
+ end
73
+
74
+ it 'casts an extended record to a base record' do
75
+ extended_record = UtilSpec::ExtendedRecord.create!(persisted_string: 'foo')
76
+ base_record = ActiveType::Util.cast(extended_record, UtilSpec::BaseRecord)
77
+ base_record.should be_a(UtilSpec::BaseRecord)
78
+ base_record.should be_persisted
79
+ base_record.id.should be_present
80
+ base_record.id.should == extended_record.id
81
+ base_record.persisted_string.should == 'foo'
82
+ end
83
+
84
+ it 'calls after_initialize callbacks of the cast target' do
85
+ base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
86
+ extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
87
+ extended_record.virtual_string.should be_present
88
+ end
89
+
90
+ it 'lets after_initialize callbacks access attributes (bug in ActiveRecord#becomes)' do
91
+ base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
92
+ extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
93
+ extended_record.virtual_string.should == 'persisted_string is foo'
94
+ end
95
+
96
+ it 'preserves the #type of an STI record that is casted to an ExtendedRecord' do
97
+ child_record = UtilSpec::Child.create!(persisted_string: 'foo')
98
+ extended_child_record = ActiveType::Util.cast(child_record, UtilSpec::ExtendedChild)
99
+ extended_child_record.should be_a(UtilSpec::ExtendedChild)
100
+ extended_child_record.type.should == 'UtilSpec::Child'
101
+ end
102
+
103
+ it 'changes the #type of an STI record when casted to another type in the hierarchy' do
104
+ child_record = UtilSpec::Child.create!(persisted_string: 'foo')
105
+ child_sibling_record = ActiveType::Util.cast(child_record, UtilSpec::ChildSibling)
106
+ child_sibling_record.should be_a(UtilSpec::ChildSibling)
107
+ child_sibling_record.type.should == 'UtilSpec::Child'
108
+ end
109
+
110
+ it 'preserves dirty tracking flags' do
111
+ base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
112
+ base_record.changes.should == {}
113
+ base_record.persisted_string = 'bar'
114
+ base_record.changes.should == { 'persisted_string' => ['foo', 'bar'] }
115
+ extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
116
+ extended_record.should be_a(UtilSpec::ExtendedRecord)
117
+ extended_record.changes.should == { 'persisted_string' => ['foo', 'bar'] }
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+
124
+ it "exposes all methods through ActiveType's root namespace" do
125
+ ActiveType.should respond_to(:cast)
126
+ end
127
+
128
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Kraze
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-11 00:00:00.000000000 Z
12
+ date: 2015-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -88,6 +88,7 @@ files:
88
88
  - lib/active_type/object.rb
89
89
  - lib/active_type/record.rb
90
90
  - lib/active_type/type_caster.rb
91
+ - lib/active_type/util.rb
91
92
  - lib/active_type/version.rb
92
93
  - lib/active_type/virtual_attributes.rb
93
94
  - spec/active_type/extended_record/single_table_inheritance_spec.rb
@@ -95,6 +96,7 @@ files:
95
96
  - spec/active_type/nested_attributes_spec.rb
96
97
  - spec/active_type/object_spec.rb
97
98
  - spec/active_type/record_spec.rb
99
+ - spec/active_type/util_spec.rb
98
100
  - spec/integration/holidays_spec.rb
99
101
  - spec/integration/shape_spec.rb
100
102
  - spec/integration/sign_in_spec.rb
@@ -142,6 +144,7 @@ test_files:
142
144
  - spec/active_type/nested_attributes_spec.rb
143
145
  - spec/active_type/object_spec.rb
144
146
  - spec/active_type/record_spec.rb
147
+ - spec/active_type/util_spec.rb
145
148
  - spec/integration/holidays_spec.rb
146
149
  - spec/integration/shape_spec.rb
147
150
  - spec/integration/sign_in_spec.rb