respect 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +289 -0
  3. data/RELATED_WORK.md +40 -0
  4. data/RELEASE_NOTES.md +23 -0
  5. data/Rakefile +31 -0
  6. data/STATUS_MATRIX.html +137 -0
  7. data/lib/respect.rb +231 -0
  8. data/lib/respect/any_schema.rb +22 -0
  9. data/lib/respect/array_def.rb +28 -0
  10. data/lib/respect/array_schema.rb +203 -0
  11. data/lib/respect/boolean_schema.rb +32 -0
  12. data/lib/respect/composite_schema.rb +86 -0
  13. data/lib/respect/core_statements.rb +206 -0
  14. data/lib/respect/datetime_schema.rb +27 -0
  15. data/lib/respect/def_without_name.rb +6 -0
  16. data/lib/respect/divisible_by_validator.rb +20 -0
  17. data/lib/respect/doc_helper.rb +24 -0
  18. data/lib/respect/doc_parser.rb +37 -0
  19. data/lib/respect/dsl_dumper.rb +181 -0
  20. data/lib/respect/equal_to_validator.rb +20 -0
  21. data/lib/respect/fake_name_proxy.rb +116 -0
  22. data/lib/respect/float_schema.rb +27 -0
  23. data/lib/respect/format_validator.rb +136 -0
  24. data/lib/respect/global_def.rb +79 -0
  25. data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
  26. data/lib/respect/greater_than_validator.rb +19 -0
  27. data/lib/respect/has_constraints.rb +34 -0
  28. data/lib/respect/hash_def.rb +40 -0
  29. data/lib/respect/hash_schema.rb +218 -0
  30. data/lib/respect/in_validator.rb +19 -0
  31. data/lib/respect/integer_schema.rb +27 -0
  32. data/lib/respect/ip_addr_schema.rb +23 -0
  33. data/lib/respect/ipv4_addr_schema.rb +27 -0
  34. data/lib/respect/ipv6_addr_schema.rb +27 -0
  35. data/lib/respect/items_def.rb +21 -0
  36. data/lib/respect/json_schema_html_formatter.rb +143 -0
  37. data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
  38. data/lib/respect/less_than_validator.rb +19 -0
  39. data/lib/respect/match_validator.rb +19 -0
  40. data/lib/respect/max_length_validator.rb +20 -0
  41. data/lib/respect/min_length_validator.rb +20 -0
  42. data/lib/respect/multiple_of_validator.rb +10 -0
  43. data/lib/respect/null_schema.rb +26 -0
  44. data/lib/respect/numeric_schema.rb +33 -0
  45. data/lib/respect/org3_dumper.rb +213 -0
  46. data/lib/respect/regexp_schema.rb +19 -0
  47. data/lib/respect/schema.rb +285 -0
  48. data/lib/respect/schema_def.rb +16 -0
  49. data/lib/respect/string_schema.rb +21 -0
  50. data/lib/respect/unit_test_helper.rb +37 -0
  51. data/lib/respect/uri_schema.rb +23 -0
  52. data/lib/respect/utc_time_schema.rb +17 -0
  53. data/lib/respect/validator.rb +51 -0
  54. data/lib/respect/version.rb +3 -0
  55. data/test/any_schema_test.rb +79 -0
  56. data/test/array_def_test.rb +113 -0
  57. data/test/array_schema_test.rb +487 -0
  58. data/test/boolean_schema_test.rb +89 -0
  59. data/test/composite_schema_test.rb +30 -0
  60. data/test/datetime_schema_test.rb +83 -0
  61. data/test/doc_helper_test.rb +34 -0
  62. data/test/doc_parser_test.rb +109 -0
  63. data/test/dsl_dumper_test.rb +395 -0
  64. data/test/fake_name_proxy_test.rb +138 -0
  65. data/test/float_schema_test.rb +146 -0
  66. data/test/format_validator_test.rb +224 -0
  67. data/test/hash_def_test.rb +126 -0
  68. data/test/hash_schema_test.rb +613 -0
  69. data/test/integer_schema_test.rb +142 -0
  70. data/test/ip_addr_schema_test.rb +78 -0
  71. data/test/ipv4_addr_schema_test.rb +71 -0
  72. data/test/ipv6_addr_schema_test.rb +71 -0
  73. data/test/json_schema_html_formatter_test.rb +214 -0
  74. data/test/null_schema_test.rb +46 -0
  75. data/test/numeric_schema_test.rb +294 -0
  76. data/test/org3_dumper_test.rb +784 -0
  77. data/test/regexp_schema_test.rb +54 -0
  78. data/test/respect_test.rb +108 -0
  79. data/test/schema_def_test.rb +405 -0
  80. data/test/schema_test.rb +290 -0
  81. data/test/string_schema_test.rb +209 -0
  82. data/test/support/circle.rb +11 -0
  83. data/test/support/color.rb +24 -0
  84. data/test/support/point.rb +11 -0
  85. data/test/support/respect/circle_schema.rb +16 -0
  86. data/test/support/respect/color_def.rb +19 -0
  87. data/test/support/respect/color_schema.rb +33 -0
  88. data/test/support/respect/point_schema.rb +19 -0
  89. data/test/support/respect/rgba_schema.rb +20 -0
  90. data/test/support/respect/universal_validator.rb +25 -0
  91. data/test/support/respect/user_macros.rb +12 -0
  92. data/test/support/rgba.rb +11 -0
  93. data/test/test_helper.rb +90 -0
  94. data/test/uri_schema_test.rb +54 -0
  95. data/test/utc_time_schema_test.rb +63 -0
  96. data/test/validator_test.rb +22 -0
  97. metadata +288 -0
@@ -0,0 +1,11 @@
1
+ class Circle
2
+ def initialize(center, radius)
3
+ @center, @radius = center, radius
4
+ end
5
+
6
+ attr_reader :center, :radius
7
+
8
+ def ==(other)
9
+ @center == other.center && @radius == radius
10
+ end
11
+ end
@@ -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,11 @@
1
+ class Point
2
+ def initialize(x, y)
3
+ @x, @y = x, y
4
+ end
5
+
6
+ attr_reader :x, :y
7
+
8
+ def ==(other)
9
+ @x == other.x && @y == other.y
10
+ end
11
+ 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
@@ -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