jsexp 1.0.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.
- data/README.md +48 -0
- data/examples/example.rb +26 -0
- data/lib/jsexp.rb +35 -0
- data/test/jsexp_test.rb +64 -0
- metadata +49 -0
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
jsexp
|
2
|
+
=====
|
3
|
+
|
4
|
+
json schemas with s-expressions
|
5
|
+
|
6
|
+
This is a tool to do common json validations. `jsexp` factors out validations into a schema.
|
7
|
+
|
8
|
+
Unlike [JSON Schema](http://tools.ietf.org/html/draft-zyp-json-schema-03), `jsexp` is not written in json and does not specify media types.
|
9
|
+
|
10
|
+
Example
|
11
|
+
-------
|
12
|
+
|
13
|
+
schema = {
|
14
|
+
'name' => String, # case expression
|
15
|
+
'email' => /@/, # case expression
|
16
|
+
'p' => (0.0..1.0), # case expression
|
17
|
+
'id' => [:range, [0, :inf]], # indefinite range
|
18
|
+
'color' => [:enum, ['red', 'green', 'blue']], # enum
|
19
|
+
'offset' => [:tuple, [Float, Float]], # exact-size array
|
20
|
+
'samples' => [:array, [:tuple, [Float, Float]]] # indefinite array
|
21
|
+
'description' => [:optional, String] # optional field
|
22
|
+
}
|
23
|
+
obj = {
|
24
|
+
'name' => '',
|
25
|
+
'email' => 'user@example.com',
|
26
|
+
'p' => 0.5,
|
27
|
+
'id' => 0,
|
28
|
+
'color' => 'red',
|
29
|
+
'offset' => [0.0, 0.0],
|
30
|
+
'samples' => [
|
31
|
+
[0.0, 0.0],
|
32
|
+
[0.0, 0.0]
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
puts JSExp.valid?(schema, obj)
|
37
|
+
# true
|
38
|
+
|
39
|
+
Non-features
|
40
|
+
------------
|
41
|
+
|
42
|
+
- default values: use defaults.merge(input) prior to validation
|
43
|
+
- string length bounds: use /^.{3,5}$/
|
44
|
+
- array/map size bounds
|
45
|
+
- key expressions
|
46
|
+
- nested schemas: This is a source of arbitrary complexity.
|
47
|
+
- specific error messages: Refer to the schema to see what's wrong.
|
48
|
+
- lambdas: Do more complex validation yourself.
|
data/examples/example.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'jsexp'
|
2
|
+
|
3
|
+
schema = {
|
4
|
+
'name' => String,
|
5
|
+
'email' => /@/,
|
6
|
+
'p' => (0.0..1.0),
|
7
|
+
'id' => [:range, [0, :inf]],
|
8
|
+
'color' => [:enum, ['red', 'green', 'blue']],
|
9
|
+
'offset' => [:tuple, [Float, Float]],
|
10
|
+
'samples' => [:array, [:tuple, [Float, Float]]],
|
11
|
+
'description' => [:optional, String]
|
12
|
+
}
|
13
|
+
obj = {
|
14
|
+
'name' => '',
|
15
|
+
'email' => 'user@example.com',
|
16
|
+
'p' => 0.5,
|
17
|
+
'id' => 0,
|
18
|
+
'color' => 'red',
|
19
|
+
'offset' => [0.0, 0.0],
|
20
|
+
'samples' => [
|
21
|
+
[0.0, 0.0],
|
22
|
+
[0.0, 0.0]
|
23
|
+
]
|
24
|
+
}
|
25
|
+
|
26
|
+
puts JSExp.valid?(schema, obj)
|
data/lib/jsexp.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module JSExp
|
2
|
+
|
3
|
+
def JSExp.valid?(schema, obj)
|
4
|
+
if schema.is_a?(Hash)
|
5
|
+
obj.is_a?(Hash) && schema.map {|key, schema_|
|
6
|
+
if schema_.is_a?(Array) && schema_[0] == :optional
|
7
|
+
!obj.key?(key) || valid?(schema_[1], obj[key])
|
8
|
+
else
|
9
|
+
obj.key?(key) && valid?(schema_, obj[key])
|
10
|
+
end
|
11
|
+
}.all?
|
12
|
+
elsif schema.is_a?(Array)
|
13
|
+
case schema[0]
|
14
|
+
when :array
|
15
|
+
obj.is_a?(Array) && obj.map {|x| valid?(schema[1], x)}.all?
|
16
|
+
when :enum
|
17
|
+
schema[1].include?(obj)
|
18
|
+
when :range
|
19
|
+
min, max = schema[1]
|
20
|
+
(min == :inf ? true : obj.class == min.class && obj >= min) &&
|
21
|
+
(max == :inf ? true : obj.class == max.class && obj <= max)
|
22
|
+
when :tuple
|
23
|
+
obj.is_a?(Array) && obj.size == schema[1].size && schema[1].each_index.map {|i| valid?(schema[1][i], obj[i])}.all?
|
24
|
+
end
|
25
|
+
else
|
26
|
+
case obj
|
27
|
+
when schema
|
28
|
+
true
|
29
|
+
else
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/test/jsexp_test.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
2
|
+
require 'jsexp'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
describe JSExp do
|
6
|
+
it 'validates case expressions' do
|
7
|
+
JSExp.valid?(String, '').must_equal true
|
8
|
+
JSExp.valid?(String, 0).must_equal false
|
9
|
+
|
10
|
+
JSExp.valid?(Integer, 0).must_equal true
|
11
|
+
JSExp.valid?(Integer, 0.0).must_equal false
|
12
|
+
|
13
|
+
JSExp.valid?(Float, 0.0).must_equal true
|
14
|
+
JSExp.valid?(Float, 0).must_equal false
|
15
|
+
|
16
|
+
JSExp.valid?(/@/, 'user@example.com').must_equal true
|
17
|
+
JSExp.valid?(/@/, '').must_equal false
|
18
|
+
|
19
|
+
JSExp.valid?((0..10), 5).must_equal true
|
20
|
+
JSExp.valid?((0..10), 11).must_equal false
|
21
|
+
|
22
|
+
JSExp.valid?((0.0..1.0), 0.5).must_equal true
|
23
|
+
JSExp.valid?((0.0..1.0), 1.1).must_equal false
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'validates indefinite arrays' do
|
27
|
+
JSExp.valid?([:array, Integer], []).must_equal true
|
28
|
+
JSExp.valid?([:array, Integer], [0]).must_equal true
|
29
|
+
JSExp.valid?([:array, Integer], [0, 0]).must_equal true
|
30
|
+
JSExp.valid?([:array, Integer], [0.0]).must_equal false
|
31
|
+
JSExp.valid?([:array, Integer], [0, 0.0]).must_equal false
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'validates enums' do
|
35
|
+
JSExp.valid?([:enum, ['red', 'green', 'blue']], 'red').must_equal true
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'validates optional fields' do
|
39
|
+
schema = {
|
40
|
+
'id' => [:optional, String]
|
41
|
+
}
|
42
|
+
JSExp.valid?(schema, {}).must_equal true
|
43
|
+
JSExp.valid?(schema, {'id' => ''}).must_equal true
|
44
|
+
JSExp.valid?(schema, {'id' => 0}).must_equal false
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'validates indefinite ranges' do
|
48
|
+
JSExp.valid?([:range, [0, :inf]], 0).must_equal true
|
49
|
+
JSExp.valid?([:range, [0, :inf]], -1).must_equal false
|
50
|
+
JSExp.valid?([:range, [0, :inf]], 0.0).must_equal false
|
51
|
+
|
52
|
+
JSExp.valid?([:range, [:inf, 0]], 0).must_equal true
|
53
|
+
JSExp.valid?([:range, [:inf, 0]], 1).must_equal false
|
54
|
+
|
55
|
+
JSExp.valid?([:range, [:inf, :inf]], 0).must_equal true
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'validates tuples' do
|
59
|
+
JSExp.valid?([:tuple, [Integer, Float]], [0, 0.0]).must_equal true
|
60
|
+
JSExp.valid?([:tuple, [Integer, Float]], 0).must_equal false
|
61
|
+
JSExp.valid?([:tuple, [Integer, Float]], [0]).must_equal false
|
62
|
+
JSExp.valid?([:tuple, [Integer, Float]], [0, 0.0, 0]).must_equal false
|
63
|
+
end
|
64
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jsexp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matthew King
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: json schemas with s-expressions
|
15
|
+
email: matthew.y.king@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- README.md
|
21
|
+
- examples/example.rb
|
22
|
+
- lib/jsexp.rb
|
23
|
+
- test/jsexp_test.rb
|
24
|
+
homepage: http://github.com/mking/jsexp
|
25
|
+
licenses: []
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 1.8.11
|
45
|
+
signing_key:
|
46
|
+
specification_version: 3
|
47
|
+
summary: json schemas
|
48
|
+
test_files:
|
49
|
+
- test/jsexp_test.rb
|