hash_cast 0.4.0 → 0.5.1
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 +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +1 -1
- data/README.md +5 -5
- data/{hcast.gemspec → hash_cast.gemspec} +2 -2
- data/lib/{hcast → hash_cast}/attributes_caster.rb +6 -6
- data/lib/{hcast → hash_cast}/attributes_parser.rb +9 -9
- data/lib/{hcast → hash_cast}/caster.rb +12 -12
- data/lib/{hcast → hash_cast}/casters/array_caster.rb +4 -4
- data/lib/{hcast → hash_cast}/casters/boolean_caster.rb +2 -2
- data/lib/{hcast → hash_cast}/casters/date_caster.rb +3 -3
- data/lib/{hcast → hash_cast}/casters/datetime_caster.rb +3 -3
- data/lib/{hcast → hash_cast}/casters/float_caster.rb +3 -3
- data/lib/{hcast → hash_cast}/casters/hash_caster.rb +2 -2
- data/lib/{hcast → hash_cast}/casters/integer_caster.rb +3 -3
- data/lib/hash_cast/casters/string_caster.rb +26 -0
- data/lib/{hcast → hash_cast}/casters/symbol_caster.rb +3 -3
- data/lib/{hcast → hash_cast}/casters/time_caster.rb +3 -3
- data/lib/hash_cast/casters.rb +13 -0
- data/lib/{hcast → hash_cast}/concern.rb +1 -1
- data/lib/hash_cast/config.rb +17 -0
- data/lib/{hcast → hash_cast}/errors.rb +8 -8
- data/lib/{hcast → hash_cast}/metadata/attribute.rb +1 -1
- data/lib/hash_cast/version.rb +3 -0
- data/lib/hash_cast.rb +46 -0
- data/spec/{hcast → hash_cast}/caster_spec.rb +42 -17
- data/spec/{hcast/hcast_spec.rb → hash_cast/hash_cast_spec.rb} +2 -2
- data/spec/spec_helper.rb +1 -1
- metadata +28 -27
- data/lib/hcast/casters/string_caster.rb +0 -13
- data/lib/hcast/casters.rb +0 -13
- data/lib/hcast/config.rb +0 -11
- data/lib/hcast/version.rb +0 -3
- data/lib/hcast.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68e050b609ffe18b09ada29f3606534113be56827b161bae6e917cbeadc82a57
|
4
|
+
data.tar.gz: 76b1ba697a03d6edcccb6f5196d3411d8af423ff5e0e0b1661b81db3e02846e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7fc1162f788fd180c0cd1a080bb2dbbcaaeb7b28fa1d59b3d490a0bd3f744a3457998d65fc1ce6d2e9819ce898416d6832c658d8bd5e3d47486980d6a4a1db3
|
7
|
+
data.tar.gz: 1d9d02707117f5619902867966c4e0a1f542e0e9aedd2b183557aaf25c6fc85704d488db2c52c22534a377779a68b1bc9d09b31420ad77af54576d701358f9fe
|
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
#
|
2
|
-
[](https://github.com/droidlabs/hash_cast/actions?query=workflow%3ARspec)
|
3
3
|
|
4
|
-
|
4
|
+
HashCast is a library for casting hash attributes
|
5
5
|
|
6
6
|
### Usage
|
7
7
|
|
8
8
|
Create caster class and declare hash attributes inside:
|
9
9
|
```ruby
|
10
10
|
class ContactCaster
|
11
|
-
include
|
11
|
+
include HashCast::Caster
|
12
12
|
|
13
13
|
attributes do
|
14
14
|
hash :contact do
|
@@ -86,7 +86,7 @@ The caster will cast your hash attributes to:
|
|
86
86
|
}
|
87
87
|
```
|
88
88
|
|
89
|
-
if some of the attributes can't be casted the
|
89
|
+
if some of the attributes can't be casted the HashCast::Errors::CastingError is raised
|
90
90
|
|
91
91
|
|
92
92
|
## Author
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require '
|
4
|
+
require 'hash_cast/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "hash_cast"
|
8
|
-
spec.version =
|
8
|
+
spec.version = HashCast::VERSION
|
9
9
|
spec.authors = ["Albert Gazizov"]
|
10
10
|
spec.email = ["deeper4k@gmail.com"]
|
11
11
|
spec.description = %q{Declarative Hash Caster}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::AttributesCaster
|
2
2
|
attr_reader :attributes, :options
|
3
3
|
|
4
4
|
def initialize(attributes, options)
|
@@ -15,15 +15,15 @@ class HCast::AttributesCaster
|
|
15
15
|
begin
|
16
16
|
casted_value = cast_attribute(attribute, input_hash)
|
17
17
|
casted_hash[attribute.name] = casted_value
|
18
|
-
rescue
|
18
|
+
rescue HashCast::Errors::AttributeError => e
|
19
19
|
handle_attribute_error(e, attribute)
|
20
20
|
end
|
21
21
|
else
|
22
|
-
raise
|
22
|
+
raise HashCast::Errors::MissingAttributeError.new("should be given", attribute.name)if attribute.required?
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
if !options[:skip_unexpected_attributes]
|
26
|
+
if options.has_key?(:skip_unexpected_attributes) && !options[:skip_unexpected_attributes]
|
27
27
|
check_unexpected_attributes_not_given!(hash_keys, casted_hash.keys)
|
28
28
|
end
|
29
29
|
|
@@ -59,7 +59,7 @@ class HCast::AttributesCaster
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def cast_children_with_caster(value, attribute, caster)
|
62
|
-
if attribute.caster ==
|
62
|
+
if attribute.caster == HashCast::Casters::ArrayCaster
|
63
63
|
value.map do |val|
|
64
64
|
caster.cast(val)
|
65
65
|
end
|
@@ -95,7 +95,7 @@ class HCast::AttributesCaster
|
|
95
95
|
def check_unexpected_attributes_not_given!(input_hash_keys, casted_hash_keys)
|
96
96
|
unexpected_keys = input_hash_keys - casted_hash_keys
|
97
97
|
unless unexpected_keys.empty?
|
98
|
-
raise
|
98
|
+
raise HashCast::Errors::UnexpectedAttributeError.new("is not valid attribute name", unexpected_keys.first)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# Parses caster rules
|
2
|
-
# and returns list of
|
2
|
+
# and returns list of HashCast::Metadata::Attribute instances
|
3
3
|
# which contains casting rules
|
4
|
-
class
|
4
|
+
class HashCast::AttributesParser
|
5
5
|
|
6
6
|
# Performs casting
|
7
7
|
# @param block [Proc] block with casting rules
|
8
|
-
# @return Array(
|
8
|
+
# @return Array(HashCast::Metadata::Attribute) list of casting rules
|
9
9
|
def self.parse(&block)
|
10
10
|
dsl = DSL.new
|
11
11
|
dsl.instance_exec(&block)
|
@@ -27,15 +27,15 @@ class HCast::AttributesParser
|
|
27
27
|
def method_missing(caster_name, *args, &block)
|
28
28
|
attr_name = args[0]
|
29
29
|
options = args[1] || {}
|
30
|
-
caster =
|
30
|
+
caster = HashCast.casters[caster_name]
|
31
31
|
|
32
32
|
check_caster_exists!(caster, caster_name)
|
33
33
|
check_attr_name_valid!(attr_name)
|
34
34
|
check_options_is_hash!(options)
|
35
35
|
|
36
|
-
attribute =
|
36
|
+
attribute = HashCast::Metadata::Attribute.new(attr_name, caster, options)
|
37
37
|
if block_given?
|
38
|
-
attribute.children =
|
38
|
+
attribute.children = HashCast::AttributesParser.parse(&block)
|
39
39
|
end
|
40
40
|
attributes << attribute
|
41
41
|
end
|
@@ -44,19 +44,19 @@ class HCast::AttributesParser
|
|
44
44
|
|
45
45
|
def check_caster_exists!(caster, caster_name)
|
46
46
|
if !caster
|
47
|
-
raise
|
47
|
+
raise HashCast::Errors::CasterNotFoundError, "caster with name '#{caster_name}' is not found"
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
def check_attr_name_valid!(attr_name)
|
52
52
|
if !attr_name.is_a?(Symbol) && !attr_name.is_a?(String)
|
53
|
-
raise
|
53
|
+
raise HashCast::Errors::ArgumentError, "attribute name should be a symbol or string"
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
def check_options_is_hash!(options)
|
58
58
|
if !options.is_a?(Hash)
|
59
|
-
raise
|
59
|
+
raise HashCast::Errors::ArgumentError, "attribute options should be a Hash"
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# Example caster:
|
4
4
|
# class ContactCaster
|
5
|
-
# include
|
5
|
+
# include HashCast::Caster
|
6
6
|
#
|
7
7
|
# attributes do
|
8
8
|
# hash :contact do
|
@@ -76,8 +76,8 @@
|
|
76
76
|
# ]
|
77
77
|
# }
|
78
78
|
# }
|
79
|
-
module
|
80
|
-
extend
|
79
|
+
module HashCast::Caster
|
80
|
+
extend HashCast::Concern
|
81
81
|
|
82
82
|
module ClassMethods
|
83
83
|
|
@@ -91,7 +91,7 @@ module HCast::Caster
|
|
91
91
|
def attributes(&block)
|
92
92
|
raise ArgumentError, "You should provide block" unless block_given?
|
93
93
|
|
94
|
-
attributes =
|
94
|
+
attributes = HashCast::AttributesParser.parse(&block)
|
95
95
|
self.class_variable_set(:@@attributes, attributes)
|
96
96
|
end
|
97
97
|
|
@@ -104,7 +104,7 @@ module HCast::Caster
|
|
104
104
|
check_options!(options)
|
105
105
|
set_default_options(options)
|
106
106
|
|
107
|
-
attributes_caster =
|
107
|
+
attributes_caster = HashCast::AttributesCaster.new(class_variable_get(:@@attributes), options)
|
108
108
|
attributes_caster.cast(hash)
|
109
109
|
end
|
110
110
|
|
@@ -112,31 +112,31 @@ module HCast::Caster
|
|
112
112
|
|
113
113
|
def check_attributes_defined!
|
114
114
|
unless class_variable_defined?(:@@attributes)
|
115
|
-
raise
|
115
|
+
raise HashCast::Errors::ArgumentError, "Attributes block should be defined"
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
119
|
def check_options!(options)
|
120
120
|
unless options.is_a?(Hash)
|
121
|
-
raise
|
121
|
+
raise HashCast::Errors::ArgumentError, "Options should be a hash"
|
122
122
|
end
|
123
123
|
if options[:input_keys] && ![:string, :symbol].include?(options[:input_keys])
|
124
|
-
raise
|
124
|
+
raise HashCast::Errors::ArgumentError, "input_keys should be :string or :symbol"
|
125
125
|
end
|
126
126
|
if options[:output_keys] && ![:string, :symbol].include?(options[:output_keys])
|
127
|
-
raise
|
127
|
+
raise HashCast::Errors::ArgumentError, "output_keys should be :string or :symbol"
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
131
|
def check_hash_given!(hash)
|
132
132
|
unless hash.is_a?(Hash)
|
133
|
-
raise
|
133
|
+
raise HashCast::Errors::ArgumentError, "Hash should be given"
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
137
|
def set_default_options(options)
|
138
|
-
options[:input_keys] ||=
|
139
|
-
options[:output_keys] ||=
|
138
|
+
options[:input_keys] ||= HashCast.config.input_keys
|
139
|
+
options[:output_keys] ||= HashCast.config.output_keys
|
140
140
|
end
|
141
141
|
end
|
142
142
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::ArrayCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if value.is_a?(Array)
|
@@ -8,7 +8,7 @@ class HCast::Casters::ArrayCaster
|
|
8
8
|
value
|
9
9
|
end
|
10
10
|
else
|
11
|
-
raise
|
11
|
+
raise HashCast::Errors::CastingError, "should be an array"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -16,7 +16,7 @@ class HCast::Casters::ArrayCaster
|
|
16
16
|
|
17
17
|
def self.cast_array_items(array, attr_name, options)
|
18
18
|
caster_name = options[:each]
|
19
|
-
caster =
|
19
|
+
caster = HashCast.casters[caster_name]
|
20
20
|
check_caster_exists!(caster, caster_name)
|
21
21
|
array.map do |item|
|
22
22
|
caster.cast(item, "#{attr_name} item", options)
|
@@ -25,7 +25,7 @@ class HCast::Casters::ArrayCaster
|
|
25
25
|
|
26
26
|
def self.check_caster_exists!(caster, caster_name)
|
27
27
|
unless caster
|
28
|
-
raise
|
28
|
+
raise HashCast::Errors::CasterNotFoundError, "caster with name #{caster_name} is not found"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::BooleanCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if [TrueClass, FalseClass].include?(value.class)
|
@@ -8,7 +8,7 @@ class HCast::Casters::BooleanCaster
|
|
8
8
|
elsif ['0', 'false', 'off', 0].include?(value)
|
9
9
|
false
|
10
10
|
else
|
11
|
-
raise
|
11
|
+
raise HashCast::Errors::CastingError, "should be a boolean"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
|
3
|
-
class
|
3
|
+
class HashCast::Casters::DateCaster
|
4
4
|
|
5
5
|
def self.cast(value, attr_name, options = {})
|
6
6
|
if value.is_a?(Date)
|
@@ -9,10 +9,10 @@ class HCast::Casters::DateCaster
|
|
9
9
|
begin
|
10
10
|
Date.parse(value)
|
11
11
|
rescue ArgumentError => e
|
12
|
-
raise
|
12
|
+
raise HashCast::Errors::CastingError, "is invalid date"
|
13
13
|
end
|
14
14
|
else
|
15
|
-
raise
|
15
|
+
raise HashCast::Errors::CastingError, "should be a date"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::DateTimeCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if value.is_a?(DateTime)
|
@@ -9,10 +9,10 @@ class HCast::Casters::DateTimeCaster
|
|
9
9
|
begin
|
10
10
|
DateTime.parse(value)
|
11
11
|
rescue ArgumentError => e
|
12
|
-
raise
|
12
|
+
raise HashCast::Errors::CastingError, "is invalid datetime"
|
13
13
|
end
|
14
14
|
else
|
15
|
-
raise
|
15
|
+
raise HashCast::Errors::CastingError, "should be a datetime"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::FloatCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if value.is_a?(Float)
|
@@ -7,10 +7,10 @@ class HCast::Casters::FloatCaster
|
|
7
7
|
begin
|
8
8
|
Float(value)
|
9
9
|
rescue ArgumentError => e
|
10
|
-
raise
|
10
|
+
raise HashCast::Errors::CastingError, "is invalid float"
|
11
11
|
end
|
12
12
|
else
|
13
|
-
raise
|
13
|
+
raise HashCast::Errors::CastingError, "should be a float"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::HashCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if value.is_a?(Hash)
|
5
5
|
value
|
6
6
|
else
|
7
|
-
raise
|
7
|
+
raise HashCast::Errors::CastingError, "should be a hash"
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::IntegerCaster
|
2
2
|
|
3
3
|
def self.cast(value, attr_name, options = {})
|
4
4
|
if value.is_a?(Integer)
|
@@ -7,10 +7,10 @@ class HCast::Casters::IntegerCaster
|
|
7
7
|
begin
|
8
8
|
Integer(value)
|
9
9
|
rescue ArgumentError => e
|
10
|
-
raise
|
10
|
+
raise HashCast::Errors::CastingError, "is invalid integer"
|
11
11
|
end
|
12
12
|
else
|
13
|
-
raise
|
13
|
+
raise HashCast::Errors::CastingError, "should be a integer"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class HashCast::Casters::StringCaster
|
2
|
+
NULL_BYTE_CHARACTER = "\u0000".freeze
|
3
|
+
|
4
|
+
def self.cast(value, attr_name, options = {})
|
5
|
+
casted_value = cast_string(value, attr_name, options)
|
6
|
+
|
7
|
+
if HashCast.config.validate_string_null_byte && casted_value.match?(NULL_BYTE_CHARACTER)
|
8
|
+
raise HashCast::Errors::CastingError, 'contains invalid characters'
|
9
|
+
end
|
10
|
+
|
11
|
+
casted_value
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def self.cast_string(value, attr_name, options = {})
|
17
|
+
if value.is_a?(String)
|
18
|
+
value
|
19
|
+
elsif value.is_a?(Symbol)
|
20
|
+
value.to_s
|
21
|
+
else
|
22
|
+
raise HashCast::Errors::CastingError, "should be a string"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class HashCast::Casters::SymbolCaster
|
2
2
|
MAX_SYMBOL_LENGTH = 1000
|
3
3
|
|
4
4
|
def self.cast(value, attr_name, options = {})
|
@@ -6,12 +6,12 @@ class HCast::Casters::SymbolCaster
|
|
6
6
|
value
|
7
7
|
elsif value.is_a?(String)
|
8
8
|
if value.length > MAX_SYMBOL_LENGTH
|
9
|
-
raise
|
9
|
+
raise HashCast::Errors::CastingError, "is too long to be a symbol"
|
10
10
|
else
|
11
11
|
value.to_sym
|
12
12
|
end
|
13
13
|
else
|
14
|
-
raise
|
14
|
+
raise HashCast::Errors::CastingError, "should be a symbol"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'time'
|
2
2
|
|
3
|
-
class
|
3
|
+
class HashCast::Casters::TimeCaster
|
4
4
|
|
5
5
|
def self.cast(value, attr_name, options = {})
|
6
6
|
if value.is_a?(Time)
|
@@ -9,10 +9,10 @@ class HCast::Casters::TimeCaster
|
|
9
9
|
begin
|
10
10
|
Time.parse(value)
|
11
11
|
rescue ArgumentError => e
|
12
|
-
raise
|
12
|
+
raise HashCast::Errors::CastingError, "is invalid time"
|
13
13
|
end
|
14
14
|
else
|
15
|
-
raise
|
15
|
+
raise HashCast::Errors::CastingError, "should be a time"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# List of build in casters
|
2
|
+
module HashCast::Casters
|
3
|
+
require 'hash_cast/casters/array_caster'
|
4
|
+
require 'hash_cast/casters/boolean_caster'
|
5
|
+
require 'hash_cast/casters/date_caster'
|
6
|
+
require 'hash_cast/casters/datetime_caster'
|
7
|
+
require 'hash_cast/casters/float_caster'
|
8
|
+
require 'hash_cast/casters/hash_caster'
|
9
|
+
require 'hash_cast/casters/integer_caster'
|
10
|
+
require 'hash_cast/casters/string_caster'
|
11
|
+
require 'hash_cast/casters/symbol_caster'
|
12
|
+
require 'hash_cast/casters/time_caster'
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class HashCast::Config
|
2
|
+
attr_accessor :input_keys, :output_keys, :validate_string_null_byte
|
3
|
+
|
4
|
+
def input_keys
|
5
|
+
@input_keys || :symbol
|
6
|
+
end
|
7
|
+
|
8
|
+
def output_keys
|
9
|
+
@output_keys || :symbol
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate_string_null_byte
|
13
|
+
return true if @validate_string_null_byte.nil?
|
14
|
+
|
15
|
+
@validate_string_null_byte
|
16
|
+
end
|
17
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
module
|
1
|
+
module HashCast::Errors
|
2
2
|
|
3
|
-
# Base error class for all
|
4
|
-
class
|
3
|
+
# Base error class for all HashCast errors
|
4
|
+
class HashCastError < StandardError; end
|
5
5
|
|
6
|
-
# Raised when caster with given name is not registered in
|
7
|
-
class CasterNotFoundError <
|
6
|
+
# Raised when caster with given name is not registered in HashCast
|
7
|
+
class CasterNotFoundError < HashCastError; end
|
8
8
|
|
9
|
-
# Raised when some of the given to
|
10
|
-
class ArgumentError <
|
9
|
+
# Raised when some of the given to HashCast argument is not valid
|
10
|
+
class ArgumentError < HashCastError; end
|
11
11
|
|
12
|
-
class AttributeError <
|
12
|
+
class AttributeError < HashCastError
|
13
13
|
attr_reader :namespaces
|
14
14
|
|
15
15
|
def initialize(message, namespace = nil)
|
data/lib/hash_cast.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'hash_cast/version'
|
2
|
+
require 'hash_cast/errors'
|
3
|
+
require 'hash_cast/config'
|
4
|
+
require 'hash_cast/casters'
|
5
|
+
require 'hash_cast/concern.rb'
|
6
|
+
require 'hash_cast/metadata/attribute'
|
7
|
+
require 'hash_cast/attributes_parser'
|
8
|
+
require 'hash_cast/attributes_caster'
|
9
|
+
require 'hash_cast/caster'
|
10
|
+
|
11
|
+
module HashCast
|
12
|
+
@@casters = {}
|
13
|
+
|
14
|
+
# Defines caster without adding own class
|
15
|
+
# @note Not yet implemented
|
16
|
+
def self.create(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns list of defined casters
|
20
|
+
def self.casters
|
21
|
+
@@casters
|
22
|
+
end
|
23
|
+
|
24
|
+
# Adds new casters to HashCast
|
25
|
+
# Allow extend HashCast with your own casters
|
26
|
+
# @param caster_name [Symbol] caster name
|
27
|
+
# @param caster [Class] caster
|
28
|
+
def self.add_caster(caster_name, caster)
|
29
|
+
@@casters[caster_name] = caster
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.config
|
33
|
+
@@config ||= HashCast::Config.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
HashCast.add_caster(:array, HashCast::Casters::ArrayCaster)
|
38
|
+
HashCast.add_caster(:boolean, HashCast::Casters::BooleanCaster)
|
39
|
+
HashCast.add_caster(:date, HashCast::Casters::DateCaster)
|
40
|
+
HashCast.add_caster(:datetime, HashCast::Casters::DateTimeCaster)
|
41
|
+
HashCast.add_caster(:float, HashCast::Casters::FloatCaster)
|
42
|
+
HashCast.add_caster(:hash, HashCast::Casters::HashCaster)
|
43
|
+
HashCast.add_caster(:integer, HashCast::Casters::IntegerCaster)
|
44
|
+
HashCast.add_caster(:string, HashCast::Casters::StringCaster)
|
45
|
+
HashCast.add_caster(:symbol, HashCast::Casters::SymbolCaster)
|
46
|
+
HashCast.add_caster(:time, HashCast::Casters::TimeCaster)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe HashCast::Caster do
|
4
4
|
describe "#cast" do
|
5
5
|
|
6
6
|
class ContactCaster
|
7
|
-
include
|
7
|
+
include HashCast::Caster
|
8
8
|
|
9
9
|
attributes do
|
10
10
|
hash :contact do
|
@@ -82,7 +82,7 @@ describe HCast::Caster do
|
|
82
82
|
|
83
83
|
describe "Custom casters" do
|
84
84
|
class SettingsCaster
|
85
|
-
include
|
85
|
+
include HashCast::Caster
|
86
86
|
|
87
87
|
attributes do
|
88
88
|
string :account
|
@@ -90,7 +90,7 @@ describe HCast::Caster do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
class EmailCaster
|
93
|
-
include
|
93
|
+
include HashCast::Caster
|
94
94
|
|
95
95
|
attributes do
|
96
96
|
string :address
|
@@ -98,7 +98,7 @@ describe HCast::Caster do
|
|
98
98
|
end
|
99
99
|
|
100
100
|
class CompanyCaster
|
101
|
-
include
|
101
|
+
include HashCast::Caster
|
102
102
|
|
103
103
|
attributes do
|
104
104
|
string :name
|
@@ -158,7 +158,7 @@ describe HCast::Caster do
|
|
158
158
|
|
159
159
|
expect do
|
160
160
|
ContactCaster.cast(input_hash)
|
161
|
-
end.to raise_error(
|
161
|
+
end.to raise_error(HashCast::Errors::CastingError, "contact[name] should be a string")
|
162
162
|
end
|
163
163
|
|
164
164
|
it "should raise error if some attribute wasn't given" do
|
@@ -188,7 +188,7 @@ describe HCast::Caster do
|
|
188
188
|
|
189
189
|
expect do
|
190
190
|
ContactCaster.cast(input_hash)
|
191
|
-
end.to raise_error(
|
191
|
+
end.to raise_error(HashCast::Errors::MissingAttributeError, "contact[name] should be given")
|
192
192
|
end
|
193
193
|
|
194
194
|
it "should not raise error if attribute is optional" do
|
@@ -221,7 +221,7 @@ describe HCast::Caster do
|
|
221
221
|
end.to_not raise_error
|
222
222
|
end
|
223
223
|
|
224
|
-
it "
|
224
|
+
it "raises error if skip_unexpected_attributes=false and unexpected attribute was given" do
|
225
225
|
input_hash = {
|
226
226
|
contact: {
|
227
227
|
wrong_attribute: 'foo',
|
@@ -248,11 +248,11 @@ describe HCast::Caster do
|
|
248
248
|
}
|
249
249
|
|
250
250
|
expect do
|
251
|
-
ContactCaster.cast(input_hash)
|
252
|
-
end.to raise_error(
|
251
|
+
ContactCaster.cast(input_hash, skip_unexpected_attributes: false)
|
252
|
+
end.to raise_error(HashCast::Errors::UnexpectedAttributeError, "contact[wrong_attribute] is not valid attribute name")
|
253
253
|
end
|
254
254
|
|
255
|
-
it "
|
255
|
+
it "doesn't raise unexpected attributes error by default" do
|
256
256
|
input_hash = {
|
257
257
|
contact: {
|
258
258
|
wrong_attribute: 'foo',
|
@@ -279,8 +279,8 @@ describe HCast::Caster do
|
|
279
279
|
}
|
280
280
|
|
281
281
|
expect do
|
282
|
-
ContactCaster.cast(input_hash
|
283
|
-
end.not_to raise_error(
|
282
|
+
ContactCaster.cast(input_hash)
|
283
|
+
end.not_to raise_error(HashCast::Errors::UnexpectedAttributeError)
|
284
284
|
|
285
285
|
end
|
286
286
|
|
@@ -343,20 +343,20 @@ describe HCast::Caster do
|
|
343
343
|
it "should raise CaterNotFound exception if caster name is invalid" do
|
344
344
|
expect do
|
345
345
|
class WrongCaster
|
346
|
-
include
|
346
|
+
include HashCast::Caster
|
347
347
|
|
348
348
|
attributes do
|
349
349
|
integr :name
|
350
350
|
end
|
351
351
|
end
|
352
|
-
end.to raise_error(
|
352
|
+
end.to raise_error(HashCast::Errors::CasterNotFoundError)
|
353
353
|
end
|
354
354
|
end
|
355
355
|
|
356
356
|
context "allow nil values" do
|
357
357
|
before(:all) do
|
358
358
|
class HomeCaster
|
359
|
-
include
|
359
|
+
include HashCast::Caster
|
360
360
|
|
361
361
|
attributes do
|
362
362
|
string :city
|
@@ -378,7 +378,32 @@ describe HCast::Caster do
|
|
378
378
|
city: nil,
|
379
379
|
zip: nil
|
380
380
|
)
|
381
|
-
end.to raise_error(
|
381
|
+
end.to raise_error(HashCast::Errors::CastingError, "city should be a string")
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
context "string caster" do
|
386
|
+
before(:all) do
|
387
|
+
class HomeCaster
|
388
|
+
include HashCast::Caster
|
389
|
+
|
390
|
+
attributes do
|
391
|
+
string :city
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
after{ HashCast.config.validate_string_null_byte = nil }
|
397
|
+
|
398
|
+
it "should allow null byte if validate_string_null_byte config is set to false" do
|
399
|
+
HashCast.config.validate_string_null_byte = false
|
400
|
+
HomeCaster.cast(city: "\u0000")
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should not allow null byte if validate_string_null_byte config by default" do
|
404
|
+
expect do
|
405
|
+
HomeCaster.cast(city: "\u0000")
|
406
|
+
end.to raise_error(HashCast::Errors::CastingError, "city contains invalid characters")
|
382
407
|
end
|
383
408
|
end
|
384
409
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe HashCast do
|
4
4
|
|
5
5
|
describe ".create" do
|
6
6
|
it "should cast hash attributes" do
|
@@ -15,7 +15,7 @@ describe HCast do
|
|
15
15
|
}
|
16
16
|
}
|
17
17
|
|
18
|
-
caster =
|
18
|
+
caster = HashCast.create do
|
19
19
|
hash :contact do
|
20
20
|
string :name
|
21
21
|
integer :age
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_cast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Albert Gazizov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -50,34 +50,35 @@ files:
|
|
50
50
|
- ".rspec"
|
51
51
|
- ".ruby-gemset"
|
52
52
|
- ".ruby-version"
|
53
|
+
- CHANGELOG.md
|
53
54
|
- Gemfile
|
54
55
|
- Gemfile.lock
|
55
56
|
- LICENSE.txt
|
56
57
|
- README.md
|
57
58
|
- Rakefile
|
58
|
-
-
|
59
|
-
- lib/
|
60
|
-
- lib/
|
61
|
-
- lib/
|
62
|
-
- lib/
|
63
|
-
- lib/
|
64
|
-
- lib/
|
65
|
-
- lib/
|
66
|
-
- lib/
|
67
|
-
- lib/
|
68
|
-
- lib/
|
69
|
-
- lib/
|
70
|
-
- lib/
|
71
|
-
- lib/
|
72
|
-
- lib/
|
73
|
-
- lib/
|
74
|
-
- lib/
|
75
|
-
- lib/
|
76
|
-
- lib/
|
77
|
-
- lib/
|
78
|
-
- lib/
|
79
|
-
- spec/
|
80
|
-
- spec/
|
59
|
+
- hash_cast.gemspec
|
60
|
+
- lib/hash_cast.rb
|
61
|
+
- lib/hash_cast/attributes_caster.rb
|
62
|
+
- lib/hash_cast/attributes_parser.rb
|
63
|
+
- lib/hash_cast/caster.rb
|
64
|
+
- lib/hash_cast/casters.rb
|
65
|
+
- lib/hash_cast/casters/array_caster.rb
|
66
|
+
- lib/hash_cast/casters/boolean_caster.rb
|
67
|
+
- lib/hash_cast/casters/date_caster.rb
|
68
|
+
- lib/hash_cast/casters/datetime_caster.rb
|
69
|
+
- lib/hash_cast/casters/float_caster.rb
|
70
|
+
- lib/hash_cast/casters/hash_caster.rb
|
71
|
+
- lib/hash_cast/casters/integer_caster.rb
|
72
|
+
- lib/hash_cast/casters/string_caster.rb
|
73
|
+
- lib/hash_cast/casters/symbol_caster.rb
|
74
|
+
- lib/hash_cast/casters/time_caster.rb
|
75
|
+
- lib/hash_cast/concern.rb
|
76
|
+
- lib/hash_cast/config.rb
|
77
|
+
- lib/hash_cast/errors.rb
|
78
|
+
- lib/hash_cast/metadata/attribute.rb
|
79
|
+
- lib/hash_cast/version.rb
|
80
|
+
- spec/hash_cast/caster_spec.rb
|
81
|
+
- spec/hash_cast/hash_cast_spec.rb
|
81
82
|
- spec/spec_helper.rb
|
82
83
|
homepage: http://github.com/droidlabs/hash_cast
|
83
84
|
licenses:
|
@@ -103,6 +104,6 @@ signing_key:
|
|
103
104
|
specification_version: 4
|
104
105
|
summary: Declarative Hash Caster
|
105
106
|
test_files:
|
106
|
-
- spec/
|
107
|
-
- spec/
|
107
|
+
- spec/hash_cast/caster_spec.rb
|
108
|
+
- spec/hash_cast/hash_cast_spec.rb
|
108
109
|
- spec/spec_helper.rb
|
data/lib/hcast/casters.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# List of build in casters
|
2
|
-
module HCast::Casters
|
3
|
-
require 'hcast/casters/array_caster'
|
4
|
-
require 'hcast/casters/boolean_caster'
|
5
|
-
require 'hcast/casters/date_caster'
|
6
|
-
require 'hcast/casters/datetime_caster'
|
7
|
-
require 'hcast/casters/float_caster'
|
8
|
-
require 'hcast/casters/hash_caster'
|
9
|
-
require 'hcast/casters/integer_caster'
|
10
|
-
require 'hcast/casters/string_caster'
|
11
|
-
require 'hcast/casters/symbol_caster'
|
12
|
-
require 'hcast/casters/time_caster'
|
13
|
-
end
|
data/lib/hcast/config.rb
DELETED
data/lib/hcast/version.rb
DELETED
data/lib/hcast.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'hcast/version'
|
2
|
-
require 'hcast/errors'
|
3
|
-
require 'hcast/config'
|
4
|
-
require 'hcast/casters'
|
5
|
-
require 'hcast/concern.rb'
|
6
|
-
require 'hcast/metadata/attribute'
|
7
|
-
require 'hcast/attributes_parser'
|
8
|
-
require 'hcast/attributes_caster'
|
9
|
-
require 'hcast/caster'
|
10
|
-
|
11
|
-
module HCast
|
12
|
-
@@casters = {}
|
13
|
-
|
14
|
-
# Defines caster without adding own class
|
15
|
-
# @note Not yet implemented
|
16
|
-
def self.create(&block)
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns list of defined casters
|
20
|
-
def self.casters
|
21
|
-
@@casters
|
22
|
-
end
|
23
|
-
|
24
|
-
# Adds new casters to HCast
|
25
|
-
# Allow extend HCast with your own casters
|
26
|
-
# @param caster_name [Symbol] caster name
|
27
|
-
# @param caster [Class] caster
|
28
|
-
def self.add_caster(caster_name, caster)
|
29
|
-
@@casters[caster_name] = caster
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.config
|
33
|
-
@@config ||= HCast::Config.new
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
HCast.add_caster(:array, HCast::Casters::ArrayCaster)
|
38
|
-
HCast.add_caster(:boolean, HCast::Casters::BooleanCaster)
|
39
|
-
HCast.add_caster(:date, HCast::Casters::DateCaster)
|
40
|
-
HCast.add_caster(:datetime, HCast::Casters::DateTimeCaster)
|
41
|
-
HCast.add_caster(:float, HCast::Casters::FloatCaster)
|
42
|
-
HCast.add_caster(:hash, HCast::Casters::HashCaster)
|
43
|
-
HCast.add_caster(:integer, HCast::Casters::IntegerCaster)
|
44
|
-
HCast.add_caster(:string, HCast::Casters::StringCaster)
|
45
|
-
HCast.add_caster(:symbol, HCast::Casters::SymbolCaster)
|
46
|
-
HCast.add_caster(:time, HCast::Casters::TimeCaster)
|