sinatra-schema 0.0.5 → 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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/sinatra/schema.rb +4 -1
- data/lib/sinatra/schema/definition.rb +4 -27
- data/lib/sinatra/schema/dsl/definitions.rb +9 -13
- data/lib/sinatra/schema/dsl/resources.rb +28 -5
- data/lib/sinatra/schema/json_schema.rb +73 -0
- data/lib/sinatra/schema/link.rb +2 -10
- data/lib/sinatra/schema/reference.rb +36 -0
- data/lib/sinatra/schema/resource.rb +0 -13
- data/lib/sinatra/schema/root.rb +0 -10
- data/lib/sinatra/schema/version.rb +1 -1
- data/spec/definition_spec.rb +21 -18
- data/spec/dsl/definitions_spec.rb +12 -35
- data/spec/dsl/resources_spec.rb +28 -1
- data/spec/integration_spec.rb +46 -15
- data/spec/json_schema_spec.rb +50 -20
- data/spec/reference_spec.rb +53 -0
- data/spec/support/test_app.rb +2 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ed53578697a31d2928747c5e315a6bf74e3a5b1
|
4
|
+
data.tar.gz: 1c8fabb80b8ee50d14186838d1a29f53d4bc039b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3a1e7c20a2737d577391748a479bddb1761183777c4797cf6dfc6009076c4caec7dc408aa174eaab7f382d34abc839f49a01728d99e2753e88e5a42c2c668ec
|
7
|
+
data.tar.gz: 7e12db3a44fe1ee3574f5feb3d9fa47c676820d24587a9f85e5d391b7678574288460bd2cef166d6c26055701f147d43fceef2acc5a4ae491f12594af1cf11dd
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ class MyApi < Sinatra::Base
|
|
17
17
|
resource("/account") do |res|
|
18
18
|
res.property.text :email
|
19
19
|
|
20
|
-
res.
|
20
|
+
res.get do |link|
|
21
21
|
link.action do
|
22
22
|
# note per definition above we need to serialize "email"
|
23
23
|
MultiJson.encode(email: current_user.email)
|
@@ -35,7 +35,7 @@ Links can have properties too:
|
|
35
35
|
resource("/account") do |res|
|
36
36
|
res.property.text :email
|
37
37
|
|
38
|
-
res.
|
38
|
+
res.post do |link|
|
39
39
|
link.property.ref :email # reuse the property defined above
|
40
40
|
link.property.text :role, optional: true
|
41
41
|
link.property.bool :admin
|
data/lib/sinatra/schema.rb
CHANGED
@@ -2,12 +2,15 @@ require "active_support/inflector"
|
|
2
2
|
require "sinatra/base"
|
3
3
|
require "singleton"
|
4
4
|
require "multi_json"
|
5
|
+
require "time"
|
5
6
|
|
6
7
|
require "sinatra/schema/definition"
|
7
8
|
require "sinatra/schema/error"
|
9
|
+
require "sinatra/schema/json_schema"
|
8
10
|
require "sinatra/schema/link"
|
9
11
|
require "sinatra/schema/param_parsing"
|
10
12
|
require "sinatra/schema/param_validation"
|
13
|
+
require "sinatra/schema/reference"
|
11
14
|
require "sinatra/schema/resource"
|
12
15
|
require "sinatra/schema/root"
|
13
16
|
require "sinatra/schema/utils"
|
@@ -32,7 +35,7 @@ module Sinatra
|
|
32
35
|
app.get "/schema" do
|
33
36
|
content_type("application/schema+json")
|
34
37
|
response.headers["Cache-Control"] = "public, max-age=3600"
|
35
|
-
MultiJson.encode(app.schema_root
|
38
|
+
MultiJson.encode(JsonSchema.dump(app.schema_root), pretty: true)
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
@@ -18,6 +18,8 @@ module Sinatra
|
|
18
18
|
case type
|
19
19
|
when "boolean"
|
20
20
|
%w( t true 1 ).include?(value.to_s)
|
21
|
+
when "datetime"
|
22
|
+
Time.parse(value.to_s)
|
21
23
|
when "email", "string", "uuid"
|
22
24
|
value.to_s
|
23
25
|
end
|
@@ -29,6 +31,8 @@ module Sinatra
|
|
29
31
|
case type
|
30
32
|
when "boolean"
|
31
33
|
[true, false].include?(value)
|
34
|
+
when "datetime"
|
35
|
+
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])$/
|
32
36
|
when "email"
|
33
37
|
value.to_s =~ /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
|
34
38
|
when "string"
|
@@ -37,33 +41,6 @@ module Sinatra
|
|
37
41
|
value.to_s =~ /\A[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}\Z/
|
38
42
|
end
|
39
43
|
end
|
40
|
-
|
41
|
-
def to_schema
|
42
|
-
schema_type, schema_format = json_schema_type_and_format
|
43
|
-
attrs = { type: schema_type }
|
44
|
-
if schema_format
|
45
|
-
attrs[:format] = schema_format
|
46
|
-
end
|
47
|
-
if description
|
48
|
-
attrs[:description] = description
|
49
|
-
end
|
50
|
-
attrs
|
51
|
-
end
|
52
|
-
|
53
|
-
protected
|
54
|
-
|
55
|
-
def json_schema_type_and_format
|
56
|
-
case type
|
57
|
-
when "boolean"
|
58
|
-
"boolean"
|
59
|
-
when "email"
|
60
|
-
["string", "email"]
|
61
|
-
when "string"
|
62
|
-
"string"
|
63
|
-
when "uuid"
|
64
|
-
["string", "uuid"]
|
65
|
-
end
|
66
|
-
end
|
67
44
|
end
|
68
45
|
end
|
69
46
|
end
|
@@ -25,6 +25,11 @@ module Sinatra
|
|
25
25
|
add Definition.new(options)
|
26
26
|
end
|
27
27
|
|
28
|
+
def datetime(id, options={})
|
29
|
+
options.merge!(id: id, type: "datetime")
|
30
|
+
add Definition.new(options)
|
31
|
+
end
|
32
|
+
|
28
33
|
def email(id, options={})
|
29
34
|
options.merge!(id: id, type: "email")
|
30
35
|
add Definition.new(options)
|
@@ -40,25 +45,16 @@ module Sinatra
|
|
40
45
|
end
|
41
46
|
|
42
47
|
def ref(id, ref_to=nil)
|
43
|
-
|
44
|
-
unless definition = resource.defs[ref_to] || Sinatra::Schema::Root.instance.find_definition(ref_to)
|
45
|
-
raise BadReference.new(id)
|
46
|
-
end
|
47
|
-
add definition, true, id
|
48
|
+
add Reference.new(resource, id, ref_to), true
|
48
49
|
end
|
49
50
|
|
50
51
|
# TODO support other types
|
51
52
|
|
52
53
|
protected
|
53
54
|
|
54
|
-
def add(definition, reference=false
|
55
|
-
|
56
|
-
|
57
|
-
# here's the trick, and here's why the first target is always the
|
58
|
-
# resource def: skip it when adding a reference (eg: it's already)
|
59
|
-
# in the resource def, just add the property!
|
60
|
-
next if reference && i == 0
|
61
|
-
hash[id] = definition
|
55
|
+
def add(definition, reference=false)
|
56
|
+
targets.each do |target|
|
57
|
+
target[definition.id] ||= definition
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
@@ -17,12 +17,35 @@ module Sinatra
|
|
17
17
|
DSL::Definitions.new(resource, [resource.defs, resource.properties])
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def delete(href="/", &blk)
|
21
|
+
build_link(:delete, href, &blk)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get(href="/", &blk)
|
25
|
+
build_link(:get, href, &blk)
|
26
|
+
end
|
27
|
+
|
28
|
+
def patch(href="/", &blk)
|
29
|
+
build_link(:patch, href, &blk)
|
30
|
+
end
|
31
|
+
|
32
|
+
def post(href="/", &blk)
|
33
|
+
build_link(:post, href, &blk)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(href="/", &blk)
|
37
|
+
build_link(:put, href, &blk)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def build_link(method, href="/", &blk)
|
21
43
|
dsl = DSL::Links.new(resource: resource, method: method, href: href)
|
22
|
-
blk.call(dsl)
|
23
|
-
link
|
24
|
-
|
25
|
-
|
44
|
+
blk.call(dsl) if blk
|
45
|
+
dsl.link.tap do |link|
|
46
|
+
link.register(app)
|
47
|
+
resource.links << link
|
48
|
+
end
|
26
49
|
end
|
27
50
|
end
|
28
51
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Schema
|
3
|
+
class JsonSchema
|
4
|
+
attr_accessor :root
|
5
|
+
|
6
|
+
def self.dump(root)
|
7
|
+
new(root).dump_root
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(root)
|
11
|
+
@root = root
|
12
|
+
end
|
13
|
+
|
14
|
+
def dump_root
|
15
|
+
{
|
16
|
+
"$schema" => "http://json-schema.org/draft-04/hyper-schema",
|
17
|
+
"definitions" => root.resources.inject({}) { |result, (id, resource)|
|
18
|
+
result.merge(id => dump_resource(resource))
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def dump_resource(resource)
|
24
|
+
{
|
25
|
+
title: resource.title,
|
26
|
+
description: resource.description,
|
27
|
+
type: "object",
|
28
|
+
definitions: resource.defs.inject({}) { |h, (id, definition)|
|
29
|
+
h.merge(id => dump_definition(definition))
|
30
|
+
},
|
31
|
+
links: resource.links.map { |link| dump_link(link) }
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump_definition(definition)
|
36
|
+
schema_type, schema_format = json_schema_type_and_format(definition.type)
|
37
|
+
attrs = { type: schema_type }
|
38
|
+
if schema_format
|
39
|
+
attrs[:format] = schema_format
|
40
|
+
end
|
41
|
+
if definition.description
|
42
|
+
attrs[:description] = definition.description
|
43
|
+
end
|
44
|
+
attrs
|
45
|
+
end
|
46
|
+
|
47
|
+
def dump_link(link)
|
48
|
+
{
|
49
|
+
description: link.description,
|
50
|
+
href: link.href,
|
51
|
+
method: link.method.to_s.upcase,
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def json_schema_type_and_format(type)
|
58
|
+
case type
|
59
|
+
when "boolean"
|
60
|
+
"boolean"
|
61
|
+
when "datetime"
|
62
|
+
["string", "date-time"]
|
63
|
+
when "email"
|
64
|
+
["string", "email"]
|
65
|
+
when "string"
|
66
|
+
"string"
|
67
|
+
when "uuid"
|
68
|
+
["string", "uuid"]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/sinatra/schema/link.rb
CHANGED
@@ -3,7 +3,7 @@ module Sinatra
|
|
3
3
|
class Link
|
4
4
|
attr_accessor :action_block, :resource, :title, :description, :href, :method, :properties, :rel
|
5
5
|
|
6
|
-
def initialize(options)
|
6
|
+
def initialize(options={})
|
7
7
|
@resource = options[:resource]
|
8
8
|
@method = options[:method]
|
9
9
|
@href = options[:href]
|
@@ -11,7 +11,7 @@ module Sinatra
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def register(app)
|
14
|
-
app.send(method
|
14
|
+
app.send(method, href, &handler)
|
15
15
|
end
|
16
16
|
|
17
17
|
def handler
|
@@ -26,14 +26,6 @@ module Sinatra
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
def to_schema
|
31
|
-
{
|
32
|
-
description: description,
|
33
|
-
href: href,
|
34
|
-
method: method.to_s.upcase,
|
35
|
-
}
|
36
|
-
end
|
37
29
|
end
|
38
30
|
end
|
39
31
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Schema
|
3
|
+
class Reference
|
4
|
+
attr_accessor :id, :ref_spec, :referenced_def, :resource
|
5
|
+
|
6
|
+
# helper to lazily delegate method to the referenced definition
|
7
|
+
def self.delegate(attribute)
|
8
|
+
define_method(attribute) do |*args|
|
9
|
+
resolve!
|
10
|
+
referenced_def.send(attribute, *args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(resource, id, ref_spec=nil)
|
15
|
+
@id = id
|
16
|
+
@ref_spec = ref_spec || id
|
17
|
+
@resource = resource
|
18
|
+
end
|
19
|
+
|
20
|
+
def resolve!
|
21
|
+
return if referenced_def
|
22
|
+
unless @referenced_def = resource.defs[ref_spec] || Sinatra::Schema::Root.instance.find_definition(ref_spec)
|
23
|
+
raise BadReference.new(ref_spec)
|
24
|
+
end
|
25
|
+
return @referenced_def
|
26
|
+
end
|
27
|
+
|
28
|
+
delegate :cast
|
29
|
+
delegate :description
|
30
|
+
delegate :example
|
31
|
+
delegate :optional
|
32
|
+
delegate :type
|
33
|
+
delegate :valid?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -31,19 +31,6 @@ module Sinatra
|
|
31
31
|
Utils.validate_keys!(properties, res)
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
35
|
-
def to_schema
|
36
|
-
{
|
37
|
-
title: title,
|
38
|
-
description: description,
|
39
|
-
type: "object",
|
40
|
-
definitions: defs.inject({}) { |h, (id, definition)|
|
41
|
-
h[id] = definition.to_schema
|
42
|
-
h
|
43
|
-
},
|
44
|
-
links: links.map(&:to_schema)
|
45
|
-
}
|
46
|
-
end
|
47
34
|
end
|
48
35
|
end
|
49
36
|
end
|
data/lib/sinatra/schema/root.rb
CHANGED
@@ -18,16 +18,6 @@ module Sinatra
|
|
18
18
|
return unless resource = resources[resource_id.to_sym]
|
19
19
|
resource.defs[def_id.to_sym]
|
20
20
|
end
|
21
|
-
|
22
|
-
def to_schema
|
23
|
-
{
|
24
|
-
"$schema" => "http://json-schema.org/draft-04/hyper-schema",
|
25
|
-
"definitions" => resources.inject({}) { |result, (id, resource)|
|
26
|
-
result[id] = resource.to_schema
|
27
|
-
result
|
28
|
-
}
|
29
|
-
}
|
30
|
-
end
|
31
21
|
end
|
32
22
|
end
|
33
23
|
end
|
data/spec/definition_spec.rb
CHANGED
@@ -13,6 +13,19 @@ describe Sinatra::Schema::Definition do
|
|
13
13
|
assert_equal false, definition.cast("false")
|
14
14
|
end
|
15
15
|
|
16
|
+
it "casts datetime" do
|
17
|
+
definition.type = "datetime"
|
18
|
+
t = definition.cast("2014-05-01T12:13:14.15Z")
|
19
|
+
assert_equal 2014, t.year
|
20
|
+
assert_equal 5, t.month
|
21
|
+
assert_equal 1, t.day
|
22
|
+
assert_equal 12, t.hour
|
23
|
+
assert_equal 13, t.min
|
24
|
+
assert_equal 14, t.sec
|
25
|
+
assert_equal 150000, t.usec
|
26
|
+
assert_equal "UTC", t.zone
|
27
|
+
end
|
28
|
+
|
16
29
|
it "casts text" do
|
17
30
|
definition.type = "string"
|
18
31
|
assert_equal "123", definition.cast(123)
|
@@ -20,45 +33,35 @@ describe Sinatra::Schema::Definition do
|
|
20
33
|
end
|
21
34
|
|
22
35
|
describe "#valid?" do
|
23
|
-
it "
|
36
|
+
it "validates booleans" do
|
24
37
|
definition.type = "boolean"
|
25
38
|
assert definition.valid?(true)
|
26
39
|
assert definition.valid?(false)
|
27
40
|
refute definition.valid?("true")
|
28
41
|
end
|
29
42
|
|
30
|
-
it "
|
43
|
+
it "validates emails" do
|
31
44
|
definition.type = "email"
|
32
45
|
assert definition.valid?("foo@bar.com")
|
33
46
|
refute definition.valid?("foobar.com")
|
34
47
|
end
|
35
48
|
|
36
|
-
it "
|
49
|
+
it "validates text" do
|
37
50
|
definition.type = "string"
|
38
51
|
assert definition.valid?("foo")
|
39
52
|
refute definition.valid?(123)
|
40
53
|
end
|
41
54
|
|
42
|
-
it "
|
55
|
+
it "validates uuids" do
|
43
56
|
definition.type = "uuid"
|
44
57
|
assert definition.valid?(SecureRandom.uuid)
|
45
58
|
refute definition.valid?("wrong")
|
46
59
|
end
|
47
|
-
end
|
48
60
|
|
49
|
-
|
50
|
-
|
51
|
-
definition.
|
52
|
-
|
53
|
-
assert_equal "string", schema[:type]
|
54
|
-
assert_equal "email", schema[:format]
|
55
|
-
end
|
56
|
-
|
57
|
-
it "dumps uuids" do
|
58
|
-
definition.type = "uuid"
|
59
|
-
schema = definition.to_schema
|
60
|
-
assert_equal "string", schema[:type]
|
61
|
-
assert_equal "uuid", schema[:format]
|
61
|
+
it "validates date+time fields" do
|
62
|
+
definition.type = "datetime"
|
63
|
+
assert definition.valid?("1985-04-12T23:20:50.52Z")
|
64
|
+
refute definition.valid?("12/4/1985 23:20:50")
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
@@ -17,6 +17,12 @@ describe Sinatra::Schema::DSL::Definitions do
|
|
17
17
|
assert_equal "boolean", resource.defs[:foobar].type
|
18
18
|
end
|
19
19
|
|
20
|
+
it "adds a datetime definition to the resource" do
|
21
|
+
dsl.datetime(:foobar)
|
22
|
+
assert_equal 1, resource.defs.size
|
23
|
+
assert_equal "datetime", resource.defs[:foobar].type
|
24
|
+
end
|
25
|
+
|
20
26
|
it "adds nested definitions" do
|
21
27
|
dsl[:user].text :email
|
22
28
|
dsl[:user].bool :admin
|
@@ -25,43 +31,14 @@ describe Sinatra::Schema::DSL::Definitions do
|
|
25
31
|
assert_equal "boolean", resource.defs[:user][:admin].type
|
26
32
|
end
|
27
33
|
|
34
|
+
it "adds references" do
|
35
|
+
dsl.ref(:another_property)
|
36
|
+
assert_equal 1, resource.defs.size
|
37
|
+
assert_instance_of Sinatra::Schema::Reference, resource.defs[:another_property]
|
38
|
+
end
|
39
|
+
|
28
40
|
it "sets other options" do
|
29
41
|
dsl.text(:foobar, optional: true)
|
30
42
|
assert_equal true, resource.defs[:foobar].optional
|
31
43
|
end
|
32
|
-
|
33
|
-
describe "#ref" do
|
34
|
-
let(:definition) { Sinatra::Schema::Definition.new(id: :foobar) }
|
35
|
-
|
36
|
-
it "adds a reference to another definition in the resource" do
|
37
|
-
resource.defs[:foobar] = definition
|
38
|
-
dsl.ref :foobar
|
39
|
-
assert_equal 1, resource.defs.size
|
40
|
-
assert_equal 1, resource.properties.size
|
41
|
-
end
|
42
|
-
|
43
|
-
it "adds a reference to a definition in a different resource" do
|
44
|
-
other = Sinatra::Schema::Resource.new(path: "/others")
|
45
|
-
root.add_resource(other)
|
46
|
-
other.defs[:foobar] = definition
|
47
|
-
dsl.ref "other/foobar"
|
48
|
-
assert_equal 1, other.defs.size
|
49
|
-
assert_equal 1, resource.properties.size
|
50
|
-
end
|
51
|
-
|
52
|
-
it "raises when we can't resolve the ref" do
|
53
|
-
assert_raises(Sinatra::Schema::BadReference) do
|
54
|
-
dsl.ref :foobar
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
it "allows references to have a different id" do
|
59
|
-
other = Sinatra::Schema::Resource.new(path: "/others")
|
60
|
-
root.add_resource(other)
|
61
|
-
other.defs[:foobar] = definition
|
62
|
-
dsl.ref :my_foobar, "other/foobar"
|
63
|
-
assert resource.properties.has_key?(:my_foobar)
|
64
|
-
assert_equal :foobar, resource.properties[:my_foobar].id
|
65
|
-
end
|
66
|
-
end
|
67
44
|
end
|
data/spec/dsl/resources_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Sinatra::Schema::DSL::Resources do
|
4
|
-
let(:app) { Sinatra
|
4
|
+
let(:app) { Sinatra.new {} }
|
5
5
|
let(:dsl) { described_class.new(app, "/foobar") }
|
6
6
|
|
7
7
|
it "sets the resource description" do
|
@@ -28,4 +28,31 @@ describe Sinatra::Schema::DSL::Resources do
|
|
28
28
|
assert_equal 2, dsl.resource.properties[:user].size
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
describe "building links" do
|
33
|
+
it "builds a DELETE" do
|
34
|
+
link = dsl.delete
|
35
|
+
assert_equal :delete, link.method
|
36
|
+
end
|
37
|
+
|
38
|
+
it "builds a GET" do
|
39
|
+
link = dsl.get
|
40
|
+
assert_equal :get, link.method
|
41
|
+
end
|
42
|
+
|
43
|
+
it "builds a PATCH" do
|
44
|
+
link = dsl.patch
|
45
|
+
assert_equal :patch, link.method
|
46
|
+
end
|
47
|
+
|
48
|
+
it "builds a POST" do
|
49
|
+
link = dsl.post
|
50
|
+
assert_equal :post, link.method
|
51
|
+
end
|
52
|
+
|
53
|
+
it "builds a PUT" do
|
54
|
+
link = dsl.put
|
55
|
+
assert_equal :put, link.method
|
56
|
+
end
|
57
|
+
end
|
31
58
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -1,24 +1,55 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Sinatra::Schema do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
describe "resource access" do
|
5
|
+
it "still works as a regular sinatra app" do
|
6
|
+
get "/regular"
|
7
|
+
assert_equal 200, last_response.status
|
8
|
+
assert_equal "hi", last_response.body
|
9
|
+
end
|
10
|
+
|
11
|
+
it "support resource gets" do
|
12
|
+
get "/accounts"
|
13
|
+
assert_equal 200, last_response.status
|
14
|
+
assert_equal({ "email" => "foo@bar.com" },
|
15
|
+
MultiJson.decode(last_response.body))
|
16
|
+
end
|
9
17
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
it "support resource posts" do
|
19
|
+
post "/accounts", email: "omg"
|
20
|
+
assert_equal 200, last_response.status
|
21
|
+
assert_equal({ "email" => "omg" },
|
22
|
+
MultiJson.decode(last_response.body))
|
23
|
+
end
|
15
24
|
end
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
describe "GET /schema" do
|
27
|
+
before do
|
28
|
+
get "/schema"
|
29
|
+
@schema = MultiJson.decode(last_response.body)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "renders a 200" do
|
33
|
+
assert_equal 200, last_response.status
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sets the appropriate content-type" do
|
37
|
+
assert_equal "application/schema+json",
|
38
|
+
last_response.headers["Content-Type"]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "sets $schema to hyper-schema" do
|
42
|
+
assert_equal "http://json-schema.org/draft-04/hyper-schema",
|
43
|
+
@schema["$schema"]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "generates definitions" do
|
47
|
+
assert_equal Hash, @schema["definitions"].class
|
48
|
+
assert_equal Hash, @schema["definitions"]["account"].class
|
49
|
+
assert_equal "Account", @schema["definitions"]["account"]["title"]
|
50
|
+
assert_equal "An account represents an individual signed up to use the service",
|
51
|
+
@schema["definitions"]["account"]["description"]
|
52
|
+
end
|
22
53
|
end
|
23
54
|
|
24
55
|
describe "error handling" do
|
data/spec/json_schema_spec.rb
CHANGED
@@ -1,30 +1,60 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
3
|
+
describe Sinatra::Schema::JsonSchema do
|
4
|
+
let(:json_schema) { described_class.new(root) }
|
5
|
+
let(:root) { Sinatra::Schema::Root.instance }
|
6
|
+
let(:schema) { json_schema.dump_root }
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
describe "#dump_root" do
|
9
|
+
it "sets $schema" do
|
10
|
+
assert_equal "http://json-schema.org/draft-04/hyper-schema",
|
11
|
+
schema["$schema"]
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
it "adds a definition hash" do
|
15
|
+
assert_instance_of Hash, schema["definitions"]
|
16
|
+
end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
describe "#dump_definition" do
|
20
|
+
let(:definition) { Sinatra::Schema::Definition.new }
|
21
|
+
|
22
|
+
it "handles simple string format" do
|
23
|
+
definition.type = "string"
|
24
|
+
schema = json_schema.dump_definition(definition)
|
25
|
+
assert_equal "string", schema[:type]
|
26
|
+
assert_nil schema[:format]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "handles the datetime format" do
|
30
|
+
definition.type = "datetime"
|
31
|
+
schema = json_schema.dump_definition(definition)
|
32
|
+
assert_equal "string", schema[:type]
|
33
|
+
assert_equal "date-time", schema[:format]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "handles the email format" do
|
37
|
+
definition.type = "email"
|
38
|
+
schema = json_schema.dump_definition(definition)
|
39
|
+
assert_equal "string", schema[:type]
|
40
|
+
assert_equal "email", schema[:format]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "handles the uuid format" do
|
44
|
+
definition.type = "uuid"
|
45
|
+
schema = json_schema.dump_definition(definition)
|
46
|
+
assert_equal "string", schema[:type]
|
47
|
+
assert_equal "uuid", schema[:format]
|
48
|
+
end
|
21
49
|
end
|
22
50
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
51
|
+
describe "#dump_link" do
|
52
|
+
let(:link) { Sinatra::Schema::Link.new }
|
53
|
+
|
54
|
+
it "renders the method in upcase" do
|
55
|
+
link.method = :get
|
56
|
+
schema = json_schema.dump_link(link)
|
57
|
+
assert_equal "GET", schema[:method]
|
58
|
+
end
|
29
59
|
end
|
30
60
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sinatra::Schema::Reference do
|
4
|
+
let(:resource) { Sinatra::Schema::Root.instance.resources[:account] }
|
5
|
+
let(:ref) { described_class.new(resource, :foo, :email) }
|
6
|
+
let(:definition) { resource.defs[:email] }
|
7
|
+
|
8
|
+
describe "#resolve!" do
|
9
|
+
it "finds other properties in the same resource" do
|
10
|
+
ref.ref_spec = :foo
|
11
|
+
resource.defs[:foo] = definition
|
12
|
+
assert_equal definition, ref.resolve!
|
13
|
+
end
|
14
|
+
|
15
|
+
it "finds other properties elsewhere in the schema" do
|
16
|
+
ref.ref_spec = "account/email"
|
17
|
+
assert_equal definition, ref.resolve!
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises when it cannot resolve" do
|
21
|
+
ref.ref_spec = "does-not-exist"
|
22
|
+
assert_raises(Sinatra::Schema::BadReference) do
|
23
|
+
ref.resolve!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "delegated attributes" do
|
29
|
+
it "#cast" do
|
30
|
+
assert_equal definition.cast("foo"), ref.cast("foo")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "#description" do
|
34
|
+
assert_equal definition.description, ref.description
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#example" do
|
38
|
+
assert_equal definition.example, ref.example
|
39
|
+
end
|
40
|
+
|
41
|
+
it "#optional" do
|
42
|
+
assert_equal definition.optional, ref.optional
|
43
|
+
end
|
44
|
+
|
45
|
+
it "#type" do
|
46
|
+
assert_equal definition.type, ref.type
|
47
|
+
end
|
48
|
+
|
49
|
+
it "#valid?" do
|
50
|
+
assert_equal definition.valid?("foo"), ref.valid?("foo")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/support/test_app.rb
CHANGED
@@ -13,7 +13,7 @@ class TestApp < Sinatra::Base
|
|
13
13
|
example: "username@example.com",
|
14
14
|
format: "email"
|
15
15
|
|
16
|
-
res.
|
16
|
+
res.get do |link|
|
17
17
|
link.title "Info"
|
18
18
|
link.rel "self"
|
19
19
|
link.description "Info for account"
|
@@ -22,7 +22,7 @@ class TestApp < Sinatra::Base
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
res.
|
25
|
+
res.post do |link|
|
26
26
|
link.title "Create"
|
27
27
|
link.rel "create"
|
28
28
|
link.description "Create a new account"
|
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Belo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -139,9 +139,11 @@ files:
|
|
139
139
|
- lib/sinatra/schema/dsl/links.rb
|
140
140
|
- lib/sinatra/schema/dsl/resources.rb
|
141
141
|
- lib/sinatra/schema/error.rb
|
142
|
+
- lib/sinatra/schema/json_schema.rb
|
142
143
|
- lib/sinatra/schema/link.rb
|
143
144
|
- lib/sinatra/schema/param_parsing.rb
|
144
145
|
- lib/sinatra/schema/param_validation.rb
|
146
|
+
- lib/sinatra/schema/reference.rb
|
145
147
|
- lib/sinatra/schema/resource.rb
|
146
148
|
- lib/sinatra/schema/root.rb
|
147
149
|
- lib/sinatra/schema/tasks/schema.rake
|
@@ -155,6 +157,7 @@ files:
|
|
155
157
|
- spec/json_schema_spec.rb
|
156
158
|
- spec/param_parsing_spec.rb
|
157
159
|
- spec/param_validation_spec.rb
|
160
|
+
- spec/reference_spec.rb
|
158
161
|
- spec/resource_spec.rb
|
159
162
|
- spec/spec_helper.rb
|
160
163
|
- spec/support/last_json.rb
|