smooth_operator 0.4.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +9 -9
- data/.gitignore +2 -1
- data/.rspec +4 -0
- data/Gemfile +13 -0
- data/README.md +258 -10
- data/console.rb +44 -0
- data/lib/smooth_operator/array_with_meta_data.rb +31 -0
- data/lib/smooth_operator/attribute_assignment.rb +102 -0
- data/lib/smooth_operator/attribute_methods.rb +87 -0
- data/lib/smooth_operator/attributes/base.rb +107 -0
- data/lib/smooth_operator/attributes/dirty.rb +29 -0
- data/lib/smooth_operator/attributes/normal.rb +15 -0
- data/lib/smooth_operator/delegation.rb +60 -0
- data/lib/smooth_operator/finder_methods.rb +43 -0
- data/lib/smooth_operator/helpers.rb +79 -0
- data/lib/smooth_operator/model_schema.rb +81 -0
- data/lib/smooth_operator/open_struct.rb +37 -0
- data/lib/smooth_operator/operator.rb +145 -0
- data/lib/smooth_operator/operators/faraday.rb +75 -0
- data/lib/smooth_operator/operators/typhoeus.rb +77 -0
- data/lib/smooth_operator/persistence.rb +144 -0
- data/lib/smooth_operator/relation/array_relation.rb +13 -0
- data/lib/smooth_operator/relation/association_reflection.rb +75 -0
- data/lib/smooth_operator/relation/associations.rb +75 -0
- data/lib/smooth_operator/relation/reflection.rb +41 -0
- data/lib/smooth_operator/relation/single_relation.rb +14 -0
- data/lib/smooth_operator/remote_call/base.rb +80 -0
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +20 -0
- data/lib/smooth_operator/remote_call/errors/timeout.rb +20 -0
- data/lib/smooth_operator/remote_call/faraday.rb +19 -0
- data/lib/smooth_operator/remote_call/typhoeus.rb +19 -0
- data/lib/smooth_operator/serialization.rb +79 -0
- data/lib/smooth_operator/translation.rb +27 -0
- data/lib/smooth_operator/validations.rb +15 -0
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +26 -5
- data/smooth_operator.gemspec +12 -3
- data/spec/factories/user_factory.rb +34 -0
- data/spec/require_helper.rb +11 -0
- data/spec/smooth_operator/attribute_assignment_spec.rb +351 -0
- data/spec/smooth_operator/attributes_dirty_spec.rb +53 -0
- data/spec/smooth_operator/delegation_spec.rb +139 -0
- data/spec/smooth_operator/finder_methods_spec.rb +105 -0
- data/spec/smooth_operator/model_schema_spec.rb +31 -0
- data/spec/smooth_operator/operator_spec.rb +46 -0
- data/spec/smooth_operator/persistence_spec.rb +424 -0
- data/spec/smooth_operator/remote_call_spec.rb +320 -0
- data/spec/smooth_operator/serialization_spec.rb +80 -0
- data/spec/smooth_operator/validations_spec.rb +42 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/helpers/persistence_helper.rb +38 -0
- data/spec/support/localhost_server.rb +97 -0
- data/spec/support/models/address.rb +14 -0
- data/spec/support/models/comment.rb +3 -0
- data/spec/support/models/post.rb +13 -0
- data/spec/support/models/user.rb +41 -0
- data/spec/support/models/user_with_address_and_posts.rb +89 -0
- data/spec/support/test_server.rb +165 -0
- metadata +108 -18
- data/lib/smooth_operator/base.rb +0 -30
- data/lib/smooth_operator/core.rb +0 -218
- data/lib/smooth_operator/http_handlers/typhoeus/base.rb +0 -58
- data/lib/smooth_operator/http_handlers/typhoeus/orm.rb +0 -34
- data/lib/smooth_operator/http_handlers/typhoeus/remote_call.rb +0 -28
- data/lib/smooth_operator/operator/base.rb +0 -43
- data/lib/smooth_operator/operator/exceptions.rb +0 -64
- data/lib/smooth_operator/operator/orm.rb +0 -118
- data/lib/smooth_operator/operator/remote_call.rb +0 -84
@@ -0,0 +1,27 @@
|
|
1
|
+
module SmoothOperator
|
2
|
+
|
3
|
+
module Translation
|
4
|
+
|
5
|
+
def human_attribute_name(attribute_key_name, options = {})
|
6
|
+
_translate("attributes.#{model_name.i18n_key}.#{attribute_key_name}", options = {})
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
private ###################### PRIVATE #########################
|
11
|
+
|
12
|
+
def _translate(namespace = '', options = {})
|
13
|
+
no_translation = "-- no translation --"
|
14
|
+
|
15
|
+
defaults = ["smooth_operator.#{namespace}".to_sym]
|
16
|
+
defaults << "activerecord.#{namespace}".to_sym
|
17
|
+
defaults << options[:default] if options[:default]
|
18
|
+
defaults.flatten!
|
19
|
+
defaults << no_translation
|
20
|
+
|
21
|
+
options = { count: 1, default: defaults }.merge!(options.except(:default))
|
22
|
+
I18n.translate(defaults.shift, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/smooth_operator.rb
CHANGED
@@ -1,7 +1,28 @@
|
|
1
|
+
require "smooth_operator/version"
|
2
|
+
require "smooth_operator/helpers"
|
3
|
+
require "smooth_operator/operator"
|
4
|
+
require "smooth_operator/persistence"
|
5
|
+
require "smooth_operator/translation"
|
6
|
+
require "smooth_operator/open_struct"
|
7
|
+
require "smooth_operator/finder_methods"
|
8
|
+
require "smooth_operator/relation/associations"
|
9
|
+
|
1
10
|
module SmoothOperator
|
2
|
-
|
3
|
-
end
|
11
|
+
class Base < OpenStruct::Base
|
4
12
|
|
5
|
-
|
6
|
-
|
7
|
-
|
13
|
+
extend FinderMethods
|
14
|
+
extend Translation if defined? I18n
|
15
|
+
|
16
|
+
include Operator
|
17
|
+
include Persistence
|
18
|
+
include FinderMethods
|
19
|
+
include Relation::Associations
|
20
|
+
|
21
|
+
self.strict_behaviour = true
|
22
|
+
|
23
|
+
def self.smooth_operator?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/smooth_operator.gemspec
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
|
4
7
|
require 'smooth_operator/version'
|
5
8
|
|
6
9
|
Gem::Specification.new do |spec|
|
@@ -9,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
9
12
|
spec.authors = ["João Gonçalves"]
|
10
13
|
spec.email = ["goncalves.joao@gmail.com"]
|
11
14
|
spec.description = %q{ActiveResource alternative}
|
12
|
-
spec.summary = %q{Simple and fully customizable alternative to ActiveResource,
|
15
|
+
spec.summary = %q{Simple and fully customizable alternative to ActiveResource, using faraday gem to stablish remote calls"}
|
13
16
|
spec.homepage = "https://github.com/goncalvesjoao/smooth_operator"
|
14
17
|
spec.license = "MIT"
|
15
18
|
|
@@ -17,7 +20,13 @@ Gem::Specification.new do |spec|
|
|
17
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
22
|
spec.require_paths = ["lib"]
|
20
|
-
|
23
|
+
|
21
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
|
25
|
+
|
26
|
+
spec.add_dependency "json"
|
27
|
+
spec.add_dependency "faraday", "~> 0.8.9"
|
28
|
+
spec.add_dependency "typhoeus", "~> 0.6.8"
|
29
|
+
|
30
|
+
# this is necessary if you want to typhoeus to correctly encode arrays
|
31
|
+
# spec.add_dependency "ethon", :git => 'https://github.com/goncalvesjoao/ethon'
|
23
32
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
|
3
|
+
factory :user, class: User::Base do
|
4
|
+
|
5
|
+
id 1
|
6
|
+
admin true
|
7
|
+
last_name 'Doe'
|
8
|
+
first_name 'John'
|
9
|
+
|
10
|
+
trait :with_address_and_posts do
|
11
|
+
address { { street: 'my_street' } }
|
12
|
+
# posts [{ id: 1, body: 'post1' }, { id: 2, body: 'post2' }]
|
13
|
+
posts [{ id: 1 }, { id: 2 }]
|
14
|
+
end
|
15
|
+
factory :user_with_address_and_posts, traits: [:with_address_and_posts]
|
16
|
+
|
17
|
+
trait :has_my_method do
|
18
|
+
my_method 'my_method'
|
19
|
+
end
|
20
|
+
factory :user_with_my_method, traits: [:with_address_and_posts, :has_my_method]
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
factory :white_list, class: User::Base do
|
25
|
+
id 1
|
26
|
+
first_name 'John'
|
27
|
+
end
|
28
|
+
|
29
|
+
factory :black_list, class: User::Base do
|
30
|
+
admin true
|
31
|
+
last_name 'Doe'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'smooth_operator'
|
6
|
+
|
7
|
+
Bundler.require :test, :default
|
8
|
+
|
9
|
+
Dir.chdir("spec/") do
|
10
|
+
Dir["support/**/*.rb"].each { |file| require file }
|
11
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
require 'date'
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe SmoothOperator::AttributeAssignment do
|
5
|
+
|
6
|
+
describe "#assign_attributes" do
|
7
|
+
|
8
|
+
describe "receiving data from server" do
|
9
|
+
subject { User::Base.new }
|
10
|
+
|
11
|
+
context "when receiving the option 'from_server = true'" do
|
12
|
+
before { subject.assign_attributes({}, from_server: true) }
|
13
|
+
|
14
|
+
it "#has_data_from_server and #from_server should return true" do
|
15
|
+
expect(subject.has_data_from_server).to be true
|
16
|
+
expect(subject.from_server).to be true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when receiving a Hash with meta_data on it" do
|
21
|
+
before { subject.assign_attributes({ user: attributes_for(:user), status: 1 }) }
|
22
|
+
|
23
|
+
it "#meta_data should reflect the receiving meta_data" do
|
24
|
+
expect(subject._meta_data).to eq({ "status" => 1 })
|
25
|
+
end
|
26
|
+
|
27
|
+
it "subject should NOT contain meta_data" do
|
28
|
+
expect{ subject.status }.to raise_error NoMethodError
|
29
|
+
end
|
30
|
+
|
31
|
+
it "subject should contain all other data" do
|
32
|
+
expect(subject.attributes).to eq(attributes_for(:user))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "white and black list" do
|
39
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
40
|
+
|
41
|
+
context "when there are no changes to attributes's white and black list" do
|
42
|
+
it 'it should return all attributes' do
|
43
|
+
expect(subject.to_hash).to eq(attributes_for(:user_with_address_and_posts))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when there are changes to attributes's white list" do
|
48
|
+
subject(:user_white_listed) { UserWithAddressAndPosts::UserWhiteListed::Son.new(attributes_for(:user_with_address_and_posts)) }
|
49
|
+
|
50
|
+
it 'it should return only the white listed' do
|
51
|
+
expect(user_white_listed.to_hash).to eq(attributes_for(:white_list))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when there are changes to attributes's black list" do
|
56
|
+
subject(:user_black_listed) { UserWithAddressAndPosts::UserBlackListed::Son.new(attributes_for(:user_with_address_and_posts)) }
|
57
|
+
|
58
|
+
it 'it should not return the black listed' do
|
59
|
+
expect(user_black_listed.to_hash).not_to include(attributes_for(:black_list))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when something other than a hash is introduced" do
|
65
|
+
it "should do nothing" do
|
66
|
+
[nil, '', [1, 2], 'test', 1, 2].each do |something_other_than_a_hash|
|
67
|
+
expect(User::Base.new(something_other_than_a_hash).internal_data).to eq({})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when one of the attribute's value, is an hash and is unknown to the schema" do
|
73
|
+
context "when the .unknown_hash_class is unused", current: true do
|
74
|
+
subject { User::Base.new(address: { street: 'something', postal_code: { code: '123' } }) }
|
75
|
+
|
76
|
+
it "a new instance of OpenStruct will be initialized with that hash" do
|
77
|
+
address = subject.address
|
78
|
+
|
79
|
+
expect(address).to be_instance_of(OpenStruct)
|
80
|
+
expect(address.street).to eq('something')
|
81
|
+
|
82
|
+
expect(address.postal_code).to be_instance_of(OpenStruct)
|
83
|
+
expect(address.postal_code.code).to eq('123')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "when the .unknown_hash_class is set to SmoothOperator::OpenStruct::Base" do
|
88
|
+
subject { User::UnknownHashClass::OpenStructBase.new(address: { street: 'something', postal_code: { code: '123' } }) }
|
89
|
+
|
90
|
+
it "a new instance of SmoothOperator::OpenStruct::Base will be initialized with that hash" do
|
91
|
+
address = subject.address
|
92
|
+
|
93
|
+
expect(address).to be_instance_of(SmoothOperator::OpenStruct::Base)
|
94
|
+
expect(address.street).to eq('something')
|
95
|
+
|
96
|
+
expect(address.postal_code).to be_instance_of(SmoothOperator::OpenStruct::Base)
|
97
|
+
expect(address.postal_code.code).to eq('123')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when the .unknown_hash_class is set to :none" do
|
102
|
+
subject { User::UnknownHashClass::None.new(creator: { first_name: 'admin', address: { street: 'something' } }) }
|
103
|
+
|
104
|
+
it "the hash will be copied as it is" do
|
105
|
+
creator = subject.creator
|
106
|
+
|
107
|
+
expect(creator).to be_instance_of(Hash)
|
108
|
+
expect(creator[:first_name]).to eq('admin')
|
109
|
+
|
110
|
+
expect(creator[:address]).to be_instance_of(Hash)
|
111
|
+
expect(creator[:address][:street]).to eq('something')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when there is no declared schema" do
|
117
|
+
subject { User::Base.new(attributes_for(:user)) }
|
118
|
+
let(:expected_internal_data) { SmoothOperator::Helpers.stringify_keys(attributes_for(:user)) }
|
119
|
+
|
120
|
+
it "it should populate 'internal_data' with unaltered duplicate data from the received hash" do
|
121
|
+
expect(subject.to_hash).to eq(attributes_for(:user))
|
122
|
+
end
|
123
|
+
|
124
|
+
it "it should populate 'known_attributes' with the keys of the received hash" do
|
125
|
+
expect(subject.known_attributes.to_a).to match_array(expected_internal_data.keys)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "when there is a known schema and the received hash has an attribute" do
|
130
|
+
subject { UserWithAddressAndPosts::Son }
|
131
|
+
|
132
|
+
context "that is declared (in schema) as an nil" do
|
133
|
+
|
134
|
+
it "when the attributes's value is '1', should return '1'" do
|
135
|
+
expect(subject.new(complex_field: '1').complex_field).to eq('1')
|
136
|
+
end
|
137
|
+
|
138
|
+
it "when the attributes's value is ['1', '2'], should return ['1', '2']" do
|
139
|
+
expect(subject.new(complex_field: ['1', '2']).complex_field).to eq(['1', '2'])
|
140
|
+
end
|
141
|
+
|
142
|
+
it "when the attributes's value is 1, should be converted to 1" do
|
143
|
+
expect(subject.new(complex_field: 1).complex_field).to eq(1)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "when the attributes's value is { first_name: ['1', '2'] }, should be converted to { first_name: ['1', '2'] }" do
|
147
|
+
expect(subject.new(complex_field: { first_name: ['1', '2'] }).complex_field).to eq({ first_name: ['1', '2'] })
|
148
|
+
end
|
149
|
+
|
150
|
+
it "when the attributes's value is -1, should be converted to -1" do
|
151
|
+
expect(subject.new(complex_field: -1).complex_field).to eq(-1)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "when the attributes's value is 0.35, should be converted to 0.35" do
|
155
|
+
expect(subject.new(complex_field: 0.35).complex_field).to eq(0.35)
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
context "that is declared (in schema) as an integer" do
|
161
|
+
|
162
|
+
it "when the attributes's value is '1', should be converted to 1" do
|
163
|
+
expect(subject.new(age: '1').age).to be(1)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "when the attributes's value is '-1', should be converted to -1" do
|
167
|
+
expect(subject.new(age: '-1').age).to be(-1)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "when the attributes's value is 's-10s', should be converted to -10" do
|
171
|
+
expect(subject.new(age: 's-10s').age).to be(-10)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "when the attributes's value is ' 10s', should be converted to 10" do
|
175
|
+
expect(subject.new(age: ' 10s').age).to be(10)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "when the attributes's value is 123, should be converted to 123" do
|
179
|
+
expect(subject.new(age: 123).age).to be(123)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "when the attributes's value is -5, should be converted to -5" do
|
183
|
+
expect(subject.new(age: -5).age).to be(-5)
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
context "that is declared (in schema) as an float" do
|
189
|
+
|
190
|
+
it "when the attributes's value is '1', should be converted to 1" do
|
191
|
+
expect(subject.new(price: '1').price).to eq(1.0)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "when the attributes's value is '-1', should be converted to -1" do
|
195
|
+
expect(subject.new(price: '-1').price).to eq(-1.0)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "when the attributes's value is 's-10s', should be converted to -10" do
|
199
|
+
expect(subject.new(price: 's-10s').price).to eq(-10.0)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "when the attributes's value is ' 10s', should be converted to 10" do
|
203
|
+
expect(subject.new(price: ' 10s').price).to eq(10.0)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "when the attributes's value is 123, should be converted to 123" do
|
207
|
+
expect(subject.new(price: 123).price).to eq(123.0)
|
208
|
+
end
|
209
|
+
|
210
|
+
it "when the attributes's value is -5, should be converted to -5" do
|
211
|
+
expect(subject.new(price: -5).price).to eq(-5.0)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "when the attributes's value is '12.3', should be converted to 12.3" do
|
215
|
+
expect(subject.new(price: '12.3').price).to eq(12.3)
|
216
|
+
end
|
217
|
+
|
218
|
+
it "when the attributes's value is 's12.3s', should be converted to 12.3" do
|
219
|
+
expect(subject.new(price: 's12.3s').price).to eq(12.3)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "when the attributes's value is 's12,3s', should be converted to 12.3" do
|
223
|
+
expect(subject.new(price: 's12,3s').price).to eq(12.3)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "when the attributes's value is 1.2, should be converted to 1.2" do
|
227
|
+
expect(subject.new(price: 1.2).price).to eq(1.2)
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
context "that is declared (in schema) as an boolean" do
|
233
|
+
|
234
|
+
it "when the attributes's value is true, should be converted to true" do
|
235
|
+
expect(subject.new(manager: true).manager).to be(true)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "when the attributes's value is false, should be converted to false" do
|
239
|
+
expect(subject.new(manager: false).manager).to be(false)
|
240
|
+
end
|
241
|
+
|
242
|
+
it "when the attributes's value is 'true', should be converted to true" do
|
243
|
+
expect(subject.new(manager: 'true').manager).to be(true)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "when the attributes's value is 'false', should be converted to false" do
|
247
|
+
expect(subject.new(manager: 'false').manager).to be(false)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "when the attributes's value is '1', should be converted to true" do
|
251
|
+
expect(subject.new(manager: '1').manager).to be(true)
|
252
|
+
end
|
253
|
+
|
254
|
+
it "when the attributes's value is '0', should be converted to false" do
|
255
|
+
expect(subject.new(manager: '0').manager).to be(false)
|
256
|
+
end
|
257
|
+
|
258
|
+
it "when the attributes's value is '', should be converted to nil" do
|
259
|
+
expect(subject.new(manager: '').manager).to be_nil
|
260
|
+
end
|
261
|
+
|
262
|
+
it "when the attributes's value is 'something', should be converted to nil" do
|
263
|
+
expect(subject.new(manager: 'something').manager).to be_nil
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
context "that is declared (in schema) as an existing class" do
|
269
|
+
|
270
|
+
it "if the attribute's value is an hash a new instance of that class will be initialized with that hash" do
|
271
|
+
address = subject.new(address: { street: 'something' }).address
|
272
|
+
|
273
|
+
expect(address).to be_instance_of(Address)
|
274
|
+
expect(address.street).to eq('something')
|
275
|
+
end
|
276
|
+
|
277
|
+
it "if the attribute's value is not an hash, then that value will be simply cloned" do
|
278
|
+
expect(subject.new(address: 'something').address).to eq('something')
|
279
|
+
end
|
280
|
+
|
281
|
+
it "if the attribute's value is an array, a new instance of that class will be initialized for each array entry" do
|
282
|
+
posts = subject.new(posts: [{ body: 'post1' }, { body: 'post2' }]).posts
|
283
|
+
|
284
|
+
expect(posts.length).to be(2)
|
285
|
+
|
286
|
+
expect(posts[0]).to be_instance_of(Post)
|
287
|
+
expect(posts[0].body).to eq('post1')
|
288
|
+
|
289
|
+
expect(posts[1]).to be_instance_of(Post)
|
290
|
+
expect(posts[1].body).to eq('post2')
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
context "that is declared (in schema) as a date" do
|
296
|
+
|
297
|
+
it "if the attribute's value is a valid date string" do
|
298
|
+
dob = subject.new(dob: '2-2-2222').dob
|
299
|
+
|
300
|
+
expect(dob).to be_instance_of(Date)
|
301
|
+
expect(dob.day).to be(2)
|
302
|
+
expect(dob.month).to be(2)
|
303
|
+
expect(dob.year).to be(2222)
|
304
|
+
end
|
305
|
+
|
306
|
+
it "if the attribute's value is a valid date" do
|
307
|
+
date_now = DateTime.now
|
308
|
+
dob = subject.new(dob: date_now).dob
|
309
|
+
|
310
|
+
expect(dob).to be_instance_of(DateTime)
|
311
|
+
expect(dob).to eq(date_now)
|
312
|
+
end
|
313
|
+
|
314
|
+
it "if the attribute's value is an invalid date string, the returning value should be nil" do
|
315
|
+
expect(subject.new(dob: '2s-2-2222').dob).to be_nil
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
context "that is declared (in schema) as a datetime" do
|
321
|
+
|
322
|
+
it "if the attribute's value is a valid datetime string" do
|
323
|
+
date = subject.new(date: '2-2-2222 12:30').date
|
324
|
+
|
325
|
+
expect(date).to be_instance_of(DateTime)
|
326
|
+
expect(date.day).to be(2)
|
327
|
+
expect(date.month).to be(2)
|
328
|
+
expect(date.year).to be(2222)
|
329
|
+
expect(date.hour).to be(12)
|
330
|
+
expect(date.min).to be(30)
|
331
|
+
end
|
332
|
+
|
333
|
+
it "if the attribute's value is a valid datetime" do
|
334
|
+
date_now = DateTime.now
|
335
|
+
date = subject.new(date: date_now).date
|
336
|
+
|
337
|
+
expect(date).to be_instance_of(DateTime)
|
338
|
+
expect(date).to eq(date_now)
|
339
|
+
end
|
340
|
+
|
341
|
+
it "if the attribute's value is an invalid datetime string, the returning value should be nil" do
|
342
|
+
expect(subject.new(date: '2s-2-2222').date).to be_nil
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SmoothOperator::Attributes::Dirty do
|
4
|
+
|
5
|
+
subject { UserWithAddressAndPosts::DirtyAttributes.new(attributes_for(:user_with_address_and_posts)) }
|
6
|
+
|
7
|
+
context "when no changes are made to an attribute" do
|
8
|
+
it "checking if that attribute is changed, should return false" do
|
9
|
+
expect(subject.first_name_changed?).to be false
|
10
|
+
end
|
11
|
+
|
12
|
+
it "checking that attribute past value, should its original value" do
|
13
|
+
expect(subject.first_name_was).to eq('John')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when there are changes made to an attribute" do
|
18
|
+
before { subject.first_name = 'nhoJ' }
|
19
|
+
|
20
|
+
it "checking if that attribute is changed, should return true" do
|
21
|
+
expect(subject.first_name_changed?).to be true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "checking that attribute past value, should its original value" do
|
25
|
+
expect(subject.first_name_was).to eq('John')
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when there are changes to the changes made to an attribute" do
|
29
|
+
before { subject.first_name = 'no_name' }
|
30
|
+
|
31
|
+
it "checking if that attribute is changed, should return true" do
|
32
|
+
expect(subject.first_name_changed?).to be true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "checking that attribute past value, should its first original value" do
|
36
|
+
expect(subject.first_name_was).to eq('John')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when there are changes made to a nested object" do
|
42
|
+
before { subject.address.street = 'my street' }
|
43
|
+
|
44
|
+
it "checking if the nested object as changed, should return false" do
|
45
|
+
expect(subject.address_changed?).to be false
|
46
|
+
end
|
47
|
+
|
48
|
+
it "checking if the nested object's attribute as changed, should return true" do
|
49
|
+
expect(subject.address.street_changed?).to be true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|