active_data 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rspec +0 -1
  4. data/.rvmrc +1 -1
  5. data/.travis.yml +13 -6
  6. data/Appraisals +7 -0
  7. data/Gemfile +1 -5
  8. data/Guardfile +68 -15
  9. data/README.md +144 -2
  10. data/active_data.gemspec +19 -11
  11. data/gemfiles/rails.4.0.gemfile +14 -0
  12. data/gemfiles/rails.4.1.gemfile +14 -0
  13. data/gemfiles/rails.4.2.gemfile +14 -0
  14. data/gemfiles/rails.5.0.gemfile +14 -0
  15. data/lib/active_data.rb +120 -3
  16. data/lib/active_data/active_record/associations.rb +50 -0
  17. data/lib/active_data/active_record/nested_attributes.rb +24 -0
  18. data/lib/active_data/config.rb +40 -0
  19. data/lib/active_data/errors.rb +93 -0
  20. data/lib/active_data/extensions.rb +33 -0
  21. data/lib/active_data/model.rb +16 -74
  22. data/lib/active_data/model/associations.rb +84 -15
  23. data/lib/active_data/model/associations/base.rb +79 -0
  24. data/lib/active_data/model/associations/collection/embedded.rb +12 -0
  25. data/lib/active_data/model/associations/collection/proxy.rb +32 -0
  26. data/lib/active_data/model/associations/collection/referenced.rb +26 -0
  27. data/lib/active_data/model/associations/embeds_many.rb +124 -18
  28. data/lib/active_data/model/associations/embeds_one.rb +90 -15
  29. data/lib/active_data/model/associations/nested_attributes.rb +180 -0
  30. data/lib/active_data/model/associations/references_many.rb +96 -0
  31. data/lib/active_data/model/associations/references_one.rb +83 -0
  32. data/lib/active_data/model/associations/reflections/base.rb +100 -0
  33. data/lib/active_data/model/associations/reflections/embeds_many.rb +25 -0
  34. data/lib/active_data/model/associations/reflections/embeds_one.rb +49 -0
  35. data/lib/active_data/model/associations/reflections/reference_reflection.rb +45 -0
  36. data/lib/active_data/model/associations/reflections/references_many.rb +28 -0
  37. data/lib/active_data/model/associations/reflections/references_one.rb +28 -0
  38. data/lib/active_data/model/associations/validations.rb +63 -0
  39. data/lib/active_data/model/attributes.rb +247 -0
  40. data/lib/active_data/model/attributes/attribute.rb +73 -0
  41. data/lib/active_data/model/attributes/base.rb +116 -0
  42. data/lib/active_data/model/attributes/collection.rb +17 -0
  43. data/lib/active_data/model/attributes/dictionary.rb +26 -0
  44. data/lib/active_data/model/attributes/localized.rb +42 -0
  45. data/lib/active_data/model/attributes/reference_many.rb +21 -0
  46. data/lib/active_data/model/attributes/reference_one.rb +42 -0
  47. data/lib/active_data/model/attributes/reflections/attribute.rb +55 -0
  48. data/lib/active_data/model/attributes/reflections/base.rb +62 -0
  49. data/lib/active_data/model/attributes/reflections/collection.rb +10 -0
  50. data/lib/active_data/model/attributes/reflections/dictionary.rb +13 -0
  51. data/lib/active_data/model/attributes/reflections/localized.rb +43 -0
  52. data/lib/active_data/model/attributes/reflections/reference_many.rb +10 -0
  53. data/lib/active_data/model/attributes/reflections/reference_one.rb +58 -0
  54. data/lib/active_data/model/attributes/reflections/represents.rb +55 -0
  55. data/lib/active_data/model/attributes/represents.rb +64 -0
  56. data/lib/active_data/model/callbacks.rb +71 -0
  57. data/lib/active_data/model/conventions.rb +35 -0
  58. data/lib/active_data/model/dirty.rb +77 -0
  59. data/lib/active_data/model/lifecycle.rb +307 -0
  60. data/lib/active_data/model/localization.rb +21 -0
  61. data/lib/active_data/model/persistence.rb +57 -0
  62. data/lib/active_data/model/primary.rb +51 -0
  63. data/lib/active_data/model/scopes.rb +77 -0
  64. data/lib/active_data/model/validations.rb +27 -0
  65. data/lib/active_data/model/validations/associated.rb +19 -0
  66. data/lib/active_data/model/validations/nested.rb +39 -0
  67. data/lib/active_data/railtie.rb +7 -0
  68. data/lib/active_data/version.rb +1 -1
  69. data/spec/lib/active_data/active_record/associations_spec.rb +149 -0
  70. data/spec/lib/active_data/active_record/nested_attributes_spec.rb +16 -0
  71. data/spec/lib/active_data/config_spec.rb +44 -0
  72. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +362 -52
  73. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +250 -31
  74. data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +23 -0
  75. data/spec/lib/active_data/model/associations/references_many_spec.rb +196 -0
  76. data/spec/lib/active_data/model/associations/references_one_spec.rb +134 -0
  77. data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +144 -0
  78. data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +116 -0
  79. data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +255 -0
  80. data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +208 -0
  81. data/spec/lib/active_data/model/associations/validations_spec.rb +153 -0
  82. data/spec/lib/active_data/model/associations_spec.rb +189 -0
  83. data/spec/lib/active_data/model/attributes/attribute_spec.rb +144 -0
  84. data/spec/lib/active_data/model/attributes/base_spec.rb +82 -0
  85. data/spec/lib/active_data/model/attributes/collection_spec.rb +73 -0
  86. data/spec/lib/active_data/model/attributes/dictionary_spec.rb +93 -0
  87. data/spec/lib/active_data/model/attributes/localized_spec.rb +88 -33
  88. data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +72 -0
  89. data/spec/lib/active_data/model/attributes/reflections/base_spec.rb +56 -0
  90. data/spec/lib/active_data/model/attributes/reflections/collection_spec.rb +37 -0
  91. data/spec/lib/active_data/model/attributes/reflections/dictionary_spec.rb +43 -0
  92. data/spec/lib/active_data/model/attributes/reflections/localized_spec.rb +37 -0
  93. data/spec/lib/active_data/model/attributes/reflections/represents_spec.rb +70 -0
  94. data/spec/lib/active_data/model/attributes/represents_spec.rb +153 -0
  95. data/spec/lib/active_data/model/attributes_spec.rb +243 -0
  96. data/spec/lib/active_data/model/callbacks_spec.rb +338 -0
  97. data/spec/lib/active_data/model/conventions_spec.rb +12 -0
  98. data/spec/lib/active_data/model/dirty_spec.rb +75 -0
  99. data/spec/lib/active_data/model/lifecycle_spec.rb +330 -0
  100. data/spec/lib/active_data/model/nested_attributes.rb +202 -0
  101. data/spec/lib/active_data/model/persistence_spec.rb +47 -0
  102. data/spec/lib/active_data/model/primary_spec.rb +84 -0
  103. data/spec/lib/active_data/model/scopes_spec.rb +88 -0
  104. data/spec/lib/active_data/model/typecasting_spec.rb +192 -0
  105. data/spec/lib/active_data/model/validations/associated_spec.rb +94 -0
  106. data/spec/lib/active_data/model/validations/nested_spec.rb +93 -0
  107. data/spec/lib/active_data/model/validations_spec.rb +31 -0
  108. data/spec/lib/active_data/model_spec.rb +1 -32
  109. data/spec/lib/active_data_spec.rb +12 -0
  110. data/spec/spec_helper.rb +39 -0
  111. data/spec/support/model_helpers.rb +10 -0
  112. metadata +246 -54
  113. data/gemfiles/Gemfile.rails-3 +0 -14
  114. data/lib/active_data/attributes/base.rb +0 -69
  115. data/lib/active_data/attributes/localized.rb +0 -42
  116. data/lib/active_data/model/associations/association.rb +0 -30
  117. data/lib/active_data/model/attributable.rb +0 -122
  118. data/lib/active_data/model/collectionizable.rb +0 -55
  119. data/lib/active_data/model/collectionizable/proxy.rb +0 -42
  120. data/lib/active_data/model/extensions.rb +0 -9
  121. data/lib/active_data/model/extensions/array.rb +0 -24
  122. data/lib/active_data/model/extensions/big_decimal.rb +0 -17
  123. data/lib/active_data/model/extensions/boolean.rb +0 -38
  124. data/lib/active_data/model/extensions/date.rb +0 -17
  125. data/lib/active_data/model/extensions/date_time.rb +0 -17
  126. data/lib/active_data/model/extensions/float.rb +0 -17
  127. data/lib/active_data/model/extensions/hash.rb +0 -22
  128. data/lib/active_data/model/extensions/integer.rb +0 -17
  129. data/lib/active_data/model/extensions/localized.rb +0 -22
  130. data/lib/active_data/model/extensions/object.rb +0 -17
  131. data/lib/active_data/model/extensions/string.rb +0 -17
  132. data/lib/active_data/model/extensions/time.rb +0 -17
  133. data/lib/active_data/model/localizable.rb +0 -31
  134. data/lib/active_data/model/nested_attributes.rb +0 -58
  135. data/lib/active_data/model/parameterizable.rb +0 -29
  136. data/lib/active_data/validations.rb +0 -7
  137. data/lib/active_data/validations/associated.rb +0 -17
  138. data/spec/lib/active_data/model/attributable_spec.rb +0 -191
  139. data/spec/lib/active_data/model/collectionizable_spec.rb +0 -60
  140. data/spec/lib/active_data/model/nested_attributes_spec.rb +0 -67
  141. data/spec/lib/active_data/model/type_cast_spec.rb +0 -116
  142. data/spec/lib/active_data/validations/associated_spec.rb +0 -88
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Date
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- value.to_date rescue nil
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- Date.send :include, ActiveData::Model::Extensions::Date
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module DateTime
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- value.to_datetime rescue nil
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- DateTime.send :include, ActiveData::Model::Extensions::DateTime
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Float
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- Float(value) rescue nil if value
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- Float.send :include, ActiveData::Model::Extensions::Float
@@ -1,22 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Hash
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- case value
10
- when ::Hash then
11
- value
12
- else
13
- nil
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
-
22
- Hash.send :include, ActiveData::Model::Extensions::Hash
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Integer
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- Float(value).to_i rescue nil if value
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- Integer.send :include, ActiveData::Model::Extensions::Integer
@@ -1,22 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Localized
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- case value
10
- when ::Hash then
11
- value.stringify_keys
12
- else
13
- nil
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
-
22
- Localized.send :include, ActiveData::Model::Extensions::Localized
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Object
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- value
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- Object.send :include, ActiveData::Model::Extensions::Object
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module String
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- value.to_s if value.present?
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- String.send :include, ActiveData::Model::Extensions::String
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Time
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- value.to_time rescue nil
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- Time.send :include, ActiveData::Model::Extensions::Time
@@ -1,31 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Localizable
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- end
8
-
9
- module ClassMethods
10
- def fallbacks locale
11
- ::I18n.respond_to?(:fallbacks) ? ::I18n.fallbacks[locale] : [locale]
12
- end
13
-
14
- def locale
15
- I18n.locale
16
- end
17
- end
18
-
19
- def read_localized_attribute name, locale = self.class.locale
20
- translations = read_attribute(name.to_s)
21
- translations[self.class.fallbacks(locale).detect { |fallback| translations[fallback.to_s] }.to_s]
22
- end
23
- alias_method :read_localized_attribute_before_type_cast, :read_localized_attribute
24
-
25
- def write_localized_attribute name, value, locale = self.class.locale
26
- translations = read_attribute(name.to_s)
27
- write_attribute(name, translations.merge(locale.to_s => value))
28
- end
29
- end
30
- end
31
- end
@@ -1,58 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module NestedAttributes
4
- extend ActiveSupport::Concern
5
-
6
- module ClassMethods
7
-
8
- def nested_attributes? association_name
9
- method_defined?(:"#{association_name}_attributes=")
10
- end
11
-
12
- def accepts_nested_attributes_for *attr_names
13
- attr_names.each do |association_name|
14
- reflection = reflect_on_association association_name
15
- type = (reflection.collection? ? :collection : :one_to_one)
16
-
17
- class_eval <<-EOS, __FILE__, __LINE__ + 1
18
- if method_defined?(:#{association_name}_attributes=)
19
- remove_method(:#{association_name}_attributes=)
20
- end
21
- def #{association_name}_attributes=(attributes)
22
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
23
- end
24
- EOS
25
- end
26
- end
27
-
28
- end
29
-
30
- def assign_nested_attributes_for_collection_association(association_name, attributes_collection, assignment_opts = {})
31
- unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
32
- raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
33
- end
34
-
35
- if attributes_collection.is_a? Hash
36
- keys = attributes_collection.keys
37
- attributes_collection = if keys.include?('id') || keys.include?(:id)
38
- Array.wrap(attributes_collection)
39
- else
40
- attributes_collection.values
41
- end
42
- end
43
-
44
- reflection = self.class.reflect_on_association association_name
45
-
46
- send "#{association_name}=", attributes_collection
47
- end
48
-
49
- def assign_nested_attributes_for_one_to_one_association(association_name, attributes, assignment_opts = {})
50
- unless attributes.is_a?(Hash)
51
- raise ArgumentError, "Hash expected, got #{attributes.class.name} (#{attributes.inspect})"
52
- end
53
-
54
- send "#{association_name}=", attributes
55
- end
56
- end
57
- end
58
- end
@@ -1,29 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Parameterizable
4
- extend ActiveSupport::Concern
5
-
6
- def to_params options = nil
7
- hash = serializable_hash options
8
-
9
- self.class.association_names.each do |association_name|
10
- if self.class.nested_attributes? association_name
11
- records = send(association_name)
12
- hash["#{association_name}_attributes"] = if records.is_a?(Enumerable)
13
- attributes = {}
14
- records.each_with_index do |a, i|
15
- key = a.has_attribute?(:id) && a.id? ? a.id : i
16
- attributes[key.to_s] = a.serializable_hash
17
- end
18
- attributes
19
- else
20
- records.serializable_hash
21
- end
22
- end
23
- end
24
-
25
- hash
26
- end
27
- end
28
- end
29
- end
@@ -1,7 +0,0 @@
1
- require 'active_data/validations/associated'
2
-
3
- module ActiveData
4
- module Validations
5
- extend ActiveSupport::Concern
6
- end
7
- end
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Validations
3
- class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
4
- def validate_each(record, attribute, value)
5
- if Array.wrap(value).reject { |r| r.respond_to?(:valid?) && r.valid?(record.validation_context) }.any?
6
- record.errors.add(attribute, :invalid, options.merge(:value => value))
7
- end
8
- end
9
- end
10
-
11
- module ClassMethods
12
- def validates_associated(*attr_names)
13
- validates_with AssociatedValidator, _merge_attributes(attr_names)
14
- end
15
- end
16
- end
17
- end
@@ -1,191 +0,0 @@
1
- # encoding: UTF-8
2
- require 'spec_helper'
3
-
4
- describe ActiveData::Model::Attributable do
5
-
6
- let(:klass) do
7
- Class.new do
8
- include ActiveData::Model::Attributable
9
- attr_reader :name
10
-
11
- attribute :hello
12
- attribute :string, type: String, default_blank: true, default: ->(record){ record.name }
13
- attribute :count, type: Integer, default: 10
14
- attribute(:calc, type: Integer) { 2 + 3 }
15
- attribute :enum, type: Integer, in: [1, 2, 3]
16
- attribute :foo, type: Boolean, default: false
17
-
18
- def initialize name = nil
19
- @attributes = self.class.initialize_attributes
20
- @name = name
21
- end
22
- end
23
- end
24
-
25
- context do
26
- subject { klass.new('world') }
27
- specify { klass.enum_values.should == [1, 2, 3] }
28
- its(:attributes) { should == { hello: nil, count: 10, calc: 5, enum: nil, string: 'world', foo: false } }
29
- its(:present_attributes) { should == { count: 10, calc: 5, string: 'world', foo: false } }
30
- its(:name) { should == 'world' }
31
- its(:hello) { should be_nil }
32
- its(:count) { should == 10 }
33
- its(:calc) { should == 5 }
34
- specify { expect { subject.hello = 'worlds' } .to change { subject.hello } .from(nil).to('worlds') }
35
- specify { expect { subject.count = 20 } .to change { subject.count } .from(10).to(20) }
36
- specify { expect { subject.calc = 15 } .to change { subject.calc } .from(5).to(15) }
37
- end
38
-
39
- context 'calculating default values' do
40
- let(:klass) do
41
- Class.new do
42
- include ActiveData::Model::Attributable
43
-
44
- attribute(:rand, type: String) { SecureRandom.uuid }
45
-
46
- def initialize
47
- @attributes = self.class.initialize_attributes
48
- end
49
- end
50
- end
51
-
52
- subject { klass.new }
53
- specify { subject.rand.should == subject.rand }
54
- specify { subject.rand.should_not == klass.new.rand }
55
- end
56
-
57
- context 'default_blank' do
58
- let(:klass) do
59
- Class.new do
60
- include ActiveData::Model::Attributable
61
-
62
- attribute :string1, type: String, default_blank: true, default: 'default'
63
- attribute :string2, type: String, default: 'default'
64
-
65
- def initialize attributes = {}
66
- @attributes = self.class.initialize_attributes
67
- self.attributes = attributes
68
- end
69
- end
70
- end
71
-
72
- specify { klass.new.string1.should == 'default' }
73
- specify { klass.new.string2.should == 'default' }
74
- specify { klass.new(string1: '').string1.should == 'default' }
75
- specify { klass.new(string2: '').string2.should == '' }
76
- specify { klass.new(string1: 'hello').string1.should == 'hello' }
77
- specify { klass.new(string2: 'hello').string2.should == 'hello' }
78
- end
79
-
80
- context 'default_blank with boolean' do
81
- let(:klass) do
82
- Class.new do
83
- include ActiveData::Model::Attributable
84
-
85
- attribute :boolean1, type: Boolean, default_blank: true, default: true
86
- attribute :boolean2, type: Boolean, default: true
87
- attribute :boolean3, type: Boolean, default_blank: true, default: false
88
- attribute :boolean4, type: Boolean, default: false
89
-
90
- def initialize attributes = {}
91
- @attributes = self.class.initialize_attributes
92
- self.attributes = attributes
93
- end
94
- end
95
- end
96
-
97
- specify { klass.new.boolean1.should == true }
98
- specify { klass.new.boolean2.should == true }
99
- specify { klass.new.boolean3.should == false }
100
- specify { klass.new.boolean4.should == false }
101
- specify { klass.new(boolean1: '').boolean1.should == true }
102
- specify { klass.new(boolean2: '').boolean2.should == true }
103
- specify { klass.new(boolean3: '').boolean3.should == false }
104
- specify { klass.new(boolean4: '').boolean4.should == false }
105
- specify { klass.new(boolean1: false).boolean1.should == false }
106
- specify { klass.new(boolean2: false).boolean2.should == false }
107
- specify { klass.new(boolean3: false).boolean3.should == false }
108
- specify { klass.new(boolean4: false).boolean4.should == false }
109
- specify { klass.new(boolean1: true).boolean1.should == true }
110
- specify { klass.new(boolean2: true).boolean2.should == true }
111
- specify { klass.new(boolean3: true).boolean3.should == true }
112
- specify { klass.new(boolean4: true).boolean4.should == true }
113
- end
114
-
115
- context 'attribute caching' do
116
- subject { klass.new('world') }
117
-
118
- context do
119
- before do
120
- subject.send(:attributes_cache).should_not_receive(:[])
121
- end
122
-
123
- specify { subject.hello }
124
- end
125
-
126
- context do
127
- before do
128
- subject.hello
129
- subject.send(:attributes_cache).should_receive(:[]).with(:hello).once
130
- end
131
-
132
- specify { subject.hello }
133
- end
134
-
135
- context 'attribute cache reset' do
136
- before do
137
- subject.hello = 'blabla'
138
- subject.hello
139
- subject.hello = 'newnewnew'
140
- end
141
-
142
- specify { subject.hello.should == 'newnewnew' }
143
- end
144
- end
145
-
146
- context 'inheritance' do
147
- let!(:ancestor) do
148
- Class.new do
149
- include ActiveData::Model::Attributable
150
- attribute :foo
151
- end
152
- end
153
-
154
- let!(:descendant1) do
155
- Class.new ancestor do
156
- attribute :bar
157
- end
158
- end
159
-
160
- let!(:descendant2) do
161
- Class.new ancestor do
162
- attribute :baz
163
- attribute :moo
164
- end
165
- end
166
-
167
- specify { ancestor._attributes.keys.should == [:foo] }
168
- specify { ancestor.instance_methods.should include :foo, :foo= }
169
- specify { ancestor.instance_methods.should_not include :bar, :bar=, :baz, :baz= }
170
- specify { descendant1._attributes.keys.should == [:foo, :bar] }
171
- specify { descendant1.instance_methods.should include :foo, :foo=, :bar, :bar= }
172
- specify { descendant1.instance_methods.should_not include :baz, :baz= }
173
- specify { descendant2._attributes.keys.should == [:foo, :baz, :moo] }
174
- specify { descendant2.instance_methods.should include :foo, :foo=, :baz, :baz=, :moo, :moo= }
175
- specify { descendant2.instance_methods.should_not include :bar, :bar= }
176
- end
177
-
178
- context '#write_attributes' do
179
- subject { klass.new('world') }
180
-
181
- specify { expect { subject.write_attributes(strange: 'value') }.to raise_error NoMethodError }
182
-
183
- context do
184
- before { subject.write_attributes('hello' => 'blabla', count: 20) }
185
- specify do
186
- subject.attributes.should == { hello: 'blabla', count: 20, calc: 5, enum: nil, string: 'world', foo: false }
187
- end
188
- end
189
- end
190
-
191
- end