render 0.0.8 → 0.0.9

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 (35) hide show
  1. data/.ruby-version +1 -1
  2. data/lib/json/draft-04/hyper-schema.json +168 -0
  3. data/lib/json/draft-04/schema.json +150 -0
  4. data/lib/render.rb +2 -0
  5. data/lib/render/attributes/array_attribute.rb +20 -14
  6. data/lib/render/attributes/attribute.rb +23 -7
  7. data/lib/render/attributes/hash_attribute.rb +6 -2
  8. data/lib/render/definition.rb +13 -7
  9. data/lib/render/errors.rb +33 -6
  10. data/lib/render/generator.rb +67 -8
  11. data/lib/render/graph.rb +39 -64
  12. data/lib/render/json_schema.rb +12 -0
  13. data/lib/render/schema.rb +92 -31
  14. data/lib/render/type.rb +51 -9
  15. data/lib/render/version.rb +1 -1
  16. data/readme.md +66 -9
  17. data/render.gemspec +4 -3
  18. data/spec/functional/render/attribute_spec.rb +66 -8
  19. data/spec/functional/render/nested_schemas_spec.rb +18 -26
  20. data/spec/functional/render/schema_spec.rb +28 -0
  21. data/spec/integration/render/graph_spec.rb +3 -3
  22. data/spec/integration/render/nested_graph_spec.rb +12 -14
  23. data/spec/integration/render/schema_spec.rb +4 -4
  24. data/spec/support/schemas/film.json +3 -3
  25. data/spec/support/schemas/films.json +3 -3
  26. data/spec/unit/render/attributes/array_attribute_spec.rb +34 -9
  27. data/spec/unit/render/attributes/attribute_spec.rb +13 -0
  28. data/spec/unit/render/attributes/hash_attribute_spec.rb +17 -7
  29. data/spec/unit/render/definition_spec.rb +7 -25
  30. data/spec/unit/render/generator_spec.rb +102 -2
  31. data/spec/unit/render/graph_spec.rb +18 -19
  32. data/spec/unit/render/schema_spec.rb +185 -54
  33. data/spec/unit/render/type_spec.rb +88 -13
  34. metadata +66 -29
  35. checksums.yaml +0 -15
@@ -18,16 +18,39 @@ module Render
18
18
  end
19
19
 
20
20
  it "is set to preloaded definition" do
21
- definition_title = :preloaded_schema
22
- definition = { title: definition_title, properties: { title: { type: String } } }
21
+ definition_id = :preloaded_schema
22
+ definition = { id: definition_id, properties: { title: { type: String } } }
23
23
  Definition.load!(definition)
24
- Schema.new(definition_title).definition.should == definition
24
+
25
+ Schema.new(definition_id).definition.should == definition
25
26
  end
26
27
 
27
28
  it "raises an error if definition is not found and argument is not a schema" do
28
29
  expect {
29
30
  Schema.new(:does_not_exists)
30
- }.to raise_error(Errors::DefinitionNotFound)
31
+ }.to raise_error(Errors::Definition::NotFound)
32
+ end
33
+
34
+ # This is probably not the best form
35
+ describe "non-container definitions" do
36
+ it "creates Object container for subschemas" do
37
+ non_container_definition = {
38
+ students: { type: Array, items: { type: String } },
39
+ teacher: { type: Object, properties: { name: { type: String } } }
40
+ }
41
+
42
+ converted_definition = {
43
+ type: Object,
44
+ properties: {
45
+ students: { type: Array, items: { type: String } },
46
+ teacher: { type: Object, properties: { name: { type: String } } }
47
+ }
48
+ }
49
+
50
+ non_container_schema = Schema.new(non_container_definition)
51
+ converted_schema = Schema.new(converted_definition)
52
+ non_container_schema.definition.should == converted_schema.definition
53
+ end
31
54
  end
32
55
  end
33
56
 
@@ -44,16 +67,16 @@ module Render
44
67
 
45
68
  describe "#array_attribute" do
46
69
  it "is set for array schemas" do
47
- archetype_schema = {
70
+ simple_schema = {
48
71
  type: Array,
49
72
  items: {
50
73
  type: String
51
74
  }
52
75
  }
53
76
 
54
- attribute = Schema.new(archetype_schema).array_attribute
55
- attribute.type.should == String
56
- attribute.archetype.should == true
77
+ attribute = Schema.new(simple_schema).array_attribute
78
+ attribute.types.should == [String]
79
+ attribute.simple.should == true
57
80
  end
58
81
  end
59
82
 
@@ -69,8 +92,158 @@ module Render
69
92
 
70
93
  schema = Schema.new(simple_schema)
71
94
  schema.hash_attributes.size.should == 2
72
- schema.hash_attributes.any? { |a| a.name == :name && a.type == String }.should == true
73
- schema.hash_attributes.any? { |a| a.name == :genre && a.type == String }.should == true
95
+ schema.hash_attributes.any? { |a| a.name == :name && a.types == [String] }.should == true
96
+ schema.hash_attributes.any? { |a| a.name == :genre && a.types == [String] }.should == true
97
+ end
98
+ end
99
+
100
+ describe "$ref" do
101
+ before(:each) do
102
+ @original_instances = Definition.instances.dup
103
+ end
104
+
105
+ after(:each) do
106
+ Definition.instances = @original_instances
107
+ end
108
+
109
+ it "creates subschemas for absolute references" do
110
+ topping_definition = {
111
+ id: "http://pizzas.local/schema#topping",
112
+ type: Object, properties: { name: { type: String } }
113
+ }
114
+ Definition.load!(topping_definition)
115
+
116
+ pizza_definition = {
117
+ type: Object,
118
+ properties: {
119
+ toppings: { type: Array, items: { :$ref => "http://pizzas.local/schema#topping" } }
120
+ }
121
+ }
122
+ pizza_schema = Schema.new(pizza_definition)
123
+
124
+ pizza_schema.definition.should == {
125
+ type: Object,
126
+ properties: {
127
+ toppings: {
128
+ type: Array,
129
+ items: {
130
+ id: "http://pizzas.local/schema#topping",
131
+ type: Object,
132
+ properties: { name: { type: String } }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ end
138
+
139
+ it "creates subschemas for relative references from root" do
140
+ definition = {
141
+ definitions: {
142
+ address: {
143
+ type: Object,
144
+ properties: { number: { type: Integer } }
145
+ }
146
+ },
147
+ type: Object,
148
+ properties: {
149
+ address: { :$ref => "#/definitions/address" }
150
+ }
151
+ }
152
+ schema = Schema.new(definition)
153
+
154
+ schema.definition[:properties].should == {
155
+ address: {
156
+ type: Object,
157
+ properties: { number: { type: Integer } }
158
+ }
159
+ }
160
+ end
161
+
162
+ it "creates nested subschemas for relative references from root" do
163
+ definition = {
164
+ definitions: {
165
+ address: {
166
+ type: Object,
167
+ properties: { number: { type: Integer } }
168
+ }
169
+ },
170
+ type: Object,
171
+ properties: {
172
+ primary_location: {
173
+ type: Object,
174
+ properties: {
175
+ address: { :$ref => "#/definitions/address" }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ schema = Schema.new(definition)
181
+
182
+ schema.definition[:properties].should == {
183
+ primary_location: {
184
+ type: Object,
185
+ properties: {
186
+ address: {
187
+ type: Object,
188
+ properties: {
189
+ number: { type: Integer }
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ end
196
+
197
+ it "interpolates closest relative definition" do
198
+ definition = {
199
+ definitions: { year: { type: :number } },
200
+ type: Object,
201
+ properties: {
202
+ book: {
203
+ definitions: { year: { type: Integer } },
204
+ type: Object,
205
+ properties: {
206
+ year: { :$ref => "definitions/year" }
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ parsed_definition = Schema.new(definition).definition
213
+ year_schema = parsed_definition.fetch(:properties).fetch(:book).fetch(:properties).fetch(:year)
214
+ year_schema.fetch(:type).should == Integer
215
+ end
216
+
217
+ it "interpolates root-relative definition when specified" do
218
+ definition = {
219
+ definitions: { year: { type: :number } },
220
+ type: Object,
221
+ properties: {
222
+ book: {
223
+ definitions: { year: { type: Integer } },
224
+ type: Object,
225
+ properties: {
226
+ year: { :$ref => "#/definitions/year" }
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ parsed_definition = Schema.new(definition).definition
233
+ parsed_definition.fetch(:properties).fetch(:book).fetch(:properties).fetch(:year).fetch(:type).should == :number
234
+ end
235
+
236
+ it "expands to empty schema if no ref is found" do
237
+ definition = {
238
+ type: Object,
239
+ properties: {
240
+ year_relative: { :$ref => "definitions/year" },
241
+ year_root: { :$ref => "#/definitions/year" }
242
+ }
243
+ }
244
+
245
+ Schema.new(definition).definition.fetch(:properties).fetch(:year_relative).should == {}
246
+ Schema.new(definition).definition.fetch(:properties).fetch(:year_root).should == {}
74
247
  end
75
248
  end
76
249
  end
@@ -104,7 +277,7 @@ module Render
104
277
  describe "#render!" do
105
278
  before(:each) do
106
279
  Definition.load!({
107
- title: :film,
280
+ id: :film,
108
281
  type: Object,
109
282
  properties: {
110
283
  genre: { type: String }
@@ -112,35 +285,6 @@ module Render
112
285
  })
113
286
  end
114
287
 
115
- describe "#raw_data" do
116
- it "is set from endpoint response" do
117
- schema = Schema.new(:film)
118
- schema.stub({ request: { response: :body } })
119
- schema.render!
120
- schema.raw_data.should == { response: :body }
121
- end
122
-
123
- it "is set to explicit_data when offline" do
124
- Render.stub({ live: false })
125
- schema = Schema.new(:film)
126
- schema.render!({ explicit: :value })
127
- schema.raw_data.should == { explicit: :value }
128
- end
129
-
130
- it "is yielded" do
131
- Render.stub({ live: false })
132
- schema = Schema.new(:film)
133
-
134
- data = { explicit: :value }
135
- schema.should_receive(:serialize!).with(data)
136
- schema.serialized_data = :serialized_data
137
-
138
- expect { |a_block|
139
- schema.render!(data, &a_block)
140
- }.to yield_with_args(:serialized_data)
141
- end
142
- end
143
-
144
288
  context "request" do
145
289
  it "raises error if endpoint does not return a 2xx" do
146
290
  endpoint = "http://endpoint.local"
@@ -175,20 +319,7 @@ module Render
175
319
  schema = Schema.new(:film)
176
320
  schema.hash_attributes.first.should_receive(:serialize).with(genre, anything).and_return({ genre: genre })
177
321
 
178
- schema.render!(nil, endpoint).should == { film: data }
179
- end
180
-
181
- it "is serialized value nested under #universal_title" do
182
- Render.stub({ live: false })
183
- definition = {
184
- title: :film,
185
- universal_title: :imdb_films_show,
186
- type: Object,
187
- properties: {
188
- genre: { type: String }
189
- }
190
- }
191
- Schema.new(definition).render!.should have_key(:imdb_films_show)
322
+ schema.render!(nil, endpoint).should == data
192
323
  end
193
324
  end
194
325
 
@@ -15,12 +15,35 @@ module Render
15
15
  Type.parse("integer").should == Integer
16
16
  end
17
17
 
18
+ it "returns constant for symbols" do
19
+ Type.parse(:integer).should == Integer
20
+ end
21
+
18
22
  it "returns nil if no type is found" do
19
23
  Type.parse("not-a-type").should == nil
20
24
  end
21
25
  end
22
26
 
23
27
  describe ".parse!" do
28
+ it "returns ruby classes for standard json types" do
29
+ Type.parse!("string").should == String
30
+ Type.parse!("number").should == Float
31
+ Type.parse!("integer").should == Integer
32
+ Type.parse!("object").should == Object
33
+ Type.parse!("array").should == Array
34
+ Type.parse!("boolean").should == Type::Boolean
35
+ Type.parse!("null").should == NilClass
36
+ end
37
+
38
+ it "returns ruby classes for standard json formats" do
39
+ Type.parse!("uri").should == URI
40
+ Type.parse!("date-time").should == DateTime
41
+ Type.parse!("ipv4").should == Type::IPv4
42
+ Type.parse!("ipv6").should == Type::IPv6
43
+ Type.parse!("email").should == Type::Email
44
+ Type.parse!("hostname").should == Type::Hostname
45
+ end
46
+
24
47
  it "returns constant for string" do
25
48
  Type.parse("integer").should == Integer
26
49
  end
@@ -48,18 +71,6 @@ module Render
48
71
  it "returns UUID for uuid" do
49
72
  Type.parse("uUId").should == UUID
50
73
  end
51
-
52
- it "returns Boolean for boolean" do
53
- Type.parse("boolean").should == Render::Type::Boolean
54
- end
55
-
56
- it "returns Float for number" do
57
- Type.parse("FloAt").should == Float
58
- end
59
-
60
- it "returns Time for date-time" do
61
- Type.parse("date-time").should == Time
62
- end
63
74
  end
64
75
  end
65
76
 
@@ -72,7 +83,7 @@ module Render
72
83
  Type.find(:foo).should_not be
73
84
  end
74
85
 
75
- describe "user type" do
86
+ describe "user types" do
76
87
  before(:each) do
77
88
  @original_types = Type.instances.dup
78
89
  module ::Foo; module Boolean; end; end
@@ -89,5 +100,69 @@ module Render
89
100
  end
90
101
  end
91
102
  end
103
+
104
+ describe ".to" do
105
+ it "maintains nil values" do
106
+ Type.to([Float], nil).should == nil
107
+ end
108
+
109
+ it "returns nil for undefined classes" do
110
+ Type.to([nil], {}).should == nil
111
+ end
112
+
113
+ it "converts to floats" do
114
+ Type.to([Float], "2").should == 2
115
+ end
116
+
117
+ it "converts to Integers" do
118
+ Type.to([Integer], "1.2").should == 1
119
+ end
120
+
121
+ it "converts to Strings" do
122
+ Type.to([String], 2).should == "2"
123
+ end
124
+
125
+ describe "enum" do
126
+ it "returns valid enum" do
127
+ enums = [:foo, :bar]
128
+ Type.to([Type::Enum], :foo, enums).should == :foo
129
+ end
130
+
131
+ it "return nil for invalid enums" do
132
+ enums = [:foo]
133
+ Type.to([Type::Enum], :bar, enums).should == nil
134
+ end
135
+ end
136
+
137
+ describe "boolean" do
138
+ it "converts strings" do
139
+ Type.to([Type::Boolean], "true").should eq(true)
140
+ Type.to([Type::Boolean], "false").should eq(false)
141
+ end
142
+
143
+ it "returns nil for invalid booleans" do
144
+ Type.to([Type::Boolean], "foo").should == nil
145
+ end
146
+ end
147
+
148
+ it "returns value for unknown types" do
149
+ class Foo; end
150
+
151
+ Type.to([Foo], :bar).should == :bar
152
+
153
+ Render.send(:remove_const, :Foo)
154
+ end
155
+
156
+ context "multiple types" do
157
+ it "returns value in original type if valid" do
158
+ Type.to([Integer, Float], 2.0).should == 2.0
159
+ end
160
+
161
+ it "returns value of first class if original type is not valid" do
162
+ Type.to([Integer, String], 2.0).should == 2
163
+ end
164
+ end
165
+
166
+ end
92
167
  end
93
168
  end
metadata CHANGED
@@ -1,88 +1,116 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: render
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Steve Weber
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-02-16 00:00:00.000000000 Z
12
+ date: 2014-03-18 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
+ name: uuid
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - ~>
19
+ - - '='
18
20
  - !ruby/object:Gem::Version
19
- version: '1.3'
20
- type: :development
21
+ version: 2.3.7
22
+ type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - ~>
27
+ - - '='
25
28
  - !ruby/object:Gem::Version
26
- version: '1.3'
29
+ version: 2.3.7
27
30
  - !ruby/object:Gem::Dependency
28
- name: rake
31
+ name: addressable
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - ~>
35
+ - - '='
32
36
  - !ruby/object:Gem::Version
33
- version: '10.1'
34
- type: :development
37
+ version: 2.3.5
38
+ type: :runtime
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - ~>
43
+ - - '='
39
44
  - !ruby/object:Gem::Version
40
- version: '10.1'
45
+ version: 2.3.5
41
46
  - !ruby/object:Gem::Dependency
42
- name: uuid
47
+ name: macaddr
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
51
  - - '='
46
52
  - !ruby/object:Gem::Version
47
- version: 2.3.7
53
+ version: 1.6.1
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - '='
53
60
  - !ruby/object:Gem::Version
54
- version: 2.3.7
61
+ version: 1.6.1
55
62
  - !ruby/object:Gem::Dependency
56
- name: macaddr
63
+ name: bundler
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - '='
67
+ - - ~>
60
68
  - !ruby/object:Gem::Version
61
- version: 1.6.1
62
- type: :runtime
69
+ version: '1.3'
70
+ type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - '='
75
+ - - ~>
67
76
  - !ruby/object:Gem::Version
68
- version: 1.6.1
77
+ version: '1.3'
69
78
  - !ruby/object:Gem::Dependency
70
- name: debugger
79
+ name: rake
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
83
  - - ~>
74
84
  - !ruby/object:Gem::Version
75
- version: '1.6'
85
+ version: '10.1'
76
86
  type: :development
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
91
  - - ~>
81
92
  - !ruby/object:Gem::Version
82
- version: '1.6'
93
+ version: '10.1'
94
+ - !ruby/object:Gem::Dependency
95
+ name: debugger
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - '='
100
+ - !ruby/object:Gem::Version
101
+ version: 1.6.6
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - '='
108
+ - !ruby/object:Gem::Version
109
+ version: 1.6.6
83
110
  - !ruby/object:Gem::Dependency
84
111
  name: rspec
85
112
  requirement: !ruby/object:Gem::Requirement
113
+ none: false
86
114
  requirements:
87
115
  - - ~>
88
116
  - !ruby/object:Gem::Version
@@ -90,6 +118,7 @@ dependencies:
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
93
122
  requirements:
94
123
  - - ~>
95
124
  - !ruby/object:Gem::Version
@@ -97,6 +126,7 @@ dependencies:
97
126
  - !ruby/object:Gem::Dependency
98
127
  name: webmock
99
128
  requirement: !ruby/object:Gem::Requirement
129
+ none: false
100
130
  requirements:
101
131
  - - ~>
102
132
  - !ruby/object:Gem::Version
@@ -104,6 +134,7 @@ dependencies:
104
134
  type: :development
105
135
  prerelease: false
106
136
  version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
107
138
  requirements:
108
139
  - - ~>
109
140
  - !ruby/object:Gem::Version
@@ -111,6 +142,7 @@ dependencies:
111
142
  - !ruby/object:Gem::Dependency
112
143
  name: yard
113
144
  requirement: !ruby/object:Gem::Requirement
145
+ none: false
114
146
  requirements:
115
147
  - - ~>
116
148
  - !ruby/object:Gem::Version
@@ -118,6 +150,7 @@ dependencies:
118
150
  type: :development
119
151
  prerelease: false
120
152
  version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
121
154
  requirements:
122
155
  - - ~>
123
156
  - !ruby/object:Gem::Version
@@ -137,6 +170,8 @@ files:
137
170
  - Gemfile.lock
138
171
  - LICENSE.txt
139
172
  - initialize.rb
173
+ - lib/json/draft-04/hyper-schema.json
174
+ - lib/json/draft-04/schema.json
140
175
  - lib/render.rb
141
176
  - lib/render/attributes/array_attribute.rb
142
177
  - lib/render/attributes/attribute.rb
@@ -148,6 +183,7 @@ files:
148
183
  - lib/render/extensions/symbolizable_hash.rb
149
184
  - lib/render/generator.rb
150
185
  - lib/render/graph.rb
186
+ - lib/render/json_schema.rb
151
187
  - lib/render/schema.rb
152
188
  - lib/render/type.rb
153
189
  - lib/render/version.rb
@@ -180,26 +216,27 @@ files:
180
216
  homepage: https://github.com/stevenweber/render
181
217
  licenses:
182
218
  - MIT
183
- metadata: {}
184
219
  post_install_message:
185
220
  rdoc_options: []
186
221
  require_paths:
187
222
  - lib
188
223
  required_ruby_version: !ruby/object:Gem::Requirement
224
+ none: false
189
225
  requirements:
190
226
  - - ! '>='
191
227
  - !ruby/object:Gem::Version
192
228
  version: '0'
193
229
  required_rubygems_version: !ruby/object:Gem::Requirement
230
+ none: false
194
231
  requirements:
195
232
  - - ! '>='
196
233
  - !ruby/object:Gem::Version
197
234
  version: '0'
198
235
  requirements: []
199
236
  rubyforge_project:
200
- rubygems_version: 2.2.1
237
+ rubygems_version: 1.8.23
201
238
  signing_key:
202
- specification_version: 4
239
+ specification_version: 3
203
240
  summary: With a JSON schema, Render will manage requests, dependent request and build
204
241
  meaningful, extensible sample data for testing.
205
242
  test_files: