hash_schema 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 772c753165bbc1e83ce3c65fe5b45bb49ec3365c
4
- data.tar.gz: 625cddb7219d5a8e04157d3710382d4e01725f52
3
+ metadata.gz: b87caa584dee8275eeb175b5fe4b8d36107db062
4
+ data.tar.gz: 9d03b279577309ed4af1cfa41ba785fc03941641
5
5
  SHA512:
6
- metadata.gz: 90439941e93b65e6880ec0683d23c20466264a13eca95c566eb680dc43e25f5f83abe14a0f53e72046350cb9b701e452d2fbf530bb4d47c51421488983f73f54
7
- data.tar.gz: abdc89cc5ef3026d536f7656be1060f6a109ab3a999a37d4b2618ff88f81a1a1e13ba5e17df5828e90b9e4346f1a90ef92f8df16517667edec85475698676dd0
6
+ metadata.gz: e608f9f48ae0fd3ff26f58c081b45677a49fb9763fc723d81e4d4f6cfaf76086caead85c9a3d00f8e5783c71e11e0732a10f340fb0391be5578413fbbb1c43b7
7
+ data.tar.gz: 0c01d4c2e02eaa7d2fb02b1756ddb666281fc0d1d5580e45585da54518e4cc81950f060d93fe81b35a811c571026983323d7ff94cb3e7d2d4f4fa69d500785ad
@@ -0,0 +1 @@
1
+ 2.3.1
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ cache:
3
+ bundler: true
4
+ sudo: false
5
+ branches:
6
+ only: master
data/README.md CHANGED
@@ -18,22 +18,110 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
+ ### What it is / isn't for
22
+
23
+ It is for:
24
+
25
+ - validating structure
26
+ - e.g. a hash contains keys `greetings` and `name`, and `name` is an inner hash that contains `give`, `family` and `other`
27
+ - { "greetings": "Hello", "name": { "given": "John", "family": "Doe", "other": "" } }
28
+ - validating data type
29
+ - e.g. { "offset": [7, 8] }, where `offset` has to be an array of numbers
30
+ - validating constants
31
+ - e.g. some value has to be set to `true`
32
+
33
+ It is **not** for:
34
+
35
+ - validating dependency
36
+ - e.g. key A has to exist if key B exists
37
+
38
+ [Jump down to see detailed example](#demo)
39
+
21
40
  ### Defined schemas
22
41
 
23
- * StringSchema
24
- * NumberSchema
25
- * BooleanSchema
26
- * EnumSchema
27
- * OptionalSchema
28
- * OrSchema
29
- * ArraySchema
30
- * **HashSchema**
42
+ #### StringSchema
43
+
44
+ - `.new`
45
+ - takes no arguments
46
+ - `#validate` :: (String|\*) -> (*Null*|error)
47
+
48
+ #### NumberSchema
49
+
50
+ - `.new`
51
+ - takes no arguments
52
+ - `#validate` :: (Number|\*) -> (*Null*|error)
53
+
54
+ #### BooleanSchema
55
+
56
+ - `.new`
57
+ - takes no arguments
58
+ - `#validate` :: (Boolean|\*) -> (*Null*|error)
59
+
60
+ #### EnumSchema
61
+
62
+ - `.new`
63
+ - takes literal constants, e.g. 123, "456", false, true...
64
+ - `#validate` :: (\*) -> (*Null*|error)
65
+ - An inclusion check is performed
31
66
 
32
- ### API
67
+ #### OptionalSchema
68
+
69
+ - `.new`
70
+ - takes a Schema or literal constant
71
+ - `#validate` :: (Void|\*) -> (*Null*|error)
72
+ - `Void.new` is the internal representation of `Nothing`
73
+ - if anything other than `Void.new` is given
74
+ - it is delegated to the Schema, if a Schema was given when initializing
75
+ - it performs equality check, if initialized with anything other than a Schema
76
+
77
+ #### OrSchema
78
+
79
+ - `.new`
80
+ - takes multiple Schemas
81
+ - `#validate` :: (\*) -> (*Null*|error)
82
+ - it passes if any of the given Schema passes
83
+ - it errors if all of the given Schema end up with error
84
+
85
+ #### ArraySchema
86
+
87
+ - `.new`
88
+ - takes one Schemas
89
+ - `#validate` :: (Array|\*) -> (**Array**|error)
90
+ - it errors if the arugment passed to `#validate` is not an array
91
+ - it maps the Schema validation over the elements in the array
92
+ - it returns the mapped-over array
93
+
94
+ #### HashSchema
95
+
96
+ - `.new`
97
+ - takes keywords, see `#1`
98
+ - other than Schemas, you can also specify literal constants like in `#2`
99
+ - you can specify `strict` mode if you want to see errors for not specified keys
100
+ - if you have the key `strict` in your data hash, see `#3`
101
+
102
+ ```ruby
103
+ #1
104
+ HashSchema.new(a: NumberSchema.new, b: BooleanSchema.new, c: StringSchema.new)
105
+
106
+ #2
107
+ HashSchema.new(strict: true,
108
+ number: 1,
109
+ boolean: true,
110
+ string: 'string',
111
+ ampm_array: ArraySchema.new(EnumSchema.new('am', 'pm'))
112
+ )
113
+
114
+ #3
115
+ HashSchema.new(strict: true,
116
+ schema_hash: {
117
+ strict: 'I am strict'
118
+ }
119
+ )
120
+ ```
33
121
 
34
- - `#valdiate` :: Hash -> Hash
35
- - `#pretty_validate` :: Hash -> String **(*)**
36
- - `#interpret` :: Hash -> [String]
122
+ - `#valdiate` :: (Hash|\*) -> (**Hash**|error)
123
+ - `#pretty_validate` :: (Hash|\*) -> String **(*)**
124
+ - `#interpret` :: (Hash|\*) -> [String]
37
125
 
38
126
  **(*)** `#pretty_validate` is just a `JSON.pretty_generate` wrapper of `#validate`
39
127
 
@@ -86,19 +86,65 @@ module HashSchema
86
86
  end
87
87
 
88
88
  def validate(data)
89
+ empty_error = true
90
+ last_error = nil
89
91
  chain.each do |schema|
90
- if data.is_a?(Array) && schema.is_a?(ArraySchema) || data.is_a?(Hash) && schema.is_a?(HashSchema)
91
- return schema.validate(data)
92
- end
93
- return if schema.validate(data).nil?
92
+ next unless schema_matches_data_type(schema, data)
93
+ last_error = schema.validate(data)
94
+ empty_error = recursive_empty_error?(last_error)
95
+ break if empty_error
96
+ end
97
+ if empty_error
98
+ last_error
99
+ else
100
+ error(data)
94
101
  end
95
- error(data)
96
102
  end
97
103
 
98
104
  def expectation
99
105
  *names, name = chain.map(&:expectation)
100
106
  names.join(', ') << " or #{name}"
101
107
  end
108
+
109
+ private
110
+
111
+ def recursive_empty_error?(error)
112
+ case error
113
+ when NilClass
114
+ true
115
+ when String
116
+ false
117
+ when Hash, Array
118
+ recursive_flat_error_values(error).empty?
119
+ else
120
+ false
121
+ end
122
+ end
123
+
124
+ def schema_matches_data_type(schema, data)
125
+ case schema
126
+ when ArraySchema
127
+ data.is_a? Array
128
+ when HashSchema
129
+ data.is_a? Hash
130
+ else
131
+ true
132
+ end
133
+ end
134
+
135
+ def recursive_flat_error_values(error_object)
136
+ if error_object.is_a? Hash
137
+ error_object.values.flat_map do |value|
138
+ recursive_flat_error_values(value)
139
+ end.compact
140
+ elsif error_object.is_a? Array
141
+ error_object.flat_map do |value|
142
+ recursive_flat_error_values(value)
143
+ end.compact
144
+ else
145
+ error_object
146
+ end
147
+ end
102
148
  end
103
149
 
104
150
  class StringSchema < Schema
@@ -1,3 +1,3 @@
1
1
  module HashSchema
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -113,6 +113,9 @@ describe HashSchema do
113
113
  HashSchema::NumberSchema.new,
114
114
  HashSchema::StringSchema.new,
115
115
  HashSchema::ArraySchema.new(HashSchema::StringSchema.new),
116
+ HashSchema::ArraySchema.new(HashSchema::NumberSchema.new),
117
+ HashSchema::ArraySchema.new(HashSchema::HashSchema.new(stringy: HashSchema::StringSchema.new)),
118
+ HashSchema::HashSchema.new(boolean: HashSchema::BooleanSchema),
116
119
  HashSchema::HashSchema.new
117
120
  )
118
121
  end
@@ -131,7 +134,25 @@ describe HashSchema do
131
134
  end
132
135
 
133
136
  it 'delegates to given HashSchema for hash' do
134
- expect(multitype.validate({})).to be_a(Hash)
137
+ expect(multitype.validate(boolean: true)).to be_a(Hash)
138
+ end
139
+
140
+ it 'delegates to more than one inner ArraySchema' do
141
+ validation_result = multitype.validate([1, 2, 3])
142
+ expect(validation_result).to be_a(Array)
143
+ expect(validation_result.compact).to be_empty
144
+ end
145
+
146
+ it 'delegates to more than one inner HashSchema' do
147
+ validation_result = multitype.validate(boolean: 5)
148
+ expect(validation_result).to be_a(Hash)
149
+ expect(validation_result.values.compact).to be_empty
150
+ end
151
+
152
+ it 'recurses into hashes and arrays' do
153
+ validation_result = multitype.validate([ { stringy: 'hello' } ])
154
+ expect(validation_result).to be_a(Array)
155
+ expect(validation_result).to eq [ { stringy: nil } ]
135
156
  end
136
157
  end
137
158
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Po Chen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-06 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bump
@@ -91,6 +91,8 @@ extensions: []
91
91
  extra_rdoc_files: []
92
92
  files:
93
93
  - ".gitignore"
94
+ - ".ruby-version"
95
+ - ".travis.yml"
94
96
  - Gemfile
95
97
  - LICENSE.txt
96
98
  - README.md
@@ -120,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
122
  version: '0'
121
123
  requirements: []
122
124
  rubyforge_project:
123
- rubygems_version: 2.2.2
125
+ rubygems_version: 2.6.4
124
126
  signing_key:
125
127
  specification_version: 4
126
128
  summary: Validate Hash against Schema