sinatra-schema 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -1
- data/lib/sinatra/schema.rb +2 -2
- data/lib/sinatra/schema/definition.rb +10 -2
- data/lib/sinatra/schema/dsl/definitions.rb +12 -2
- data/lib/sinatra/schema/dsl/resources.rb +11 -3
- data/lib/sinatra/schema/json_schema.rb +2 -0
- data/lib/sinatra/schema/reference.rb +15 -5
- data/lib/sinatra/schema/resource.rb +8 -2
- data/lib/sinatra/schema/version.rb +1 -1
- data/spec/definition_spec.rb +17 -0
- data/spec/dsl/definitions_spec.rb +12 -0
- data/spec/dsl/resources_spec.rb +5 -0
- data/spec/json_schema_spec.rb +6 -0
- data/spec/reference_spec.rb +6 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68898f14935c5a727937d1eec3921da16fab59fc
|
4
|
+
data.tar.gz: 148c841cfeb602cb252d13827a621938997b9298
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a43e4d2e18ee81dbb18467881a402782953aa54937cd6dfb6a28c61e54822f63b24d876df3645af58b57fb747ea2bc361b7a448b4eb92ebf733eb5725428563
|
7
|
+
data.tar.gz: 8c2e3ea36d035a7c82dd01f26c62eaae3cefd779bdf0c5e8d861e7b5a909635354b515255af1baaf5213182d84916f7292c5b67f692aae400ef34c8d0d13d50c
|
data/README.md
CHANGED
@@ -58,10 +58,24 @@ end
|
|
58
58
|
|
59
59
|
resource("/albums") do |res|
|
60
60
|
res.property.text :name, description: "Album name"
|
61
|
-
res.property.ref :artist_name, "artists/name"
|
61
|
+
res.property.ref :artist_name, to: "artists/name"
|
62
62
|
end
|
63
63
|
```
|
64
64
|
|
65
|
+
You can also customize attributes on the reference so that they're different from the original property. For instance:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
resource("/artists") do |res|
|
69
|
+
res.property.text :name, description: "Artist name"
|
70
|
+
|
71
|
+
res.patch do |link|
|
72
|
+
link.property.ref :name, optional: true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
In this case the artist name has to be serialized by every endpoint on the resource, but doesn't have to be informed by every request to `PATCH` the resource.
|
78
|
+
|
65
79
|
### Nested properties
|
66
80
|
|
67
81
|
These are also casted and validated as you'd expect:
|
data/lib/sinatra/schema.rb
CHANGED
@@ -22,11 +22,15 @@ module Sinatra
|
|
22
22
|
Time.parse(value.to_s)
|
23
23
|
when "email", "string", "uuid"
|
24
24
|
value.to_s
|
25
|
+
when "integer"
|
26
|
+
value.to_i
|
27
|
+
when "object"
|
28
|
+
value
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
|
-
def valid?(value)
|
29
|
-
return true if value.nil? &&
|
32
|
+
def valid?(value, skip_nils=optional)
|
33
|
+
return true if value.nil? && skip_nils
|
30
34
|
|
31
35
|
case type
|
32
36
|
when "boolean"
|
@@ -35,6 +39,10 @@ module Sinatra
|
|
35
39
|
value.to_s =~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\.[0-9]+)?(Z|[\-+][0-9]{2}:[0-5][0-9])$/
|
36
40
|
when "email"
|
37
41
|
value.to_s =~ /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
|
42
|
+
when "integer"
|
43
|
+
value.to_s =~ /\A\d*\z/
|
44
|
+
when "object"
|
45
|
+
value.is_a?(Hash)
|
38
46
|
when "string"
|
39
47
|
value.is_a?(String)
|
40
48
|
when "uuid"
|
@@ -25,9 +25,19 @@ module Sinatra
|
|
25
25
|
add Definition.new(options)
|
26
26
|
end
|
27
27
|
|
28
|
+
def int(id, options={})
|
29
|
+
options.merge!(id: id, type: "integer")
|
30
|
+
add Definition.new(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def object(id, options={})
|
34
|
+
options.merge!(id: id, type: "object")
|
35
|
+
add Definition.new(options)
|
36
|
+
end
|
37
|
+
|
28
38
|
# support references to other properties that are lazily evaluated
|
29
|
-
def ref(id,
|
30
|
-
add Reference.new(resource, id,
|
39
|
+
def ref(id, options={})
|
40
|
+
add Reference.new(resource, id, options)
|
31
41
|
end
|
32
42
|
|
33
43
|
def text(id, options={})
|
@@ -4,9 +4,13 @@ module Sinatra
|
|
4
4
|
class Resources
|
5
5
|
attr_accessor :app, :resource
|
6
6
|
|
7
|
-
def initialize(app,
|
8
|
-
@app
|
9
|
-
|
7
|
+
def initialize(app, path_or_id)
|
8
|
+
@app = app
|
9
|
+
if path_or_id.is_a?(Symbol)
|
10
|
+
@resource = Resource.new(id: path_or_id)
|
11
|
+
else
|
12
|
+
@resource = Resource.new(path: path_or_id)
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
def description(description)
|
@@ -17,6 +21,10 @@ module Sinatra
|
|
17
21
|
@resource.id = id.to_sym
|
18
22
|
end
|
19
23
|
|
24
|
+
def title(title)
|
25
|
+
@resource.title = title
|
26
|
+
end
|
27
|
+
|
20
28
|
def property
|
21
29
|
DSL::Definitions.new(resource, [resource.defs, resource.properties])
|
22
30
|
end
|
@@ -1,20 +1,25 @@
|
|
1
1
|
module Sinatra
|
2
2
|
module Schema
|
3
3
|
class Reference
|
4
|
-
attr_accessor :id, :ref_spec, :referenced_def, :resource
|
4
|
+
attr_accessor :id, :options, :ref_spec, :referenced_def, :resource
|
5
5
|
|
6
6
|
# helper to lazily delegate method to the referenced definition
|
7
7
|
def self.delegate(attribute)
|
8
8
|
define_method(attribute) do |*args|
|
9
|
+
# support overriding attributes. example: referenced
|
10
|
+
# definition is optional, but parameter is not
|
11
|
+
return options[attribute] if options.has_key?(attribute)
|
12
|
+
|
9
13
|
resolve!
|
10
14
|
referenced_def.send(attribute, *args)
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
14
|
-
def initialize(resource, id,
|
15
|
-
@id = id
|
16
|
-
@ref_spec = ref_spec || id
|
18
|
+
def initialize(resource, id, options={})
|
17
19
|
@resource = resource
|
20
|
+
@id = id
|
21
|
+
@ref_spec = options[:to] || id
|
22
|
+
@options = options
|
18
23
|
end
|
19
24
|
|
20
25
|
def resolve!
|
@@ -30,7 +35,12 @@ module Sinatra
|
|
30
35
|
delegate :example
|
31
36
|
delegate :optional
|
32
37
|
delegate :type
|
33
|
-
|
38
|
+
|
39
|
+
# redefine to make sure overrides on "optional" are considered
|
40
|
+
def valid?(value)
|
41
|
+
resolve!
|
42
|
+
referenced_def.valid?(value, self.optional)
|
43
|
+
end
|
34
44
|
end
|
35
45
|
end
|
36
46
|
end
|
@@ -4,7 +4,8 @@ module Sinatra
|
|
4
4
|
attr_accessor :id, :path, :title, :defs, :links, :description, :properties
|
5
5
|
|
6
6
|
def initialize(options)
|
7
|
-
@
|
7
|
+
@id = options[:id]
|
8
|
+
@path = (options[:path] || "").chomp("/")
|
8
9
|
@links = []
|
9
10
|
@defs = {}
|
10
11
|
@properties = {}
|
@@ -40,7 +41,12 @@ module Sinatra
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def validate_properties!(received)
|
43
|
-
|
44
|
+
required_properties = properties.map do |k, prop|
|
45
|
+
# ignore nested properties for now, we'll cover these next
|
46
|
+
k unless prop.is_a?(Hash) || prop.optional
|
47
|
+
end.compact
|
48
|
+
|
49
|
+
missing = required_properties.map(&:to_s).sort - received.keys.map(&:to_s).sort
|
44
50
|
unless missing.empty?
|
45
51
|
raise BadResponse.new("Missing properties: #{missing}")
|
46
52
|
end
|
data/spec/definition_spec.rb
CHANGED
@@ -26,6 +26,11 @@ describe Sinatra::Schema::Definition do
|
|
26
26
|
assert_equal "UTC", t.zone
|
27
27
|
end
|
28
28
|
|
29
|
+
it "casts integers" do
|
30
|
+
definition.type = "integer"
|
31
|
+
assert_equal 42, definition.cast("42")
|
32
|
+
end
|
33
|
+
|
29
34
|
it "casts text" do
|
30
35
|
definition.type = "string"
|
31
36
|
assert_equal "123", definition.cast(123)
|
@@ -46,6 +51,18 @@ describe Sinatra::Schema::Definition do
|
|
46
51
|
refute definition.valid?("foobar.com")
|
47
52
|
end
|
48
53
|
|
54
|
+
it "validates integers" do
|
55
|
+
definition.type = "integer"
|
56
|
+
assert definition.valid?(42)
|
57
|
+
refute definition.valid?("42omg")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "validates objects" do
|
61
|
+
definition.type = "object"
|
62
|
+
assert definition.valid?(good: true)
|
63
|
+
refute definition.valid?("bad")
|
64
|
+
end
|
65
|
+
|
49
66
|
it "validates text" do
|
50
67
|
definition.type = "string"
|
51
68
|
assert definition.valid?("foo")
|
@@ -23,6 +23,18 @@ describe Sinatra::Schema::DSL::Definitions do
|
|
23
23
|
assert_equal "email", resource.defs[:foobar].type
|
24
24
|
end
|
25
25
|
|
26
|
+
it "adds integer definition to the resource" do
|
27
|
+
dsl.int(:foobar)
|
28
|
+
assert_equal 1, resource.defs.size
|
29
|
+
assert_equal "integer", resource.defs[:foobar].type
|
30
|
+
end
|
31
|
+
|
32
|
+
it "adds object definition to the resource" do
|
33
|
+
dsl.object(:foobar)
|
34
|
+
assert_equal 1, resource.defs.size
|
35
|
+
assert_equal "object", resource.defs[:foobar].type
|
36
|
+
end
|
37
|
+
|
26
38
|
it "adds references" do
|
27
39
|
dsl.ref(:another_property)
|
28
40
|
assert_equal 1, resource.defs.size
|
data/spec/dsl/resources_spec.rb
CHANGED
@@ -9,6 +9,11 @@ describe Sinatra::Schema::DSL::Resources do
|
|
9
9
|
assert_equal "This is a foobar", dsl.resource.description
|
10
10
|
end
|
11
11
|
|
12
|
+
it "sets the resource title" do
|
13
|
+
dsl.title("Foobar")
|
14
|
+
assert_equal "Foobar", dsl.resource.title
|
15
|
+
end
|
16
|
+
|
12
17
|
it "sets the id casting to symbol" do
|
13
18
|
dsl.id("account")
|
14
19
|
assert_equal :account, dsl.resource.id
|
data/spec/json_schema_spec.rb
CHANGED
@@ -40,6 +40,12 @@ describe Sinatra::Schema::JsonSchema do
|
|
40
40
|
assert_equal "email", schema[:format]
|
41
41
|
end
|
42
42
|
|
43
|
+
it "handles the integer format" do
|
44
|
+
definition.type = "integer"
|
45
|
+
schema = json_schema.dump_definition(definition)
|
46
|
+
assert_equal "integer", schema[:type]
|
47
|
+
end
|
48
|
+
|
43
49
|
it "handles the uuid format" do
|
44
50
|
definition.type = "uuid"
|
45
51
|
schema = json_schema.dump_definition(definition)
|
data/spec/reference_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Sinatra::Schema::Reference do
|
4
4
|
let(:resource) { Sinatra::Schema::Root.instance.resources[:accounts] }
|
5
|
-
let(:ref) { described_class.new(resource, :
|
5
|
+
let(:ref) { described_class.new(resource, :email) }
|
6
6
|
let(:definition) { resource.defs[:email] }
|
7
7
|
|
8
8
|
describe "#resolve!" do
|
@@ -49,5 +49,10 @@ describe Sinatra::Schema::Reference do
|
|
49
49
|
it "#valid?" do
|
50
50
|
assert_equal definition.valid?("foo"), ref.valid?("foo")
|
51
51
|
end
|
52
|
+
|
53
|
+
it "supports overriding delegated methods" do
|
54
|
+
ref.options[:description] = "diff"
|
55
|
+
assert_equal "diff", ref.description
|
56
|
+
end
|
52
57
|
end
|
53
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Belo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|