hash_schema 0.1.3 → 0.2.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 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