active_type 0.4.5 → 0.7.5

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +30 -24
  5. data/CHANGELOG.md +73 -2
  6. data/README.md +56 -11
  7. data/Rakefile +22 -1
  8. data/active_type.gemspec +2 -1
  9. data/gemfiles/Gemfile.3.2.mysql2 +1 -0
  10. data/gemfiles/Gemfile.3.2.mysql2.lock +4 -2
  11. data/gemfiles/Gemfile.3.2.sqlite3 +1 -0
  12. data/gemfiles/Gemfile.3.2.sqlite3.lock +4 -2
  13. data/gemfiles/Gemfile.4.0.sqlite3 +1 -0
  14. data/gemfiles/Gemfile.4.0.sqlite3.lock +4 -2
  15. data/gemfiles/Gemfile.4.1.sqlite3 +1 -0
  16. data/gemfiles/Gemfile.4.1.sqlite3.lock +4 -2
  17. data/gemfiles/Gemfile.4.2.1.mysql2 +1 -0
  18. data/gemfiles/Gemfile.4.2.1.mysql2.lock +4 -2
  19. data/gemfiles/Gemfile.4.2.1.pg +1 -0
  20. data/gemfiles/Gemfile.4.2.1.pg.lock +4 -2
  21. data/gemfiles/Gemfile.4.2.1.sqlite3 +1 -0
  22. data/gemfiles/Gemfile.4.2.1.sqlite3.lock +4 -2
  23. data/gemfiles/Gemfile.5.0.0.mysql2.lock +56 -0
  24. data/gemfiles/Gemfile.5.0.0.pg.lock +56 -0
  25. data/gemfiles/Gemfile.5.0.0.sqlite3 +8 -0
  26. data/gemfiles/Gemfile.5.0.0.sqlite3.lock +56 -0
  27. data/gemfiles/Gemfile.5.1.0.mysql2 +8 -0
  28. data/gemfiles/Gemfile.5.1.0.mysql2.lock +56 -0
  29. data/gemfiles/Gemfile.5.1.0.pg +8 -0
  30. data/gemfiles/Gemfile.5.1.0.pg.lock +56 -0
  31. data/gemfiles/Gemfile.5.1.0.sqlite3 +8 -0
  32. data/gemfiles/Gemfile.5.1.0.sqlite3.lock +56 -0
  33. data/lib/active_type/extended_record/inheritance.rb +41 -6
  34. data/lib/active_type/nested_attributes/association.rb +13 -4
  35. data/lib/active_type/nested_attributes/builder.rb +3 -3
  36. data/lib/active_type/nested_attributes/nests_many_association.rb +5 -1
  37. data/lib/active_type/nested_attributes/nests_one_association.rb +3 -2
  38. data/lib/active_type/no_table.rb +129 -42
  39. data/lib/active_type/type_caster.rb +66 -25
  40. data/lib/active_type/util.rb +21 -6
  41. data/lib/active_type/version.rb +1 -1
  42. data/lib/active_type/virtual_attributes.rb +23 -1
  43. data/lib/active_type.rb +13 -3
  44. metadata +16 -55
  45. data/spec/active_type/extended_record/single_table_inheritance_spec.rb +0 -62
  46. data/spec/active_type/extended_record_spec.rb +0 -233
  47. data/spec/active_type/nested_attributes_spec.rb +0 -700
  48. data/spec/active_type/object_spec.rb +0 -400
  49. data/spec/active_type/record_spec.rb +0 -236
  50. data/spec/active_type/util_spec.rb +0 -128
  51. data/spec/integration/holidays_spec.rb +0 -102
  52. data/spec/integration/shape_spec.rb +0 -110
  53. data/spec/integration/sign_in_spec.rb +0 -101
  54. data/spec/integration/sign_up_spec.rb +0 -102
  55. data/spec/shared_examples/accessors.rb +0 -41
  56. data/spec/shared_examples/belongs_to.rb +0 -17
  57. data/spec/shared_examples/coercible_columns.rb +0 -228
  58. data/spec/shared_examples/constructor.rb +0 -30
  59. data/spec/shared_examples/defaults.rb +0 -60
  60. data/spec/shared_examples/dirty_tracking.rb +0 -40
  61. data/spec/shared_examples/dupable.rb +0 -31
  62. data/spec/shared_examples/mass_assignment.rb +0 -26
  63. data/spec/spec_helper.rb +0 -27
  64. data/spec/support/database.rb +0 -55
  65. data/spec/support/database.sample.yml +0 -3
  66. data/spec/support/error_on.rb +0 -12
  67. data/spec/support/i18n.rb +0 -1
  68. data/spec/support/protected_params.rb +0 -20
  69. data/spec/support/time_zone.rb +0 -1
@@ -1,128 +0,0 @@
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
- expect(casted_scope.build).to be_a(UtilSpec::ExtendedRecord)
46
- found_record = casted_scope.find(record.id)
47
- expect(found_record.persisted_string).to eq('foo')
48
- expect(found_record).to 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
- expect(casted_scope.to_a).to eq([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
- expect(extended_record).to be_a(UtilSpec::ExtendedRecord)
68
- expect(extended_record).to be_persisted
69
- expect(extended_record.id).to be_present
70
- expect(extended_record.id).to eq(base_record.id)
71
- expect(extended_record.persisted_string).to eq('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
- expect(base_record).to be_a(UtilSpec::BaseRecord)
78
- expect(base_record).to be_persisted
79
- expect(base_record.id).to be_present
80
- expect(base_record.id).to eq(extended_record.id)
81
- expect(base_record.persisted_string).to eq('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
- expect(extended_record.virtual_string).to 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
- expect(extended_record.virtual_string).to eq('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
- expect(extended_child_record).to be_a(UtilSpec::ExtendedChild)
100
- expect(extended_child_record.type).to eq('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
- expect(child_sibling_record).to be_a(UtilSpec::ChildSibling)
107
- expect(child_sibling_record.type).to eq('UtilSpec::Child')
108
- end
109
-
110
- it 'preserves dirty tracking flags' do
111
- base_record = UtilSpec::BaseRecord.create!(:persisted_string => 'foo')
112
- expect(base_record.changes).to eq({})
113
- base_record.persisted_string = 'bar'
114
- expect(base_record.changes).to eq({ 'persisted_string' => ['foo', 'bar'] })
115
- extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
116
- expect(extended_record).to be_a(UtilSpec::ExtendedRecord)
117
- expect(extended_record.changes).to eq({ '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
- expect(ActiveType).to respond_to(:cast)
126
- end
127
-
128
- end
@@ -1,102 +0,0 @@
1
- # Usecase: CRUD a number of records
2
-
3
- require 'spec_helper'
4
-
5
- ActiveRecord::Migration.class_eval do
6
- create_table :holidays do |t|
7
- t.string :name
8
- t.date :date
9
- end
10
- end
11
-
12
- module HolidaySpec
13
-
14
- class Holiday < ActiveRecord::Base
15
- validates :name, :date, :presence => true
16
- end
17
-
18
- class HolidayForm < ActiveType::Object
19
- nests_many :holidays, :scope => Holiday, :default => proc { Holiday.all }, :reject_if => :all_blank, :allow_destroy => true
20
- end
21
-
22
- end
23
-
24
-
25
- describe HolidaySpec::HolidayForm do
26
-
27
- let(:params) do
28
- {
29
- '1' => {
30
- 'name' => 'New Year',
31
- 'date' => '2014-01-01',
32
- },
33
- '2' => {
34
- 'name' => 'Epiphany',
35
- 'date' => '2014-01-06',
36
- },
37
- }
38
- end
39
-
40
- def update(params)
41
- form = HolidaySpec::HolidayForm.new(:holidays_attributes => params)
42
- if form.save
43
- ids = form.holidays.collect(&:id)
44
- params.each_with_index do |(key, attributes), index|
45
- attributes['id'] = ids[index]
46
- end
47
- true
48
- end
49
- end
50
-
51
- it 'will return holidays including updated ones' do
52
- HolidaySpec::Holiday.create!(:name => 'New Year', :date => '2014-01-01')
53
- form = HolidaySpec::HolidayForm.new(:holidays_attributes => params.slice('2'))
54
- expect(form.holidays.collect(&:name)).to eq(["New Year", "Epiphany"])
55
- end
56
-
57
- it 'can create a list of holidays' do
58
- expect(update(params)).to eq(true)
59
-
60
- holidays = HolidaySpec::Holiday.order(:date)
61
- expect(holidays.collect(&:name)).to eq(["New Year", "Epiphany"])
62
- expect(holidays.collect(&:date)).to eq([Date.civil(2014, 1, 1), Date.civil(2014, 1, 6)])
63
- end
64
-
65
- it 'can update holidays' do
66
- update(params)
67
-
68
- params['1']['name'] += ' 2014'
69
- params['2']['name'] += ' 2014'
70
- expect(update(params)).to eq(true)
71
-
72
- holidays = HolidaySpec::Holiday.order(:date)
73
- expect(holidays.collect(&:name)).to eq(["New Year 2014", "Epiphany 2014"])
74
- expect(holidays.collect(&:date)).to eq([Date.civil(2014, 1, 1), Date.civil(2014, 1, 6)])
75
- end
76
-
77
- it 'can destroy holidays' do
78
- update(params)
79
-
80
- params['1']['_destroy'] = '1'
81
- expect(update(params)).to eq(true)
82
-
83
- holidays = HolidaySpec::Holiday.order(:date)
84
- expect(holidays.collect(&:name)).to eq(["Epiphany"])
85
- expect(holidays.collect(&:date)).to eq([Date.civil(2014, 1, 6)])
86
- end
87
-
88
- it 'will not save if some fields are invalid' do
89
- update(params)
90
-
91
- params['1']['name'] = '-'
92
- params['1']['_destroy'] = '1'
93
- params['2']['name'] = '' # invalid
94
- expect(update(params)).to be_falsey
95
-
96
- holidays = HolidaySpec::Holiday.order(:date)
97
- expect(holidays.collect(&:name)).to eq(["New Year", "Epiphany"])
98
- expect(holidays.collect(&:date)).to eq([Date.civil(2014, 1, 1), Date.civil(2014, 1, 6)])
99
- end
100
-
101
-
102
- end
@@ -1,110 +0,0 @@
1
- # Usecase: Create a STI record, form model decides which type
2
-
3
- require 'spec_helper'
4
-
5
- ActiveRecord::Migration.class_eval do
6
- create_table :shapes do |t|
7
- t.string :type
8
- t.integer :radius
9
- t.integer :length
10
- t.integer :width
11
- end
12
- end
13
-
14
- module ShapeSpec
15
-
16
- class Shape < ActiveType::Record
17
- end
18
-
19
- class Circle < Shape
20
- validates :radius, :presence => true
21
- end
22
-
23
- class Rectangle < Shape
24
- validates :length, :width, :presence => true
25
- end
26
-
27
- class ShapeForm < ActiveType::Object
28
- nests_one :child
29
-
30
- def child_type=(type)
31
- case type
32
- when 'circle'
33
- if child
34
- self.child = self.child.becomes(Circle)
35
- else
36
- self.child = Circle.new
37
- end
38
- when 'rectangle'
39
- if child
40
- self.child = self.child.becomes(Rectangle)
41
- else
42
- self.child = Rectangle.new
43
- end
44
- end
45
- end
46
- end
47
-
48
- end
49
-
50
-
51
- describe ShapeSpec::ShapeForm do
52
-
53
- let(:form) { ShapeSpec::ShapeForm.new }
54
-
55
- def update(params)
56
- form.child_type = params[:type]
57
- form.child_attributes = params.except(:type)
58
- form.save
59
- end
60
-
61
- it 'can create a circle' do
62
- params = {
63
- 'type' => 'circle',
64
- 'radius' => '20'
65
- }.with_indifferent_access
66
-
67
- expect(update(params)).to eq(true)
68
-
69
- expect(ShapeSpec::Circle.all.collect(&:radius)).to eq([20])
70
- expect(ShapeSpec::Rectangle.count).to eq(0)
71
- end
72
-
73
- it 'can create a rectangle' do
74
- params = {
75
- 'type' => 'rectangle',
76
- 'length' => '100',
77
- 'width' => '30'
78
- }.with_indifferent_access
79
-
80
- expect(update(params)).to eq(true)
81
-
82
- expect(ShapeSpec::Circle.count).to eq(0)
83
- expect(ShapeSpec::Rectangle.all.collect(&:length)).to eq([100])
84
- expect(ShapeSpec::Rectangle.all.collect(&:width)).to eq([30])
85
- end
86
-
87
- it 'can update' do
88
- params = {
89
- 'type' => 'circle',
90
- 'radius' => '20'
91
- }.with_indifferent_access
92
- update(params)
93
-
94
- params['radius'] = '30'
95
- expect(update(params)).to eq(true)
96
-
97
- expect(ShapeSpec::Circle.all.collect(&:radius)).to eq([30])
98
- end
99
-
100
- it 'has validations' do
101
- params = {
102
- 'type' => 'circle'
103
- }.with_indifferent_access
104
-
105
- expect(update(params)).to be_falsey
106
-
107
- expect(form.child.errors['radius']).to eq(["can't be blank"])
108
- end
109
-
110
- end
@@ -1,101 +0,0 @@
1
- # Usecase: implement a sign in form
2
- # The sign in is not tied to a database record
3
-
4
- require 'spec_helper'
5
-
6
- module SignInSpec
7
-
8
- class SignIn < ActiveType::Object
9
- attribute :email, :string
10
- attribute :password, :string
11
-
12
- validates :email, :presence => true
13
- validates :password, :presence => true
14
-
15
- validate :if => :password do |sign_in|
16
- errors.add(:password, 'is not correct') unless sign_in.password == "correct password"
17
- end
18
-
19
- after_save :set_session
20
-
21
- def set_session
22
- end
23
- end
24
-
25
- end
26
-
27
- describe SignInSpec::SignIn do
28
-
29
- describe 'with missing credentials' do
30
-
31
- it 'is invalid' do
32
- expect(subject).not_to be_valid
33
- end
34
-
35
- it 'has errors' do
36
- subject.valid?
37
- expect(subject.errors[:email]).to eq(["can't be blank"])
38
- expect(subject.errors[:password]).to eq(["can't be blank"])
39
- end
40
-
41
- it 'does not save' do
42
- expect(subject.save).to be_falsey
43
- end
44
-
45
- it 'does not set the session' do
46
- expect(subject).not_to receive :set_session
47
- subject.save
48
- end
49
-
50
- end
51
-
52
- describe 'with invalid credentials' do
53
-
54
- before do
55
- subject.email = "email"
56
- subject.password = "incorrect password"
57
- end
58
-
59
- it 'is invalid' do
60
- expect(subject).not_to be_valid
61
- end
62
-
63
- it 'has errors' do
64
- subject.valid?
65
- expect(subject.errors[:password]).to eq(["is not correct"])
66
- end
67
-
68
- it 'does not save' do
69
- expect(subject.save).to be_falsey
70
- end
71
-
72
- it 'does not set the session' do
73
- expect(subject).not_to receive :set_session
74
- subject.save
75
- end
76
-
77
- end
78
-
79
- describe 'with valid credentials' do
80
-
81
- before do
82
- subject.email = "email"
83
- subject.password = "correct password"
84
- end
85
-
86
- it 'is invalid' do
87
- expect(subject).to be_valid
88
- end
89
-
90
- it 'does save' do
91
- expect(subject.save).to eq(true)
92
- end
93
-
94
- it 'sets the session' do
95
- expect(subject).to receive :set_session
96
- subject.save
97
- end
98
-
99
- end
100
-
101
- end
@@ -1,102 +0,0 @@
1
- # Usecase: implement a sign up form
2
- # The sign up is tied to a user model
3
-
4
-
5
- require 'spec_helper'
6
-
7
- ActiveRecord::Migration.class_eval do
8
- create_table :users do |t|
9
- t.string :email
10
- t.string :password
11
- end
12
- end
13
-
14
-
15
- module SignUpSpec
16
-
17
- class User < ActiveType::Record
18
- validates :email, :presence => true
19
- validates :password, :presence => true
20
- end
21
-
22
-
23
- class SignUp < ActiveType::Record[User]
24
- attribute :terms, :boolean
25
-
26
- validates :terms, :acceptance => {:allow_nil => false, :accept => true}
27
-
28
- after_create :send_welcome_email
29
-
30
- def send_welcome_email
31
- end
32
- end
33
-
34
- end
35
-
36
-
37
- describe SignUpSpec::User do
38
-
39
- it 'is valid without a password confirmation' do
40
- subject.email = "email"
41
- subject.password = "password"
42
-
43
- expect(subject).to be_valid
44
- end
45
-
46
- end
47
-
48
-
49
- describe SignUpSpec::SignUp do
50
-
51
- it 'is invalid without an email' do
52
- subject.password = "password"
53
- subject.terms = true
54
-
55
- expect(subject).not_to be_valid
56
- expect(subject.errors['email']).to eq(["can't be blank"])
57
- end
58
-
59
- it 'is invalid without accepted terms' do
60
- subject.email = "email"
61
- subject.password = "password"
62
-
63
- expect(subject).not_to be_valid
64
- expect(subject.errors['terms']).to eq(["must be accepted"])
65
- end
66
-
67
- context 'with invalid data' do
68
-
69
- it 'does not save' do
70
- expect(subject.save).to be_falsey
71
- end
72
-
73
- it 'does not send an email' do
74
- expect(subject).not_to receive :send_welcome_email
75
- subject.save
76
- end
77
-
78
- end
79
-
80
- context 'with valid data' do
81
-
82
- before do
83
- subject.email = "email"
84
- subject.password = "password"
85
- subject.terms = "1"
86
- end
87
-
88
- it 'does save' do
89
- subject.valid?
90
- expect(subject.save).to eq(true)
91
- end
92
-
93
- it 'sends the email' do
94
- expect(subject).to receive :send_welcome_email
95
-
96
- subject.save
97
- end
98
-
99
- end
100
-
101
-
102
- end
@@ -1,41 +0,0 @@
1
- class User < ::ActiveRecord::Base
2
- end
3
-
4
- class Foo < ::ActiveType::Record[User]
5
- def new
6
- allocate
7
- end
8
- end
9
-
10
-
11
- shared_examples_for "ActiveRecord-like accessors" do |attributes|
12
- it 'setup the virtual_attributes instance variable lazy' do
13
- expect(Foo.new.virtual_attributes).to eq({})
14
- end
15
-
16
- it 'setup the virtual_attributes_cache instance variable lazy' do
17
- expect(Foo.new.virtual_attributes_cache).to eq({})
18
- end
19
-
20
- it 'allows to read and write' do
21
- attributes.each do |key, value|
22
- subject.send("#{key}=", value)
23
- expect(subject.send(key)).to eq(value)
24
- end
25
- end
26
-
27
- it 'allows to read via []' do
28
- attributes.each do |key, value|
29
- subject.send("#{key}=", value)
30
- expect(subject[key]).to eq(value)
31
- end
32
- end
33
-
34
- it 'allows to write via []=' do
35
- attributes.each do |key, value|
36
- subject[key] = value
37
- expect(subject.send(key)).to eq(value)
38
- end
39
- end
40
-
41
- end
@@ -1,17 +0,0 @@
1
- shared_examples_for 'a belongs_to association' do |association, klass|
2
-
3
- let(:record) { klass.create }
4
-
5
- it 'sets the id when assigning a record' do
6
- subject.send("#{association}=", record)
7
-
8
- expect(subject.send("#{association}_id")).to eq(record.id)
9
- end
10
-
11
- it 'sets the record when assigning an id' do
12
- subject.send("#{association}_id=", record.id)
13
-
14
- expect(subject.send("#{association}")).to eq(record)
15
- end
16
-
17
- end