explicit 0.2.0 → 0.2.2

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +76 -68
  3. data/app/helpers/explicit/application_helper.rb +32 -0
  4. data/app/views/explicit/documentation/_attribute.html.erb +38 -0
  5. data/app/views/explicit/documentation/_page.html.erb +166 -0
  6. data/app/views/explicit/documentation/_request.html.erb +87 -0
  7. data/app/views/explicit/documentation/request/_examples.html.erb +50 -0
  8. data/app/views/explicit/documentation/type/_agreement.html.erb +7 -0
  9. data/app/views/explicit/documentation/type/_array.html.erb +3 -0
  10. data/app/views/explicit/documentation/type/_big_decimal.html.erb +4 -0
  11. data/app/views/explicit/documentation/type/_boolean.html.erb +7 -0
  12. data/app/views/explicit/documentation/type/_date_time_iso8601.html.erb +3 -0
  13. data/app/views/explicit/documentation/type/_date_time_posix.html.erb +3 -0
  14. data/app/views/explicit/documentation/type/_enum.html.erb +7 -0
  15. data/app/views/explicit/documentation/type/_file.html.erb +9 -0
  16. data/app/views/explicit/documentation/type/_hash.html.erb +4 -0
  17. data/app/views/explicit/documentation/type/_integer.html.erb +25 -0
  18. data/app/views/explicit/documentation/type/_one_of.html.erb +11 -0
  19. data/app/views/explicit/documentation/type/_record.html.erb +9 -0
  20. data/app/views/explicit/documentation/type/_string.html.erb +21 -0
  21. data/config/locales/en.yml +27 -11
  22. data/lib/explicit/configuration.rb +1 -1
  23. data/lib/explicit/documentation/builder.rb +80 -0
  24. data/lib/explicit/documentation/markdown.rb +2 -13
  25. data/lib/explicit/documentation/output/swagger.rb +176 -0
  26. data/lib/explicit/documentation/output/webpage.rb +31 -0
  27. data/lib/explicit/documentation/page/partial.rb +20 -0
  28. data/lib/explicit/documentation/page/request.rb +27 -0
  29. data/lib/explicit/documentation/section.rb +9 -0
  30. data/lib/explicit/documentation.rb +12 -145
  31. data/lib/explicit/request/example.rb +50 -1
  32. data/lib/explicit/request/invalid_params_error.rb +1 -3
  33. data/lib/explicit/request/invalid_response_error.rb +2 -15
  34. data/lib/explicit/request/route.rb +18 -0
  35. data/lib/explicit/request.rb +43 -24
  36. data/lib/explicit/test_helper/example_recorder.rb +7 -2
  37. data/lib/explicit/test_helper.rb +25 -7
  38. data/lib/explicit/type/agreement.rb +39 -0
  39. data/lib/explicit/type/array.rb +56 -0
  40. data/lib/explicit/type/big_decimal.rb +58 -0
  41. data/lib/explicit/type/boolean.rb +47 -0
  42. data/lib/explicit/type/date_time_iso8601.rb +41 -0
  43. data/lib/explicit/type/date_time_posix.rb +44 -0
  44. data/lib/explicit/type/enum.rb +41 -0
  45. data/lib/explicit/type/file.rb +60 -0
  46. data/lib/explicit/type/hash.rb +57 -0
  47. data/lib/explicit/type/integer.rb +79 -0
  48. data/lib/explicit/type/literal.rb +45 -0
  49. data/lib/explicit/type/modifiers/default.rb +24 -0
  50. data/lib/explicit/type/modifiers/description.rb +11 -0
  51. data/lib/explicit/type/modifiers/nilable.rb +19 -0
  52. data/lib/explicit/type/modifiers/param_location.rb +11 -0
  53. data/lib/explicit/type/one_of.rb +46 -0
  54. data/lib/explicit/type/record.rb +96 -0
  55. data/lib/explicit/type/string.rb +68 -0
  56. data/lib/explicit/type.rb +112 -0
  57. data/lib/explicit/version.rb +1 -1
  58. data/lib/explicit.rb +28 -18
  59. metadata +47 -25
  60. data/app/views/explicit/application/_documentation.html.erb +0 -136
  61. data/app/views/explicit/application/_request.html.erb +0 -37
  62. data/lib/explicit/documentation/property.rb +0 -19
  63. data/lib/explicit/spec/agreement.rb +0 -17
  64. data/lib/explicit/spec/array.rb +0 -28
  65. data/lib/explicit/spec/bigdecimal.rb +0 -27
  66. data/lib/explicit/spec/boolean.rb +0 -30
  67. data/lib/explicit/spec/date_time_iso8601.rb +0 -17
  68. data/lib/explicit/spec/date_time_posix.rb +0 -21
  69. data/lib/explicit/spec/default.rb +0 -20
  70. data/lib/explicit/spec/error.rb +0 -63
  71. data/lib/explicit/spec/hash.rb +0 -30
  72. data/lib/explicit/spec/inclusion.rb +0 -15
  73. data/lib/explicit/spec/integer.rb +0 -53
  74. data/lib/explicit/spec/literal.rb +0 -15
  75. data/lib/explicit/spec/nilable.rb +0 -15
  76. data/lib/explicit/spec/one_of.rb +0 -40
  77. data/lib/explicit/spec/record.rb +0 -33
  78. data/lib/explicit/spec/string.rb +0 -50
  79. data/lib/explicit/spec.rb +0 -72
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "time"
4
-
5
- module Explicit::Spec::DateTimePosix
6
- extend self
7
-
8
- ERROR_INVALID = [:error, :date_time_posix].freeze
9
-
10
- def call(value)
11
- if !value.is_a?(::Integer) && !value.is_a?(::String)
12
- return ERROR_INVALID
13
- end
14
-
15
- datetimeval = DateTime.strptime(value.to_s, "%s")
16
-
17
- [:ok, datetimeval]
18
- rescue Date::Error
19
- ERROR_INVALID
20
- end
21
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Default
4
- extend self
5
-
6
- def build(defaultval, subspec)
7
- subspec_validator = Explicit::Spec::build(subspec)
8
-
9
- lambda do |value|
10
- value =
11
- if value.nil?
12
- defaultval.respond_to?(:call) ? defaultval.call : defaultval
13
- else
14
- value
15
- end
16
-
17
- subspec_validator.call(value)
18
- end
19
- end
20
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Error
4
- extend self
5
-
6
- RailsI18n = ->(error, **context) do
7
- key = "explicit.errors.#{error}"
8
-
9
- ::I18n.t(key, **context)
10
- end
11
-
12
- def translate(error, translator = RailsI18n)
13
- case error
14
- in :agreement
15
- translator.call(:agreement)
16
- in [:array, index, suberr]
17
- translator.call(:array, index:, error: translate(suberr, translator))
18
- in :bigdecimal
19
- translator.call(:bigdecimal)
20
- in :boolean
21
- translator.call(:boolean)
22
- in :date_time_iso8601
23
- translator.call(:date_time_iso8601)
24
- in :date_time_posix
25
- translator.call(:date_time_posix)
26
- in :hash
27
- translator.call(:hash)
28
- in [:hash_key, key, suberr]
29
- translator.call(:hash_key, key:, error: translate(suberr, translator))
30
- in [:hash_value, key, suberr]
31
- translator.call(:hash_value, key:, error: translate(suberr, translator))
32
- in [:inclusion, values]
33
- translator.call(:inclusion, values: values.inspect)
34
- in :integer
35
- translator.call(:integer)
36
- in [:min, min]
37
- translator.call(:min, min:)
38
- in [:max, max]
39
- translator.call(:max, max:)
40
- in :negative
41
- translator.call(:negative)
42
- in :positive
43
- translator.call(:positive)
44
- in [:literal, value]
45
- translator.call(:literal, value: value.inspect)
46
- in [:one_of, *errors]
47
- # TODO
48
- errors.map { translate(_1, translator) }.join(" OR ")
49
- in :string
50
- translator.call(:string)
51
- in :empty
52
- translator.call(:empty)
53
- in [:minlength, minlength]
54
- translator.call(:minlength, minlength:)
55
- in [:maxlength, maxlength]
56
- translator.call(:maxlength, maxlength:)
57
- in [:format, regex]
58
- translator.call(:format, regex: regex.inspect)
59
- in Hash
60
- error.to_h { |attr_name, err| [attr_name, translate(err, translator)] }
61
- end
62
- end
63
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Hash
4
- extend self
5
-
6
- def build(keyspec, valuespec, options)
7
- keyspec_validator = Explicit::Spec.build(keyspec)
8
- valuespec_validator = Explicit::Spec.build(valuespec)
9
-
10
- lambda do |value|
11
- return [:error, :hash] if !value.is_a?(::Hash)
12
- return [:error, :empty] if value.empty? && !options[:empty]
13
-
14
- validated_hash = {}
15
-
16
- value.each do |key, value|
17
- case [keyspec_validator.call(key), valuespec_validator.call(value)]
18
- in [[:ok, validated_key], [:ok, validated_value]]
19
- validated_hash[validated_key] = validated_value
20
- in [[:error, err], _]
21
- return [:error, [:hash_key, key, err]]
22
- in [_, [:error, err]]
23
- return [:error, [:hash_value, key, err]]
24
- end
25
- end
26
-
27
- [:ok, validated_hash]
28
- end
29
- end
30
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Inclusion
4
- extend self
5
-
6
- def build(values)
7
- lambda do |value|
8
- if values.include?(value)
9
- [:ok, value]
10
- else
11
- [:error, [:inclusion, values]]
12
- end
13
- end
14
- end
15
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Integer
4
- extend self
5
-
6
- def build(options)
7
- lambda do |value|
8
- value =
9
- if value.is_a?(::Integer)
10
- value
11
- elsif value.is_a?(::String) && options[:parse]
12
- parse_from_string(value)
13
- else
14
- nil
15
- end
16
-
17
- return [:error, :integer] if value.nil?
18
-
19
- if (min = options[:min]) && !validate_min(value, min)
20
- return [:error, [:min, min]]
21
- end
22
-
23
- if (max = options[:max]) && !validate_max(value, max)
24
- return [:error, [:max, max]]
25
- end
26
-
27
- if options[:negative] == false && value < 0
28
- return [:error, :negative]
29
- end
30
-
31
- if options[:positive] == false && value > 0
32
- return [:error, :positive]
33
- end
34
-
35
- [:ok, value]
36
- end
37
- end
38
-
39
- private
40
- def parse_from_string(value)
41
- Integer(value)
42
- rescue ::ArgumentError
43
- nil
44
- end
45
-
46
- def validate_min(value, min)
47
- value >= min
48
- end
49
-
50
- def validate_max(value, max)
51
- value <= max
52
- end
53
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Literal
4
- extend self
5
-
6
- def build(literal_value)
7
- lambda do |value|
8
- if value == literal_value
9
- [:ok, value]
10
- else
11
- [:error, [:literal, literal_value]]
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Nilable
4
- extend self
5
-
6
- def build(subspec)
7
- subspec_validator = Explicit::Spec.build(subspec)
8
-
9
- lambda do |value|
10
- return [:ok, nil] if value.nil?
11
-
12
- subspec_validator.call(value)
13
- end
14
- end
15
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::OneOf
4
- extend self
5
-
6
- def build(subspecs)
7
- subspec_validators = subspecs.map { Explicit::Spec.build(_1) }
8
-
9
- errors = []
10
-
11
- lambda do |value|
12
- subspec_validators.each do |subspec_validator|
13
- case subspec_validator.call(value)
14
- in [:ok, validated_value]
15
- return [:ok, validated_value]
16
- in [:error, err]
17
- errors << err
18
- end
19
- end
20
-
21
- errors.each do |err|
22
- if looks_like_at_least_one_attribute_matched?(value, err)
23
- return [:error, err]
24
- end
25
- end
26
-
27
- [:error, [:one_of, *errors]]
28
- end
29
- end
30
-
31
- private
32
- def looks_like_at_least_one_attribute_matched?(value, err)
33
- return false if !value.is_a?(::Hash)
34
- return false if !err.is_a?(::Hash)
35
-
36
- keyset = value.keys - err.keys
37
-
38
- keyset.empty?
39
- end
40
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::Record
4
- extend self
5
-
6
- def build(attributes)
7
- attributes_validators = attributes.map do |attribute_name, attribute_spec|
8
- [attribute_name, Explicit::Spec.build(attribute_spec)]
9
- end
10
-
11
- lambda do |data|
12
- return [:error, :hash] if !data.respond_to?(:[])
13
-
14
- validated_data = {}
15
- errors = {}
16
-
17
- attributes_validators.each do |attribute_name, attribute_validator|
18
- value = data[attribute_name]
19
-
20
- case attribute_validator.call(value)
21
- in [:ok, validated_value]
22
- validated_data[attribute_name] = validated_value
23
- in [:error, err]
24
- errors[attribute_name] = err
25
- end
26
- end
27
-
28
- return [:error, errors] if errors.any?
29
-
30
- [:ok, validated_data]
31
- end
32
- end
33
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec::String
4
- extend self
5
-
6
- def build(options)
7
- lambda do |value|
8
- return [:error, :string] if !value.is_a?(::String)
9
-
10
- value = value.strip if options[:strip]
11
-
12
- if options.key?(:empty) && !validate_empty(value, options[:empty])
13
- return [:error, :empty]
14
- end
15
-
16
- if (minlength = options[:minlength]) && !validate_minlength(value, minlength)
17
- return [:error, [:minlength, minlength:]]
18
- end
19
-
20
- if (maxlength = options[:maxlength]) && !validate_maxlength(value, maxlength)
21
- return [:error, [:maxlength, maxlength:]]
22
- end
23
-
24
- if (format = options[:format]) && !validate_format(value, format)
25
- return [:error, [:format, format]]
26
- end
27
-
28
- [:ok, value]
29
- end
30
- end
31
-
32
- private
33
- def validate_empty(value, allow_empty)
34
- return true if allow_empty
35
-
36
- !value.empty?
37
- end
38
-
39
- def validate_minlength(value, minlength)
40
- value.length >= minlength
41
- end
42
-
43
- def validate_maxlength(value, maxlength)
44
- value.length <= maxlength
45
- end
46
-
47
- def validate_format(value, format)
48
- format.match?(value)
49
- end
50
- end
data/lib/explicit/spec.rb DELETED
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Explicit::Spec
4
- extend self
5
-
6
- def build(spec)
7
- case spec
8
- in :agreement
9
- Explicit::Spec::Agreement.build({})
10
- in [:agreement, options]
11
- Explicit::Spec::Agreement.build(options)
12
-
13
- in [:array, itemspec]
14
- Explicit::Spec::Array.build(itemspec, {})
15
- in [:array, itemspec, options]
16
- Explicit::Spec::Array.build(itemspec, options)
17
-
18
- in :bigdecimal
19
- Explicit::Spec::Bigdecimal.build({})
20
- in [:bigdecimal, options]
21
- Explicit::Spec::Bigdecimal.build(options)
22
-
23
- in :boolean
24
- Explicit::Spec::Boolean.build({})
25
- in [:boolean, options]
26
- Explicit::Spec::Boolean.build(options)
27
-
28
- in :date_time_iso8601
29
- Explicit::Spec::DateTimeISO8601
30
- in :date_time_posix
31
- Explicit::Spec::DateTimePosix
32
-
33
- in [:default, defaultval, subspec]
34
- Explicit::Spec::Default.build(defaultval, subspec)
35
-
36
- in [:description, _, subspec]
37
- Explicit::Spec.build(subspec)
38
-
39
- in [:hash, keyspec, valuespec]
40
- Explicit::Spec::Hash.build(keyspec, valuespec, {})
41
- in [:hash, keyspec, valuespec, options]
42
- Explicit::Spec::Hash.build(keyspec, valuespec, options)
43
-
44
- in [:inclusion, options]
45
- Explicit::Spec::Inclusion.build(options)
46
-
47
- in :integer
48
- Explicit::Spec::Integer.build({})
49
- in [:integer, options]
50
- Explicit::Spec::Integer.build(options)
51
-
52
- in [:literal, value]
53
- Explicit::Spec::Literal.build(value)
54
- in ::String
55
- Explicit::Spec::Literal.build(spec)
56
-
57
- in [:nilable, options]
58
- Explicit::Spec::Nilable.build(options)
59
-
60
- in [:one_of, *subspecs]
61
- Explicit::Spec::OneOf.build(subspecs)
62
-
63
- in :string
64
- Explicit::Spec::String.build({})
65
- in [:string, options]
66
- Explicit::Spec::String.build(options)
67
-
68
- in ::Hash
69
- Explicit::Spec::Record.build(spec)
70
- end
71
- end
72
- end