render 0.0.2 → 0.0.3

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.
@@ -5,35 +5,30 @@ require "uuid"
5
5
  module Render
6
6
  describe Graph do
7
7
  before(:each) do
8
+ Render.stub({ live: false })
9
+ @definition = double(:definition)
8
10
  @schema = double(:schema)
11
+ Schema.stub(:new).with(@definition).and_return(@schema)
9
12
  end
10
13
 
11
14
  describe ".initialize" do
12
- it "has defaults" do
13
- graph = Graph.new(@schema)
14
- graph.raw_endpoint.should == ""
15
- graph.relationships.should == {}
16
- graph.graphs.should == []
17
- graph.parental_params.should == {}
18
- graph.config.should == {}
19
- end
20
-
21
- describe "schema" do
22
- it "sets argument" do
23
- graph = Graph.new(@schema)
24
- graph.schema.should == @schema
15
+ describe "#schema" do
16
+ it "is set from argument" do
17
+ Schema.unstub(:new)
18
+ schema = Schema.new({ title: :foo, properties: { name: { type: String } } })
19
+ Graph.new(schema).schema.should == schema
25
20
  end
26
21
 
27
- it "creates new schema from symbol (for loaded schema lookup)" do
28
- Schema.should_receive(:new).with(:film).and_return(:new_schema)
29
- Graph.new(:film).schema.should == :new_schema
22
+ it "is set to new Schema from definition" do
23
+ Schema.should_receive(:new).with(:title_or_definition).and_return(:schema)
24
+ Graph.new(:title_or_definition).schema.should == :schema
30
25
  end
31
26
  end
32
27
 
33
- it "sets attributes" do
28
+ it "sets attributes from options" do
34
29
  relationships = { director_id: :id }
35
30
  graphs = [double(:graph)]
36
- graph = Graph.new(@schema, {
31
+ graph = Graph.new(@definition, {
37
32
  relationships: relationships,
38
33
  graphs: graphs,
39
34
  })
@@ -42,80 +37,47 @@ module Render
42
37
  graph.graphs.should == graphs
43
38
  end
44
39
 
45
- it "treats non-used attributes as config" do
40
+ it "sets config from options that are not attributes" do
46
41
  relationships = { some: :relationship }
47
- graphs = [double(:some_graph)]
48
42
  client_id = UUID.generate
49
- graph = Graph.new(@schema, {
43
+ graph = Graph.new(@definition, {
50
44
  relationships: relationships,
51
- graphs: graphs,
52
45
  client_id: client_id
53
46
  })
54
47
 
55
48
  graph.config.should == { client_id: client_id }
56
49
  end
57
-
58
- describe "#raw_endpoint" do
59
- it "is set with endpoint" do
60
- endpoint = "http://endpoint.local"
61
- graph = Graph.new(@schema, { endpoint: endpoint })
62
- graph.raw_endpoint.should == endpoint
63
- end
64
- end
65
-
66
- it "initializes params from endpoint" do
67
- endpoint = "http://endpoint.local/:id?client_id=:client_id"
68
- graph = Graph.new(@schema, { endpoint: endpoint })
69
- graph.params.should == { id: nil, client_id: nil }
70
- end
71
50
  end
72
51
 
73
52
  describe ".endpoint" do
74
53
  it "returns #raw_endpoint" do
75
54
  simple_endpoint = "http://endpoint.local"
76
- graph = Graph.new(@schema, { endpoint: simple_endpoint })
55
+ graph = Graph.new(@definition, { endpoint: simple_endpoint })
77
56
  graph.endpoint.should == simple_endpoint
78
57
  end
79
58
 
80
- it "interpolates parental_params" do
59
+ it "interpolates inherited parameters" do
81
60
  director_id = UUID.generate
82
61
  endpoint = "http://endpoint.local/directors/:id"
83
- interpolated_endpoint = "http://endpoint.local/directors/#{director_id}"
84
-
85
62
  relationships = { director_id: :id }
86
- graph = Graph.new(@schema, { endpoint: endpoint, relationships: relationships })
87
- graph.parental_params[:id] = director_id
88
63
 
89
- graph.endpoint.should == interpolated_endpoint
90
- end
91
-
92
- it "interpolates config attributes" do
93
- client_id = UUID.generate
94
- endpoint = "http://endpoint.local/?:client_id"
95
- interpolated_endpoint = "http://endpoint.local/?client_id=#{client_id}"
64
+ graph = Graph.new(@definition, { endpoint: endpoint, relationships: relationships })
65
+ graph.inherited_data = { director_id: director_id }
96
66
 
97
- graph = Graph.new(@schema, { endpoint: endpoint, client_id: client_id })
98
- graph.endpoint.should == interpolated_endpoint
67
+ graph.endpoint.should == "http://endpoint.local/directors/#{director_id}"
99
68
  end
100
69
 
101
- it "interpolates multiple path and query values" do
102
- the_shinning = UUID.generate
103
- kubrick = UUID.generate
70
+ it "interpolates config options" do
104
71
  client_id = UUID.generate
105
- client_secret = UUID.generate
106
-
107
- endpoint = "http://endpoint.local/directors/:id/films/:film_id?:client_id&:client_secret"
108
- interpolated_endpoint = "http://endpoint.local/directors/#{kubrick}/films/#{the_shinning}?client_id=#{client_id}&client_secret=#{client_secret}"
109
-
110
- graph = Graph.new(@schema, { endpoint: endpoint, client_id: client_id, client_secret: client_secret })
111
- graph.parental_params = { id: kubrick, film_id: the_shinning }
72
+ endpoint = "http://endpoint.local/?:client_id"
112
73
 
113
- graph.endpoint.should == interpolated_endpoint
74
+ graph = Graph.new(@definition, { endpoint: endpoint, client_id: client_id })
75
+ graph.endpoint.should == "http://endpoint.local/?client_id=#{client_id}"
114
76
  end
115
77
 
116
78
  it "raises an error if no value can be found" do
117
79
  endpoint = "http://endpoint.com/?:undefined_key"
118
- graph = Graph.new(@schema, { endpoint: endpoint })
80
+ graph = Graph.new(@definition, { endpoint: endpoint })
119
81
 
120
82
  expect {
121
83
  graph.endpoint
@@ -125,88 +87,122 @@ module Render
125
87
 
126
88
  describe "#render" do
127
89
  it "returns its schema's data" do
128
- pull = { film: { id: UUID.generate } }
129
- @schema.stub({ render: pull })
90
+ serialized_data = { id: UUID.generate }
91
+ pull = { film: serialized_data }
92
+ @schema.stub({ render!: pull, serialized_data: serialized_data })
130
93
 
131
- graph = Graph.new(@schema)
94
+ graph = Graph.new(@definition)
132
95
  graph.render.should == pull
133
96
  end
134
97
 
135
98
  it "returns a dottable hash" do
136
99
  pull = { film: { id: UUID.generate } }
137
- @schema.stub({ render: pull })
100
+ @schema.stub({ render!: pull })
138
101
 
139
- graph = Graph.new(@schema)
102
+ graph = Graph.new(@definition)
140
103
  graph.render.should be_a(DottableHash)
141
104
  end
142
105
 
143
106
  it "sends interpolated endpoint to its schema" do
144
107
  endpoint = "http://endpoint.local/?:client_id"
145
108
  client_id = UUID.generate
146
- graph = Graph.new(@schema, { endpoint: endpoint, client_id: client_id })
109
+ graph = Graph.new(@definition, { endpoint: endpoint, client_id: client_id })
147
110
 
148
- pull = { foo: "bar" }
149
- @schema.should_receive(:render).with({ endpoint: graph.endpoint }).and_return(pull)
150
- graph.render.should == pull
111
+ @schema.should_receive(:render!).with({ endpoint: graph.endpoint }).and_return({})
112
+ graph.render
151
113
  end
152
114
 
153
115
  context "with nested graphs" do
154
116
  before(:each) do
155
- Render.stub({ live: false })
156
-
157
- director_schema = {
158
- title: "director",
117
+ Schema.unstub(:new)
118
+ film_definition = {
119
+ title: "film",
159
120
  type: Object,
160
- attributes: { id: { type: UUID } }
121
+ properties: { director_id: { type: UUID } }
161
122
  }
162
- @director_schema = Schema.new(director_schema)
123
+ @film_schema = Schema.new(film_definition)
163
124
 
164
- film_schema = {
165
- title: "film",
125
+ @director_id = UUID.generate
126
+ director_definition = {
127
+ title: "director",
166
128
  type: Object,
167
- attributes: { director_id: { type: UUID } }
129
+ properties: { id: { type: UUID } }
168
130
  }
169
- @film_schema = Schema.new(film_schema)
131
+ @director_schema = Schema.new(director_definition)
170
132
  end
171
133
 
172
- it "merges nested graphs" do
173
- pulled_data = { a: "attribute" }
174
- @director_schema.stub({ render: pulled_data })
175
-
176
- director = Graph.new(@director_schema)
177
- film = Graph.new(@film_schema, { graphs: [director]})
178
-
179
- film_graph = film.render[@film_schema.title.to_sym]
180
- film_graph.should include(pulled_data)
134
+ it "includes nested graphs" do
135
+ film = Graph.new(@film_schema, { graphs: [Graph.new(@director_schema)] })
136
+ film = film.render
137
+ film.keys.should =~ [:film, :director]
181
138
  end
182
139
 
183
140
  it "uses parent data to calculate endpoint" do
184
- director_id = UUID.generate
185
141
  film = Graph.new(@film_schema)
186
- film.schema.stub({ render: { film: { director_id: director_id } } })
187
-
188
- endpoint = "http://endpoint.local/directors/:id"
189
- interpolated_endpoint = "http://endpoint.local/directors/#{director_id}"
190
142
  relationships = { director_id: :id }
191
- director = Graph.new(@director_schema, { endpoint: endpoint, relationships: relationships })
143
+ endpoint = "http://endpoint.local/directors/:id"
144
+ film.graphs << Graph.new(@director_schema, { endpoint: endpoint, relationships: relationships })
192
145
 
193
- film.graphs << director
194
- director.schema.should_receive(:render).with do |args|
195
- args[:endpoint].should == interpolated_endpoint
196
- end.and_return({})
146
+ film_data = { director_id: @director_id }
147
+ @film_schema.should_receive(:render!).and_yield(film_data).and_return(film_data)
197
148
 
149
+ @director_schema.should_receive(:render!).with do |args|
150
+ args[:endpoint].should == "http://endpoint.local/directors/#{@director_id}"
151
+ end.and_return({})
198
152
  film.render
199
153
  end
200
154
 
201
- context "offline" do
202
- it "uses parent data for childrens attributes" do
203
- relationships = { director_id: :id }
204
- director = Graph.new(@director_schema, { relationships: relationships })
205
- film = Graph.new(@film_schema, { graphs: [director]})
155
+ it "uses parent data to make multiple queries" do
156
+ films_schema = Schema.new({
157
+ title: "films",
158
+ type: Array,
159
+ items: {
160
+ properties: {
161
+ id: { type: UUID }
162
+ }
163
+ }
164
+ })
165
+
166
+ film_graph = Graph.new(@film_schema, { relationships: { id: :director_id } })
167
+ films = Graph.new(films_schema, { graphs: [film_graph] })
168
+
169
+ first_film_id = UUID.generate
170
+ second_film_id = UUID.generate
171
+ films_response = [{ id: first_film_id }, { id: second_film_id }]
172
+ films_schema.should_receive(:render!).and_yield(films_response).and_return({ films: films_response })
173
+
174
+ response = films.render
175
+ response.film.should be_a(Array)
176
+ response.film.should =~ [{ director_id: first_film_id }, { director_id: second_film_id }]
177
+ end
178
+
179
+ it "uses parent data for childrens' properties when explicitly used" do
180
+ director = Graph.new(@director_schema, { relationships: { director_id: :id } })
181
+ film = Graph.new(@film_schema, { graphs: [director] })
182
+ @film_schema.should_receive(:render!).and_yield({ director_id: @director_id }).and_return({})
183
+
184
+ film.render.director.id.should == @director_id
185
+ end
206
186
 
207
- film_graph = film.render[@film_schema.title.to_sym]
208
- film_graph[@director_schema.title.to_sym][:id].should == film_graph[:director_id]
209
- end
187
+ it "uses archetype parental data" do
188
+ films_schema = Schema.new({
189
+ title: "films",
190
+ type: Array,
191
+ items: {
192
+ type: UUID
193
+ }
194
+ })
195
+
196
+ film_graph = Graph.new(@film_schema, { relationships: { anything: :director_id } })
197
+ films = Graph.new(films_schema, { graphs: [film_graph] })
198
+
199
+ film_id = UUID.generate
200
+ films_response = [film_id]
201
+ films_schema.should_receive(:render!).and_yield(films_response).and_return({ films: films_response })
202
+
203
+ response = films.render
204
+ response.film.should be_a(Array)
205
+ response.film.should =~ [{ director_id: film_id }]
210
206
  end
211
207
  end
212
208
  end
@@ -0,0 +1,130 @@
1
+ module Render
2
+ describe HashAttribute do
3
+ describe "#initialize" do
4
+ describe "#name" do
5
+ it "is set from options key" do
6
+ options = { id: { type: UUID } }
7
+ HashAttribute.new(options).name.should == :id
8
+ end
9
+ end
10
+
11
+ describe "#type" do
12
+ it "is set from options" do
13
+ type = Integer
14
+ attribute = HashAttribute.new({ key_name: { type: type } })
15
+ attribute.type.should == type
16
+ end
17
+
18
+ it "is set from name hash" do
19
+ type = String
20
+ attribute = HashAttribute.new({ id: { type: UUID } })
21
+ attribute.type.should == UUID
22
+ end
23
+
24
+ it "determines type from string" do
25
+ HashAttribute.new({ key_name: { type: "string" } }).type.should == String
26
+ end
27
+ end
28
+
29
+ describe "#format" do
30
+ it "is set from options" do
31
+ HashAttribute.new({ key_name: { type: String, format: UUID } }).format.should == UUID
32
+ end
33
+
34
+ it "is nil for indeterminable types" do
35
+ HashAttribute.new({ key_name: { type: String, format: "random-iso-format" } }).format.should == nil
36
+ end
37
+ end
38
+
39
+ describe "#schema" do
40
+ it "is set to nil if its a regular attribute" do
41
+ HashAttribute.new({ id: { type: UUID } }).schema.should == nil
42
+ end
43
+
44
+ it "is initiazed from options" do
45
+ options = {
46
+ film: {
47
+ type: Object,
48
+ properties: {
49
+ year: { type: Integer }
50
+ }
51
+ }
52
+ }
53
+
54
+ schema = HashAttribute.new(options).schema
55
+ schema.title.should == :film
56
+ schema.type.should == Object
57
+ hash_attributes = schema.hash_attributes
58
+ hash_attributes.size.should == 1
59
+ attribute = hash_attributes.first
60
+ attribute.name.should == :year
61
+ attribute.type.should == Integer
62
+ end
63
+ end
64
+
65
+ context "enums" do
66
+ it "sets enum values" do
67
+ enum_values = ["foo", "bar", "baz"]
68
+ attribute = HashAttribute.new({ key: { type: String, enum: enum_values } })
69
+ attribute.enums.should == enum_values
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#serialize" do
75
+ it "returns attribute with its value" do
76
+ attribute = HashAttribute.new({ title: { type: String } })
77
+ title = "the title"
78
+ attribute.serialize(title).should == { title: title }
79
+ end
80
+
81
+ describe "nested schema" do
82
+ it "returns serialized schema" do
83
+ attribute = HashAttribute.new({ film: { type: Object, properties: { title: { type: String } } } })
84
+ title = "the title"
85
+ attribute.serialize({ title: title }).should == { film: { title: title } }
86
+ end
87
+ end
88
+
89
+ it "uses faux data when offline" do
90
+ type = [String, Integer].sample
91
+ Render.stub({ live: false })
92
+
93
+ data = HashAttribute.new({ title: { type: type } }).serialize(nil)
94
+ data[:title].should be_a(type)
95
+ end
96
+ end
97
+
98
+ describe "#value" do
99
+ context "offline mode" do
100
+ before(:all) do
101
+ @original_live = Render.live
102
+ Render.live = false
103
+ end
104
+
105
+ after(:all) do
106
+ Render.live = @original_live
107
+ end
108
+
109
+ it "generate value based on type" do
110
+ supported_classes = [
111
+ String,
112
+ Integer
113
+ ]
114
+
115
+ supported_classes.each do |klass|
116
+ HashAttribute.new({ key: { type: klass } }).default_value.should be_a(klass)
117
+ end
118
+ UUID.validate(HashAttribute.new({ key: { type: UUID } }).default_value).should be_true
119
+ end
120
+
121
+ it "generates value from enum" do
122
+ enums = ["horror", "comedy", "drama"]
123
+ attribute = HashAttribute.new({ genre: { enum: enums, type: String } })
124
+ enums.should include(attribute.default_value)
125
+ end
126
+ end
127
+ end
128
+
129
+ end
130
+ end