respect 0.1.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/MIT-LICENSE +20 -0
- data/README.md +289 -0
- data/RELATED_WORK.md +40 -0
- data/RELEASE_NOTES.md +23 -0
- data/Rakefile +31 -0
- data/STATUS_MATRIX.html +137 -0
- data/lib/respect.rb +231 -0
- data/lib/respect/any_schema.rb +22 -0
- data/lib/respect/array_def.rb +28 -0
- data/lib/respect/array_schema.rb +203 -0
- data/lib/respect/boolean_schema.rb +32 -0
- data/lib/respect/composite_schema.rb +86 -0
- data/lib/respect/core_statements.rb +206 -0
- data/lib/respect/datetime_schema.rb +27 -0
- data/lib/respect/def_without_name.rb +6 -0
- data/lib/respect/divisible_by_validator.rb +20 -0
- data/lib/respect/doc_helper.rb +24 -0
- data/lib/respect/doc_parser.rb +37 -0
- data/lib/respect/dsl_dumper.rb +181 -0
- data/lib/respect/equal_to_validator.rb +20 -0
- data/lib/respect/fake_name_proxy.rb +116 -0
- data/lib/respect/float_schema.rb +27 -0
- data/lib/respect/format_validator.rb +136 -0
- data/lib/respect/global_def.rb +79 -0
- data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/greater_than_validator.rb +19 -0
- data/lib/respect/has_constraints.rb +34 -0
- data/lib/respect/hash_def.rb +40 -0
- data/lib/respect/hash_schema.rb +218 -0
- data/lib/respect/in_validator.rb +19 -0
- data/lib/respect/integer_schema.rb +27 -0
- data/lib/respect/ip_addr_schema.rb +23 -0
- data/lib/respect/ipv4_addr_schema.rb +27 -0
- data/lib/respect/ipv6_addr_schema.rb +27 -0
- data/lib/respect/items_def.rb +21 -0
- data/lib/respect/json_schema_html_formatter.rb +143 -0
- data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/less_than_validator.rb +19 -0
- data/lib/respect/match_validator.rb +19 -0
- data/lib/respect/max_length_validator.rb +20 -0
- data/lib/respect/min_length_validator.rb +20 -0
- data/lib/respect/multiple_of_validator.rb +10 -0
- data/lib/respect/null_schema.rb +26 -0
- data/lib/respect/numeric_schema.rb +33 -0
- data/lib/respect/org3_dumper.rb +213 -0
- data/lib/respect/regexp_schema.rb +19 -0
- data/lib/respect/schema.rb +285 -0
- data/lib/respect/schema_def.rb +16 -0
- data/lib/respect/string_schema.rb +21 -0
- data/lib/respect/unit_test_helper.rb +37 -0
- data/lib/respect/uri_schema.rb +23 -0
- data/lib/respect/utc_time_schema.rb +17 -0
- data/lib/respect/validator.rb +51 -0
- data/lib/respect/version.rb +3 -0
- data/test/any_schema_test.rb +79 -0
- data/test/array_def_test.rb +113 -0
- data/test/array_schema_test.rb +487 -0
- data/test/boolean_schema_test.rb +89 -0
- data/test/composite_schema_test.rb +30 -0
- data/test/datetime_schema_test.rb +83 -0
- data/test/doc_helper_test.rb +34 -0
- data/test/doc_parser_test.rb +109 -0
- data/test/dsl_dumper_test.rb +395 -0
- data/test/fake_name_proxy_test.rb +138 -0
- data/test/float_schema_test.rb +146 -0
- data/test/format_validator_test.rb +224 -0
- data/test/hash_def_test.rb +126 -0
- data/test/hash_schema_test.rb +613 -0
- data/test/integer_schema_test.rb +142 -0
- data/test/ip_addr_schema_test.rb +78 -0
- data/test/ipv4_addr_schema_test.rb +71 -0
- data/test/ipv6_addr_schema_test.rb +71 -0
- data/test/json_schema_html_formatter_test.rb +214 -0
- data/test/null_schema_test.rb +46 -0
- data/test/numeric_schema_test.rb +294 -0
- data/test/org3_dumper_test.rb +784 -0
- data/test/regexp_schema_test.rb +54 -0
- data/test/respect_test.rb +108 -0
- data/test/schema_def_test.rb +405 -0
- data/test/schema_test.rb +290 -0
- data/test/string_schema_test.rb +209 -0
- data/test/support/circle.rb +11 -0
- data/test/support/color.rb +24 -0
- data/test/support/point.rb +11 -0
- data/test/support/respect/circle_schema.rb +16 -0
- data/test/support/respect/color_def.rb +19 -0
- data/test/support/respect/color_schema.rb +33 -0
- data/test/support/respect/point_schema.rb +19 -0
- data/test/support/respect/rgba_schema.rb +20 -0
- data/test/support/respect/universal_validator.rb +25 -0
- data/test/support/respect/user_macros.rb +12 -0
- data/test/support/rgba.rb +11 -0
- data/test/test_helper.rb +90 -0
- data/test/uri_schema_test.rb +54 -0
- data/test/utc_time_schema_test.rb +63 -0
- data/test/validator_test.rb +22 -0
- metadata +288 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
class Color
|
2
|
+
class FormatError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def from_string(str)
|
7
|
+
if str.to_s =~ /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/
|
8
|
+
Color.new($1.to_i(16), $2.to_i(16), $3.to_i(16), $4.to_i(16))
|
9
|
+
else
|
10
|
+
raise FormatError, "'#{str}' does not match color regexp"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(red, green, blue, alpha)
|
16
|
+
@red, @green, @blue, @alpha = red, green, blue, alpha
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :red, :green, :blue, :alpha
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
@red == other.red && @green == other.green && @blue == other.blue && @alpha == other.alpha
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a custom type based on another custom type.
|
4
|
+
class CircleSchema < CompositeSchema
|
5
|
+
def schema_definition
|
6
|
+
HashSchema.define do |s|
|
7
|
+
s.point "center"
|
8
|
+
s.float "radius", greater_than: 0.0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def sanitize(doc)
|
13
|
+
Circle.new(doc[:center], doc[:radius])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Respect
|
2
|
+
class ColorDef < GlobalDef
|
3
|
+
def initialize(options = {})
|
4
|
+
@color_schema = ColorSchema.new(options)
|
5
|
+
end
|
6
|
+
|
7
|
+
[ :red, :green, :blue, :alpha ].each do |name|
|
8
|
+
define_method(name) do |value|
|
9
|
+
@color_schema.send("#{name}=", value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def evaluation_result
|
16
|
+
@color_schema
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Respect
|
2
|
+
class ColorSchema < Schema
|
3
|
+
|
4
|
+
public_class_method :new
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
super
|
8
|
+
@red, @green, @blue, @alpha = 0, 0, 0, 0
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :red, :green, :blue, :alpha
|
12
|
+
|
13
|
+
def validate(doc)
|
14
|
+
color = nil
|
15
|
+
begin
|
16
|
+
color = Color.from_string(doc.to_s)
|
17
|
+
rescue Color::FormatError => e
|
18
|
+
raise ValidationError, "invalid color: #{e.message}"
|
19
|
+
end
|
20
|
+
[ :red, :green, :blue, :alpha ].each do |part|
|
21
|
+
if expected = send(part)
|
22
|
+
value = color.send(part)
|
23
|
+
unless value == expected
|
24
|
+
raise ValidationError, "color part #{part} is #{value} but should be #{expected}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self.sanitized_object = color
|
29
|
+
end
|
30
|
+
|
31
|
+
end # class ColorSchema
|
32
|
+
|
33
|
+
end # module Respect
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a custom type providing both a composition macro and a
|
4
|
+
# sanitizer block.
|
5
|
+
class PointSchema < CompositeSchema
|
6
|
+
|
7
|
+
def schema_definition
|
8
|
+
HashSchema.define do |s|
|
9
|
+
s.float "x"
|
10
|
+
s.float "y"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sanitize(doc)
|
15
|
+
Point.new(doc["x"], doc["y"])
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a composite schema based on an array schema.
|
4
|
+
class RgbaSchema < CompositeSchema
|
5
|
+
def schema_definition
|
6
|
+
ArraySchema.define do |s|
|
7
|
+
s.items do |s|
|
8
|
+
s.color_channel # red
|
9
|
+
s.color_channel # green
|
10
|
+
s.color_channel # blue
|
11
|
+
s.color_channel # alpha
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def sanitize(doc)
|
17
|
+
Rgba.new(doc[0], doc[1], doc[2], doc[3])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the validator hierarchy
|
3
|
+
# with their own ones.
|
4
|
+
class UniversalValidator < Validator
|
5
|
+
|
6
|
+
def initialize(enabled)
|
7
|
+
@enabled = enabled
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate(value)
|
11
|
+
if @enabled
|
12
|
+
unless value == 42
|
13
|
+
raise ValidationError, "#{value} is not a universal value"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def to_h_org3
|
21
|
+
{ "minimum" => 42, "maximum" => 42 }
|
22
|
+
end
|
23
|
+
|
24
|
+
end # class UniversalValidator
|
25
|
+
end # module Respect
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test module proving that users can easily extend the definition DSL
|
3
|
+
# with their own macros bundled in their own modules organized as they
|
4
|
+
# want.
|
5
|
+
module UserMacros
|
6
|
+
def color_channel(name)
|
7
|
+
float name, in: 0.0..1.0
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
extend_dsl_with(UserMacros)
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Rgba
|
2
|
+
def initialize(red, green, blue, alpha)
|
3
|
+
@red, @green, @blue, @alpha = red, green, blue, alpha
|
4
|
+
end
|
5
|
+
|
6
|
+
attr_reader :red, :green, :blue, :alpha
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
@red == other.red && @green == other.green && @blue == other.blue && @alpha == other.alpha
|
10
|
+
end
|
11
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'debugger'
|
3
|
+
|
4
|
+
require 'respect'
|
5
|
+
|
6
|
+
# Test that "hash" methods has been removed from GlabelDef as soon as we load "respect".
|
7
|
+
# We cannot do it in HashSchema since the "hash" method maybe call before hand.
|
8
|
+
if Respect::GlobalDef.new.respond_to? :hash
|
9
|
+
raise "'hash' method should have been removed before Respect::HashSchema class is loaded."
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'respect/unit_test_helper'
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
# Similar to assert_raises but return the exception object caught.
|
16
|
+
def assert_exception(exception_class, message = nil, &block)
|
17
|
+
begin
|
18
|
+
block.call
|
19
|
+
assert false, message
|
20
|
+
rescue exception_class => e
|
21
|
+
e
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Load support files
|
27
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
28
|
+
|
29
|
+
# It *MUST* be defined before EndUserDSLStatement.
|
30
|
+
module Respect
|
31
|
+
# A class to test DSL extension.
|
32
|
+
class CoreDef < GlobalDef
|
33
|
+
include_core_statements
|
34
|
+
include DefWithoutName
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A module to test statement extension helper.
|
39
|
+
module EndUserDSLStatement
|
40
|
+
|
41
|
+
def id(name = "id")
|
42
|
+
integer name, greater_than: 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def call_to_kernel
|
46
|
+
# The point is to call an instance method of the Kernel module.
|
47
|
+
integer "kernel", equal_to: Integer(0)
|
48
|
+
end
|
49
|
+
|
50
|
+
def call_to_object
|
51
|
+
# The point is to call an instance method of the Object class.
|
52
|
+
string "object", equal_to: self.class.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
Respect.extend_dsl_with(EndUserDSLStatement)
|
58
|
+
|
59
|
+
FORMAT_HELPER_STATEMENTS_LIST = [
|
60
|
+
:phone_number,
|
61
|
+
:hostname,
|
62
|
+
:email,
|
63
|
+
]
|
64
|
+
|
65
|
+
PRIMITIVE_STATEMENTS_LIST = [
|
66
|
+
:integer,
|
67
|
+
:string,
|
68
|
+
:any,
|
69
|
+
:boolean,
|
70
|
+
:null,
|
71
|
+
:float,
|
72
|
+
:numeric,
|
73
|
+
:uri,
|
74
|
+
:regexp,
|
75
|
+
:datetime,
|
76
|
+
:ipv4_addr,
|
77
|
+
:ipv6_addr,
|
78
|
+
:ip_addr,
|
79
|
+
]
|
80
|
+
|
81
|
+
TERMINAL_STATEMENTS_LIST = FORMAT_HELPER_STATEMENTS_LIST + PRIMITIVE_STATEMENTS_LIST
|
82
|
+
|
83
|
+
COMPOSITE_STATEMENTS_LIST = [
|
84
|
+
:hash,
|
85
|
+
:array,
|
86
|
+
]
|
87
|
+
|
88
|
+
BASIC_STATEMENTS_LIST = TERMINAL_STATEMENTS_LIST + COMPOSITE_STATEMENTS_LIST
|
89
|
+
|
90
|
+
require "mocha/setup"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class URISchemaTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_uri_schema_creates_uri_object
|
6
|
+
s = Respect::URISchema.new
|
7
|
+
assert_nil s.sanitized_object
|
8
|
+
assert_schema_validate s, "http://foo.com"
|
9
|
+
assert s.sanitized_object.is_a?(URI::Generic)
|
10
|
+
assert_equal "http://foo.com", s.sanitized_object.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_uri_schema_relies_on_format_validator
|
14
|
+
doc = "http://foo.com"
|
15
|
+
Respect::FormatValidator.any_instance.stubs(:validate_uri).with(doc).at_least_once
|
16
|
+
Respect::URISchema.new.validate(doc)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_failed_validation_reset_sanitized_object
|
20
|
+
s = Respect::URISchema.new
|
21
|
+
assert_schema_validate(s, "http://foo.com")
|
22
|
+
assert_not_nil(s.sanitized_object)
|
23
|
+
assert_schema_invalidate(s, "<")
|
24
|
+
assert_nil(s.sanitized_object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_allow_nil
|
28
|
+
s = Respect::URISchema.new(allow_nil: true)
|
29
|
+
assert s.allow_nil?
|
30
|
+
assert_schema_validate s, nil
|
31
|
+
assert_equal(nil, s.sanitized_object)
|
32
|
+
assert_schema_validate s, "http://foo.com"
|
33
|
+
assert_not_nil(s.sanitized_object)
|
34
|
+
assert_schema_invalidate(s, "<")
|
35
|
+
assert_nil(s.sanitized_object)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_disallow_nil
|
39
|
+
s = Respect::URISchema.new
|
40
|
+
assert !s.allow_nil?
|
41
|
+
exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
|
42
|
+
assert_match exception.message, /\bURISchema\b/
|
43
|
+
assert_equal(nil, s.sanitized_object)
|
44
|
+
assert_schema_validate s, "http://foo.com"
|
45
|
+
assert_not_nil(s.sanitized_object)
|
46
|
+
assert_schema_invalidate(s, "<")
|
47
|
+
assert_nil(s.sanitized_object)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_validate_uri_object
|
51
|
+
s = Respect::URISchema.new
|
52
|
+
assert_schema_validate(s, URI.parse("http://foo.com"))
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class UTCTimeSchemaTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_utc_time_schema_creates_time_object
|
6
|
+
s = Respect::UTCTimeSchema.new
|
7
|
+
assert_nil s.sanitized_object
|
8
|
+
t = Time.now.to_i
|
9
|
+
assert_schema_validate s, t.to_s
|
10
|
+
assert_equal Time, s.sanitized_object.class
|
11
|
+
assert_equal(t, s.sanitized_object.to_i)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_utc_time_schema_accept_float
|
15
|
+
s = Respect::UTCTimeSchema.new
|
16
|
+
assert_nil s.sanitized_object
|
17
|
+
t = Time.now.to_f
|
18
|
+
assert_schema_validate s, t.to_s
|
19
|
+
assert_equal Time, s.sanitized_object.class
|
20
|
+
assert_equal(t, s.sanitized_object.to_f)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_utc_time_schema_do_not_accept_negative
|
24
|
+
s = Respect::UTCTimeSchema.new
|
25
|
+
begin
|
26
|
+
s.validate(-1)
|
27
|
+
assert false
|
28
|
+
rescue Respect::ValidationError => e
|
29
|
+
assert_match(/-1/, e.message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_failed_validation_reset_sanitized_object
|
34
|
+
s = Respect::UTCTimeSchema.new
|
35
|
+
assert_schema_validate(s, 42)
|
36
|
+
assert_not_nil(s.sanitized_object)
|
37
|
+
assert_schema_invalidate(s, "*")
|
38
|
+
assert_nil(s.sanitized_object)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_allow_nil
|
42
|
+
s = Respect::UTCTimeSchema.new(allow_nil: true)
|
43
|
+
assert s.allow_nil?
|
44
|
+
assert_schema_validate s, nil
|
45
|
+
assert_equal(nil, s.sanitized_object)
|
46
|
+
assert_schema_validate s, 42
|
47
|
+
assert_not_nil(s.sanitized_object)
|
48
|
+
assert_schema_invalidate(s, "wrong")
|
49
|
+
assert_nil(s.sanitized_object)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_disallow_nil
|
53
|
+
s = Respect::UTCTimeSchema.new
|
54
|
+
assert !s.allow_nil?
|
55
|
+
exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
|
56
|
+
assert_match exception.message, /\bUTCTimeSchema\b/
|
57
|
+
assert_equal(nil, s.sanitized_object)
|
58
|
+
assert_schema_validate s, 42
|
59
|
+
assert_not_nil(s.sanitized_object)
|
60
|
+
assert_schema_invalidate(s, "wrong")
|
61
|
+
assert_nil(s.sanitized_object)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ValidatorTest < Test::Unit::TestCase
|
4
|
+
def test_constraint_name
|
5
|
+
assert_equal "equal_to", Respect::EqualToValidator.constraint_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_end_user_validator
|
9
|
+
s = Respect::IntegerSchema.new(universal: true)
|
10
|
+
assert_schema_invalidate s, 52
|
11
|
+
assert_schema_validate s, 42
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_end_user_validate_get_called
|
15
|
+
value = 1664
|
16
|
+
v = Respect::UniversalValidator.new(true)
|
17
|
+
Respect::UniversalValidator.expects(:new).with(true).returns(v)
|
18
|
+
v.stubs(:validate).with(value).at_least_once
|
19
|
+
Respect::IntegerSchema.new(universal: true).validate(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|