hash_cast 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 +7 -0
- data/.github/workflows/rspec.yml +34 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +35 -0
- data/LICENSE.txt +22 -0
- data/README.md +93 -0
- data/Rakefile +1 -0
- data/hcast.gemspec +23 -0
- data/lib/hcast/attributes_caster.rb +102 -0
- data/lib/hcast/attributes_parser.rb +63 -0
- data/lib/hcast/caster.rb +142 -0
- data/lib/hcast/casters/array_caster.rb +32 -0
- data/lib/hcast/casters/boolean_caster.rb +15 -0
- data/lib/hcast/casters/date_caster.rb +19 -0
- data/lib/hcast/casters/datetime_caster.rb +19 -0
- data/lib/hcast/casters/float_caster.rb +17 -0
- data/lib/hcast/casters/hash_caster.rb +11 -0
- data/lib/hcast/casters/integer_caster.rb +17 -0
- data/lib/hcast/casters/string_caster.rb +13 -0
- data/lib/hcast/casters/symbol_caster.rb +18 -0
- data/lib/hcast/casters/time_caster.rb +19 -0
- data/lib/hcast/casters.rb +13 -0
- data/lib/hcast/concern.rb +136 -0
- data/lib/hcast/config.rb +11 -0
- data/lib/hcast/errors.rb +67 -0
- data/lib/hcast/metadata/attribute.rb +30 -0
- data/lib/hcast/version.rb +3 -0
- data/lib/hcast.rb +46 -0
- data/spec/hcast/caster_spec.rb +384 -0
- data/spec/hcast/hcast_spec.rb +37 -0
- data/spec/spec_helper.rb +6 -0
- metadata +108 -0
@@ -0,0 +1,384 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HCast::Caster do
|
4
|
+
describe "#cast" do
|
5
|
+
|
6
|
+
class ContactCaster
|
7
|
+
include HCast::Caster
|
8
|
+
|
9
|
+
attributes do
|
10
|
+
hash :contact do
|
11
|
+
string :name
|
12
|
+
integer :age, optional: true
|
13
|
+
float :weight
|
14
|
+
date :birthday
|
15
|
+
datetime :last_logged_in
|
16
|
+
time :last_visited_at
|
17
|
+
hash :company do
|
18
|
+
string :name
|
19
|
+
end
|
20
|
+
array :emails, each: :string
|
21
|
+
array :social_accounts, each: :hash do
|
22
|
+
string :name
|
23
|
+
symbol :type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should cast hash attributes" do
|
30
|
+
input_hash = {
|
31
|
+
contact: {
|
32
|
+
name: "John Smith",
|
33
|
+
age: "22",
|
34
|
+
weight: "65.5",
|
35
|
+
birthday: "2014-02-02",
|
36
|
+
last_logged_in: "2014-02-02 10:10:00",
|
37
|
+
last_visited_at: "2014-02-02 10:10:00",
|
38
|
+
company: {
|
39
|
+
name: "MyCo",
|
40
|
+
},
|
41
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
42
|
+
social_accounts: [
|
43
|
+
{
|
44
|
+
name: "john_smith",
|
45
|
+
type: 'twitter',
|
46
|
+
},
|
47
|
+
{
|
48
|
+
name: "John",
|
49
|
+
type: :facebook,
|
50
|
+
},
|
51
|
+
]
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
casted_hash = ContactCaster.cast(input_hash)
|
56
|
+
|
57
|
+
casted_hash.should == {
|
58
|
+
contact: {
|
59
|
+
name: "John Smith",
|
60
|
+
age: 22,
|
61
|
+
weight: 65.5,
|
62
|
+
birthday: Date.parse("2014-02-02"),
|
63
|
+
last_logged_in: DateTime.parse("2014-02-02 10:10:00"),
|
64
|
+
last_visited_at: Time.parse("2014-02-02 10:10:00"),
|
65
|
+
company: {
|
66
|
+
name: "MyCo",
|
67
|
+
},
|
68
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
69
|
+
social_accounts: [
|
70
|
+
{
|
71
|
+
name: "john_smith",
|
72
|
+
type: :twitter,
|
73
|
+
},
|
74
|
+
{
|
75
|
+
name: "John",
|
76
|
+
type: :facebook,
|
77
|
+
},
|
78
|
+
]
|
79
|
+
}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "Custom casters" do
|
84
|
+
class SettingsCaster
|
85
|
+
include HCast::Caster
|
86
|
+
|
87
|
+
attributes do
|
88
|
+
string :account
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class EmailCaster
|
93
|
+
include HCast::Caster
|
94
|
+
|
95
|
+
attributes do
|
96
|
+
string :address
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class CompanyCaster
|
101
|
+
include HCast::Caster
|
102
|
+
|
103
|
+
attributes do
|
104
|
+
string :name
|
105
|
+
hash :settings, caster: SettingsCaster
|
106
|
+
array :emails, caster: EmailCaster
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should allow specify caster for nested hash attribute" do
|
111
|
+
casted_hash = CompanyCaster.cast(
|
112
|
+
name: 'Might & Magic',
|
113
|
+
settings: {
|
114
|
+
account: :'migthy_lord'
|
115
|
+
},
|
116
|
+
emails: [
|
117
|
+
{ address: :'test1@example.com' },
|
118
|
+
{ address: :'test2@example.com' },
|
119
|
+
]
|
120
|
+
)
|
121
|
+
|
122
|
+
casted_hash.should == {
|
123
|
+
name: "Might & Magic",
|
124
|
+
settings: { account: "migthy_lord" },
|
125
|
+
emails: [
|
126
|
+
{ address: "test1@example.com" },
|
127
|
+
{ address: "test2@example.com" }
|
128
|
+
]
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should raise error if some attribute can't be casted" do
|
134
|
+
input_hash = {
|
135
|
+
contact: {
|
136
|
+
name: {},
|
137
|
+
age: 22,
|
138
|
+
weight: 65.5,
|
139
|
+
birthday: Date.today,
|
140
|
+
last_logged_in: DateTime.now,
|
141
|
+
last_visited_at: Time.now,
|
142
|
+
company: {
|
143
|
+
name: "MyCo",
|
144
|
+
},
|
145
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
146
|
+
social_accounts: [
|
147
|
+
{
|
148
|
+
name: "john_smith",
|
149
|
+
type: :twitter,
|
150
|
+
},
|
151
|
+
{
|
152
|
+
name: "John",
|
153
|
+
type: :facebook,
|
154
|
+
}
|
155
|
+
]
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
expect do
|
160
|
+
ContactCaster.cast(input_hash)
|
161
|
+
end.to raise_error(HCast::Errors::CastingError, "contact[name] should be a string")
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should raise error if some attribute wasn't given" do
|
165
|
+
input_hash = {
|
166
|
+
contact: {
|
167
|
+
age: 22,
|
168
|
+
weight: 65.5,
|
169
|
+
birthday: Date.today,
|
170
|
+
last_logged_in: DateTime.now,
|
171
|
+
last_visited_at: Time.now,
|
172
|
+
company: {
|
173
|
+
name: "MyCo",
|
174
|
+
},
|
175
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
176
|
+
social_accounts: [
|
177
|
+
{
|
178
|
+
name: "john_smith",
|
179
|
+
type: :twitter,
|
180
|
+
},
|
181
|
+
{
|
182
|
+
name: "John",
|
183
|
+
type: :facebook,
|
184
|
+
}
|
185
|
+
]
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
expect do
|
190
|
+
ContactCaster.cast(input_hash)
|
191
|
+
end.to raise_error(HCast::Errors::MissingAttributeError, "contact[name] should be given")
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should not raise error if attribute is optional" do
|
195
|
+
input_hash = {
|
196
|
+
contact: {
|
197
|
+
name: "Jim",
|
198
|
+
weight: 65.5,
|
199
|
+
birthday: Date.today,
|
200
|
+
last_logged_in: DateTime.now,
|
201
|
+
last_visited_at: Time.now,
|
202
|
+
company: {
|
203
|
+
name: "MyCo",
|
204
|
+
},
|
205
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
206
|
+
social_accounts: [
|
207
|
+
{
|
208
|
+
name: "john_smith",
|
209
|
+
type: :twitter,
|
210
|
+
},
|
211
|
+
{
|
212
|
+
name: "John",
|
213
|
+
type: :facebook,
|
214
|
+
},
|
215
|
+
]
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
expect do
|
220
|
+
ContactCaster.cast(input_hash)
|
221
|
+
end.to_not raise_error
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should raise error if unexpected attribute was given" do
|
225
|
+
input_hash = {
|
226
|
+
contact: {
|
227
|
+
wrong_attribute: 'foo',
|
228
|
+
name: "Jim",
|
229
|
+
weight: 65.5,
|
230
|
+
birthday: Date.today,
|
231
|
+
last_logged_in: DateTime.now,
|
232
|
+
last_visited_at: Time.now,
|
233
|
+
company: {
|
234
|
+
name: "MyCo",
|
235
|
+
},
|
236
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
237
|
+
social_accounts: [
|
238
|
+
{
|
239
|
+
name: "john_smith",
|
240
|
+
type: :twitter,
|
241
|
+
},
|
242
|
+
{
|
243
|
+
name: "John",
|
244
|
+
type: :facebook,
|
245
|
+
},
|
246
|
+
]
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
expect do
|
251
|
+
ContactCaster.cast(input_hash)
|
252
|
+
end.to raise_error(HCast::Errors::UnexpectedAttributeError, "contact[wrong_attribute] is not valid attribute name")
|
253
|
+
end
|
254
|
+
|
255
|
+
it "shouldn't unexpected attributes error if skip_unexpected_attributes flag is set to true" do
|
256
|
+
input_hash = {
|
257
|
+
contact: {
|
258
|
+
wrong_attribute: 'foo',
|
259
|
+
name: "Jim",
|
260
|
+
weight: 65.5,
|
261
|
+
birthday: Date.today,
|
262
|
+
last_logged_in: DateTime.now,
|
263
|
+
last_visited_at: Time.now,
|
264
|
+
company: {
|
265
|
+
name: "MyCo",
|
266
|
+
},
|
267
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
268
|
+
social_accounts: [
|
269
|
+
{
|
270
|
+
name: "john_smith",
|
271
|
+
type: :twitter,
|
272
|
+
},
|
273
|
+
{
|
274
|
+
name: "John",
|
275
|
+
type: :facebook,
|
276
|
+
},
|
277
|
+
]
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
expect do
|
282
|
+
ContactCaster.cast(input_hash, skip_unexpected_attributes: true)
|
283
|
+
end.not_to raise_error(HCast::Errors::UnexpectedAttributeError)
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should convert accept hash with string keys and cast them to symbol keys" do
|
288
|
+
input_hash = {
|
289
|
+
'contact' => {
|
290
|
+
'name' => "John Smith",
|
291
|
+
'age' => "22",
|
292
|
+
'weight' => "65.5",
|
293
|
+
'birthday' => "2014-02-02",
|
294
|
+
'last_logged_in' => "2014-02-02 10:10:00",
|
295
|
+
'last_visited_at' => "2014-02-02 10:10:00",
|
296
|
+
'company' => {
|
297
|
+
'name' => "MyCo",
|
298
|
+
},
|
299
|
+
'emails' => [ "test@example.com", "test2@example.com" ],
|
300
|
+
'social_accounts' => [
|
301
|
+
{
|
302
|
+
'name' => "john_smith",
|
303
|
+
'type' => 'twitter',
|
304
|
+
},
|
305
|
+
{
|
306
|
+
'name' => "John",
|
307
|
+
'type' => :facebook,
|
308
|
+
},
|
309
|
+
]
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
casted_hash = ContactCaster.cast(input_hash, input_keys: :string, output_keys: :symbol)
|
314
|
+
|
315
|
+
casted_hash.should == {
|
316
|
+
contact: {
|
317
|
+
name: "John Smith",
|
318
|
+
age: 22,
|
319
|
+
weight: 65.5,
|
320
|
+
birthday: Date.parse("2014-02-02"),
|
321
|
+
last_logged_in: DateTime.parse("2014-02-02 10:10:00"),
|
322
|
+
last_visited_at: Time.parse("2014-02-02 10:10:00"),
|
323
|
+
company: {
|
324
|
+
name: "MyCo",
|
325
|
+
},
|
326
|
+
emails: [ "test@example.com", "test2@example.com" ],
|
327
|
+
social_accounts: [
|
328
|
+
{
|
329
|
+
name: "john_smith",
|
330
|
+
type: :twitter,
|
331
|
+
},
|
332
|
+
{
|
333
|
+
name: "John",
|
334
|
+
type: :facebook,
|
335
|
+
},
|
336
|
+
]
|
337
|
+
}
|
338
|
+
}
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context "checking invalid parameters" do
|
343
|
+
it "should raise CaterNotFound exception if caster name is invalid" do
|
344
|
+
expect do
|
345
|
+
class WrongCaster
|
346
|
+
include HCast::Caster
|
347
|
+
|
348
|
+
attributes do
|
349
|
+
integr :name
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end.to raise_error(HCast::Errors::CasterNotFoundError)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
context "allow nil values" do
|
357
|
+
before(:all) do
|
358
|
+
class HomeCaster
|
359
|
+
include HCast::Caster
|
360
|
+
|
361
|
+
attributes do
|
362
|
+
string :city
|
363
|
+
integer :zip, allow_nil: true
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should allow nil values if allow_nil is set to true" do
|
369
|
+
HomeCaster.cast(
|
370
|
+
city: 'Kazan',
|
371
|
+
zip: nil
|
372
|
+
)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "should allow nil values unless allow_nil is set to true" do
|
376
|
+
expect do
|
377
|
+
HomeCaster.cast(
|
378
|
+
city: nil,
|
379
|
+
zip: nil
|
380
|
+
)
|
381
|
+
end.to raise_error(HCast::Errors::CastingError, "city should be a string")
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HCast do
|
4
|
+
|
5
|
+
describe ".create" do
|
6
|
+
it "should cast hash attributes" do
|
7
|
+
pending "NOT YET IMPLEMENTED"
|
8
|
+
input_hash = {
|
9
|
+
contact: {
|
10
|
+
name: "John Smith",
|
11
|
+
age: "22",
|
12
|
+
company: {
|
13
|
+
name: "MyCo",
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
caster = HCast.create do
|
19
|
+
hash :contact do
|
20
|
+
string :name
|
21
|
+
integer :age
|
22
|
+
hash :company do
|
23
|
+
string :name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def registered?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
casted_hash = caster.cast(input_hash)
|
33
|
+
casted_hash.object_id.should_not == hash.object_id
|
34
|
+
caster_hash.should == hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hash_cast
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Albert Gazizov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Declarative Hash Caster
|
42
|
+
email:
|
43
|
+
- deeper4k@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".github/workflows/rspec.yml"
|
49
|
+
- ".gitignore"
|
50
|
+
- ".rspec"
|
51
|
+
- ".ruby-gemset"
|
52
|
+
- ".ruby-version"
|
53
|
+
- Gemfile
|
54
|
+
- Gemfile.lock
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- hcast.gemspec
|
59
|
+
- lib/hcast.rb
|
60
|
+
- lib/hcast/attributes_caster.rb
|
61
|
+
- lib/hcast/attributes_parser.rb
|
62
|
+
- lib/hcast/caster.rb
|
63
|
+
- lib/hcast/casters.rb
|
64
|
+
- lib/hcast/casters/array_caster.rb
|
65
|
+
- lib/hcast/casters/boolean_caster.rb
|
66
|
+
- lib/hcast/casters/date_caster.rb
|
67
|
+
- lib/hcast/casters/datetime_caster.rb
|
68
|
+
- lib/hcast/casters/float_caster.rb
|
69
|
+
- lib/hcast/casters/hash_caster.rb
|
70
|
+
- lib/hcast/casters/integer_caster.rb
|
71
|
+
- lib/hcast/casters/string_caster.rb
|
72
|
+
- lib/hcast/casters/symbol_caster.rb
|
73
|
+
- lib/hcast/casters/time_caster.rb
|
74
|
+
- lib/hcast/concern.rb
|
75
|
+
- lib/hcast/config.rb
|
76
|
+
- lib/hcast/errors.rb
|
77
|
+
- lib/hcast/metadata/attribute.rb
|
78
|
+
- lib/hcast/version.rb
|
79
|
+
- spec/hcast/caster_spec.rb
|
80
|
+
- spec/hcast/hcast_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
homepage: http://github.com/droidlabs/hash_cast
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubygems_version: 3.5.11
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Declarative Hash Caster
|
105
|
+
test_files:
|
106
|
+
- spec/hcast/caster_spec.rb
|
107
|
+
- spec/hcast/hcast_spec.rb
|
108
|
+
- spec/spec_helper.rb
|