cfoundry 0.3.61 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,8 @@ module CFoundry::V2
6
6
  attribute :wildcard, :boolean, :default => true
7
7
  to_one :owning_organization, :as => :organization, :default => nil
8
8
 
9
+ queryable_by :name, :owning_organization_guid, :space_guid
10
+
9
11
  # hide wildcard support for now
10
12
  private :wildcard=
11
13
  end
@@ -6,6 +6,8 @@ module CFoundry::V2
6
6
  attribute :description, :string
7
7
  to_many :apps
8
8
 
9
+ queryable_by :name, :app_guid
10
+
9
11
  attr_accessor :detection, :runtimes
10
12
  end
11
13
  end
@@ -1,273 +1,11 @@
1
1
  require "multi_json"
2
2
 
3
- module CFoundry::V2
4
- class Model
5
- class << self
6
- attr_reader :scoped_organization, :scoped_space
7
-
8
- def value_matches?(val, type)
9
- case type
10
- when Class
11
- val.is_a?(type)
12
- when Regexp
13
- val.is_a?(String) && val =~ type
14
- when :url
15
- value_matches?(val, URI::regexp(%w(http https)))
16
- when :https_url
17
- value_matches?(val, URI::regexp("https"))
18
- when :boolean
19
- val.is_a?(TrueClass) || val.is_a?(FalseClass)
20
- when Array
21
- val.all? do |x|
22
- value_matches?(x, type.first)
23
- end
24
- when Hash
25
- val.is_a?(Hash) &&
26
- type.all? { |name, subtype|
27
- val.key?(name) && value_matches?(val[name], subtype)
28
- }
29
- else
30
- val.is_a?(Object.const_get(type.to_s.capitalize))
31
- end
32
- end
33
-
34
- def validate_type(val, type)
35
- unless value_matches?(val, type)
36
- raise CFoundry::Mismatch.new(type, val)
37
- end
38
- end
39
-
40
- def defaults
41
- @defaults ||= {}
42
- end
43
-
44
- def attributes
45
- @attributes ||= {}
46
- end
47
-
48
- def to_one_relations
49
- @to_one_relations ||= {}
50
- end
51
-
52
- def to_many_relations
53
- @to_many_relations ||= {}
54
- end
55
-
56
- def attribute(name, type, opts = {})
57
- attributes[name] = opts
58
-
59
- default = opts[:default]
60
-
61
- if has_default = opts.key?(:default)
62
- defaults[name] = default
63
- end
64
-
65
- define_method(name) do
66
- return @cache[name] if @cache.key?(name)
67
-
68
- @cache[name] = manifest[:entity][name] || default
69
- end
70
-
71
- define_method(:"#{name}=") do |val|
72
- unless has_default && val == default
73
- Model.validate_type(val, type)
74
- end
75
-
76
- @cache[name] = val
77
-
78
- @manifest ||= {}
79
- @manifest[:entity] ||= {}
80
- @manifest[:entity][name] = val
81
- @diff[name] = val
82
- end
83
- end
84
-
85
- def scoped_to_organization(relation = :organization)
86
- @scoped_organization = relation
87
- end
88
-
89
- def scoped_to_space(relation = :space)
90
- @scoped_space = relation
91
- end
92
-
93
- def to_one(name, opts = {})
94
- to_one_relations[name] = opts
95
-
96
- obj = opts[:as] || name
97
- kls = obj.to_s.capitalize.gsub(/(.)_(.)/) do
98
- $1 + $2.upcase
99
- end
100
-
101
- default = opts[:default]
102
-
103
- if has_default = opts.key?(:default)
104
- defaults[:"#{name}_guid"] = default
105
- end
106
-
107
- define_method(name) do
108
- return @cache[name] if @cache.key?(name)
109
-
110
- @cache[name] =
111
- if @manifest && @manifest[:entity].key?(name)
112
- @client.send(:"make_#{obj}", @manifest[:entity][name])
113
- elsif url = send("#{name}_url")
114
- @client.send(:"#{obj}_from", url, opts[:depth] || 1)
115
- else
116
- default
117
- end
118
- end
119
-
120
- define_method(:"#{name}_url") do
121
- manifest[:entity][:"#{name}_url"]
122
- end
123
-
124
- define_method(:"#{name}=") do |x|
125
- unless has_default && x == default
126
- Model.validate_type(x, CFoundry::V2.const_get(kls))
127
- end
128
-
129
- @cache[name] = x
130
-
131
- @manifest ||= {}
132
- @manifest[:entity] ||= {}
133
- @manifest[:entity][:"#{name}_guid"] =
134
- @diff[:"#{name}_guid"] = x && x.guid
135
- end
136
- end
3
+ require "cfoundry/v2/model_magic"
137
4
 
138
- def to_many(plural, opts = {})
139
- to_many_relations[plural] = opts
140
5
 
141
- singular = plural.to_s.sub(/s$/, "").to_sym
142
-
143
- object = opts[:as] || singular
144
- plural_object = :"#{object}s"
145
-
146
- kls = object.to_s.capitalize.gsub(/(.)_(.)/) do
147
- $1 + $2.upcase
148
- end
149
-
150
- define_method(plural) do |*args|
151
- depth, query = args
152
-
153
- if !depth && !query && cache = @cache[plural]
154
- return cache
155
- end
156
-
157
- if @manifest && @manifest[:entity].key?(plural) && !depth
158
- objs = @manifest[:entity][plural]
159
-
160
- if query
161
- find_by = query.keys.first
162
- find_val = query.values.first
163
- objs = objs.select { |o| o[:entity][find_by] == find_val }
164
- end
165
-
166
- res =
167
- objs.collect do |json|
168
- @client.send(:"make_#{object}", json)
169
- end
170
- else
171
- res =
172
- @client.send(
173
- :"#{plural_object}_from",
174
- "/v2/#{object_name}s/#@guid/#{plural}",
175
- depth || opts[:depth],
176
- query)
177
- end
178
-
179
- unless depth || query
180
- @cache[plural] = res
181
- end
182
-
183
- res
184
- end
185
-
186
- define_method(:"#{plural}_url") do
187
- manifest[:entity][:"#{plural}_url"]
188
- end
189
-
190
- define_method(:"add_#{singular}") do |x|
191
- Model.validate_type(x, CFoundry::V2.const_get(kls))
192
-
193
- if cache = @cache[plural]
194
- cache << x unless cache.include?(x)
195
- end
196
-
197
- @client.base.request_path(
198
- Net::HTTP::Put,
199
- ["v2", "#{object_name}s", @guid, plural, x.guid],
200
- :accept => :json)
201
- end
202
-
203
- define_method(:"remove_#{singular}") do |x|
204
- Model.validate_type(x, CFoundry::V2.const_get(kls))
205
-
206
- if cache = @cache[plural]
207
- cache.delete(x)
208
- end
209
-
210
- @client.base.request_path(
211
- Net::HTTP::Delete,
212
- ["v2", "#{object_name}s", @guid, plural, x.guid],
213
- :accept => :json)
214
- end
215
-
216
- define_method(:"#{plural}=") do |xs|
217
- Model.validate_type(xs, [CFoundry::V2.const_get(kls)])
218
-
219
- @cache[plural] = xs
220
-
221
- @manifest ||= {}
222
- @manifest[:entity] ||= {}
223
- @manifest[:entity][:"#{singular}_guids"] =
224
- @diff[:"#{singular}_guids"] = xs.collect(&:guid)
225
- end
226
- end
227
-
228
- def has_summary(actions = {})
229
- define_method(:summary) do
230
- @client.base.request_path(
231
- Net::HTTP::Get,
232
- ["v2", "#{object_name}s", @guid, "summary"],
233
- :accept => :json)
234
- end
235
-
236
- define_method(:summarize!) do |*args|
237
- body, _ = args
238
-
239
- body ||= summary
240
-
241
- body.each do |key, val|
242
- if act = actions[key]
243
- instance_exec(val, &act)
244
-
245
- elsif self.class.attributes[key]
246
- self.send(:"#{key}=", val)
247
-
248
- elsif self.class.to_many_relations[key]
249
- singular = key.to_s.sub(/s$/, "").to_sym
250
-
251
- vals = val.collect do |sub|
252
- obj = @client.send(singular, sub[:guid], true)
253
- obj.summarize! sub
254
- obj
255
- end
256
-
257
- self.send(:"#{key}=", vals)
258
-
259
- elsif self.class.to_one_relations[key]
260
- obj = @client.send(key, val[:guid], true)
261
- obj.summarize! val
262
-
263
- self.send(:"#{key}=", obj)
264
- end
265
- end
266
-
267
- nil
268
- end
269
- end
270
- end
6
+ module CFoundry::V2
7
+ class Model
8
+ extend ModelMagic
271
9
 
272
10
  attr_accessor :guid, :cache
273
11
 
@@ -293,10 +31,7 @@ module CFoundry::V2
293
31
  end
294
32
 
295
33
  def object_name
296
- @object_name ||=
297
- self.class.name.split("::").last.gsub(
298
- /([a-z])([A-Z])/,
299
- '\1_\2').downcase
34
+ @object_name ||= self.class.object_name
300
35
  end
301
36
 
302
37
  def invalidate!
@@ -372,6 +107,10 @@ module CFoundry::V2
372
107
  false
373
108
  end
374
109
 
110
+ def query_target(klass)
111
+ self
112
+ end
113
+
375
114
  def eql?(other)
376
115
  other.is_a?(self.class) && @guid == other.guid
377
116
  end
@@ -0,0 +1,434 @@
1
+ module CFoundry::V2
2
+ # object name -> module containing query methods
3
+ #
4
+ # e.g. app -> { app_by_name, app_by_space_guid, ... }
5
+ QUERIES = Hash.new do |h, k|
6
+ h[k] = Module.new
7
+ end
8
+
9
+ module BaseClientMethods
10
+ end
11
+
12
+ module ClientMethods
13
+ end
14
+
15
+ module ModelMagic
16
+ attr_reader :scoped_organization, :scoped_space
17
+
18
+ def object_name
19
+ @object_name ||=
20
+ name.split("::").last.gsub(
21
+ /([a-z])([A-Z])/,
22
+ '\1_\2').downcase.to_sym
23
+ end
24
+
25
+ def defaults
26
+ @defaults ||= {}
27
+ end
28
+
29
+ def attributes
30
+ @attributes ||= {}
31
+ end
32
+
33
+ def to_one_relations
34
+ @to_one_relations ||= {}
35
+ end
36
+
37
+ def to_many_relations
38
+ @to_many_relations ||= {}
39
+ end
40
+
41
+ def inherited(klass)
42
+ singular = klass.object_name
43
+ plural = :"#{singular}s"
44
+
45
+ BaseClientMethods.module_eval do
46
+ define_method(singular) do |guid, *args|
47
+ get("v2", plural, guid, :accept => :json,
48
+ :params => ModelMagic.params_from(args))
49
+ end
50
+
51
+ define_method(:"create_#{singular}") do |payload|
52
+ post(payload, "v2", plural, :content => :json, :accept => :json)
53
+ end
54
+
55
+ define_method(:"delete_#{singular}") do |guid|
56
+ delete("v2", plural, guid)
57
+ true
58
+ end
59
+
60
+ define_method(:"update_#{singular}") do |guid, payload|
61
+ put(payload, "v2", plural, guid, :content => :json, :accept => :json)
62
+ end
63
+
64
+ define_method(plural) do |*args|
65
+ all_pages(
66
+ get("v2", plural, :accept => :json,
67
+ :params => ModelMagic.params_from(args)))
68
+ end
69
+ end
70
+
71
+ ClientMethods.module_eval do
72
+ define_method(singular) do |*args|
73
+ guid, partial, _ = args
74
+
75
+ x = klass.new(guid, self, nil, partial)
76
+
77
+ # when creating an object, automatically set the org/space
78
+ unless guid
79
+ if klass.scoped_organization && current_organization
80
+ x.send(:"#{klass.scoped_organization}=", current_organization)
81
+ end
82
+
83
+ if klass.scoped_space && current_space
84
+ x.send(:"#{klass.scoped_space}=", current_space)
85
+ end
86
+ end
87
+
88
+ x
89
+ end
90
+
91
+ define_method(plural) do |*args|
92
+ # use current org/space
93
+ if klass.scoped_space && current_space
94
+ current_space.send(plural, *args)
95
+ elsif klass.scoped_organization && current_organization
96
+ current_organization.send(plural, *args)
97
+ else
98
+ @base.send(plural, *args).collect do |json|
99
+ send(:"make_#{singular}", json)
100
+ end
101
+ end
102
+ end
103
+
104
+ define_method(:"#{singular}_from") do |path, *args|
105
+ send(
106
+ :"make_#{singular}",
107
+ @base.request_path(
108
+ Net::HTTP::Get,
109
+ path,
110
+ :accept => :json,
111
+ :params => ModelMagic.params_from(args)))
112
+ end
113
+
114
+ define_method(:"#{plural}_from") do |path, *args|
115
+ objs = @base.all_pages(
116
+ @base.request_path(
117
+ Net::HTTP::Get,
118
+ path,
119
+ :accept => :json,
120
+ :params => ModelMagic.params_from(args)))
121
+
122
+ objs.collect do |json|
123
+ send(:"make_#{singular}", json)
124
+ end
125
+ end
126
+
127
+ define_method(:"make_#{singular}") do |json|
128
+ klass.new(
129
+ json[:metadata][:guid],
130
+ self,
131
+ json)
132
+ end
133
+ end
134
+ end
135
+
136
+ def attribute(name, type, opts = {})
137
+ attributes[name] = opts
138
+
139
+ default = opts[:default]
140
+
141
+ if has_default = opts.key?(:default)
142
+ defaults[name] = default
143
+ end
144
+
145
+ define_method(name) do
146
+ return @cache[name] if @cache.key?(name)
147
+
148
+ @cache[name] = manifest[:entity][name] || default
149
+ end
150
+
151
+ define_method(:"#{name}=") do |val|
152
+ unless has_default && val == default
153
+ ModelMagic.validate_type(val, type)
154
+ end
155
+
156
+ @cache[name] = val
157
+
158
+ @manifest ||= {}
159
+ @manifest[:entity] ||= {}
160
+ @manifest[:entity][name] = val
161
+ @diff[name] = val
162
+ end
163
+ end
164
+
165
+ def scoped_to_organization(relation = :organization)
166
+ @scoped_organization = relation
167
+ end
168
+
169
+ def scoped_to_space(relation = :space)
170
+ @scoped_space = relation
171
+ end
172
+
173
+ def to_one(name, opts = {})
174
+ to_one_relations[name] = opts
175
+
176
+ obj = opts[:as] || name
177
+ kls = obj.to_s.capitalize.gsub(/(.)_(.)/) do
178
+ $1 + $2.upcase
179
+ end
180
+
181
+ default = opts[:default]
182
+
183
+ if has_default = opts.key?(:default)
184
+ defaults[:"#{name}_guid"] = default
185
+ end
186
+
187
+ define_method(name) do
188
+ return @cache[name] if @cache.key?(name)
189
+
190
+ @cache[name] =
191
+ if @manifest && @manifest[:entity].key?(name)
192
+ @client.send(:"make_#{obj}", @manifest[:entity][name])
193
+ elsif url = send("#{name}_url")
194
+ @client.send(:"#{obj}_from", url)
195
+ else
196
+ default
197
+ end
198
+ end
199
+
200
+ define_method(:"#{name}_url") do
201
+ manifest[:entity][:"#{name}_url"]
202
+ end
203
+
204
+ define_method(:"#{name}=") do |x|
205
+ unless has_default && x == default
206
+ ModelMagic.validate_type(x, CFoundry::V2.const_get(kls))
207
+ end
208
+
209
+ @cache[name] = x
210
+
211
+ @manifest ||= {}
212
+ @manifest[:entity] ||= {}
213
+ @manifest[:entity][:"#{name}_guid"] =
214
+ @diff[:"#{name}_guid"] = x && x.guid
215
+ end
216
+ end
217
+
218
+ def to_many(plural, opts = {})
219
+ to_many_relations[plural] = opts
220
+
221
+ singular = plural.to_s.sub(/s$/, "").to_sym
222
+
223
+ include QUERIES[singular]
224
+
225
+ object = opts[:as] || singular
226
+ plural_object = :"#{object}s"
227
+
228
+ kls = object.to_s.capitalize.gsub(/(.)_(.)/) do
229
+ $1 + $2.upcase
230
+ end
231
+
232
+ define_method(plural) do |*args|
233
+ opts, _ = args
234
+ opts ||= {}
235
+
236
+ if opts.empty? && cache = @cache[plural]
237
+ return cache
238
+ end
239
+
240
+ if @manifest && @manifest[:entity].key?(plural) && opts.empty?
241
+ objs = @manifest[:entity][plural]
242
+
243
+ if query = opts[:query]
244
+ find_by, find_val = query
245
+ objs = objs.select { |o| o[:entity][find_by] == find_val }
246
+ end
247
+
248
+ res =
249
+ objs.collect do |json|
250
+ @client.send(:"make_#{object}", json)
251
+ end
252
+ else
253
+ res =
254
+ @client.send(
255
+ :"#{plural_object}_from",
256
+ "/v2/#{object_name}s/#@guid/#{plural}",
257
+ opts)
258
+ end
259
+
260
+ if opts.empty?
261
+ @cache[plural] = res
262
+ end
263
+
264
+ res
265
+ end
266
+
267
+ define_method(:"#{plural}_url") do
268
+ manifest[:entity][:"#{plural}_url"]
269
+ end
270
+
271
+ define_method(:"add_#{singular}") do |x|
272
+ ModelMagic.validate_type(x, CFoundry::V2.const_get(kls))
273
+
274
+ if cache = @cache[plural]
275
+ cache << x unless cache.include?(x)
276
+ end
277
+
278
+ @client.base.request_path(
279
+ Net::HTTP::Put,
280
+ ["v2", "#{object_name}s", @guid, plural, x.guid],
281
+ :accept => :json)
282
+ end
283
+
284
+ define_method(:"remove_#{singular}") do |x|
285
+ ModelMagic.validate_type(x, CFoundry::V2.const_get(kls))
286
+
287
+ if cache = @cache[plural]
288
+ cache.delete(x)
289
+ end
290
+
291
+ @client.base.request_path(
292
+ Net::HTTP::Delete,
293
+ ["v2", "#{object_name}s", @guid, plural, x.guid],
294
+ :accept => :json)
295
+ end
296
+
297
+ define_method(:"#{plural}=") do |xs|
298
+ ModelMagic.validate_type(xs, [CFoundry::V2.const_get(kls)])
299
+
300
+ @cache[plural] = xs
301
+
302
+ @manifest ||= {}
303
+ @manifest[:entity] ||= {}
304
+ @manifest[:entity][:"#{singular}_guids"] =
305
+ @diff[:"#{singular}_guids"] = xs.collect(&:guid)
306
+ end
307
+ end
308
+
309
+ def has_summary(actions = {})
310
+ define_method(:summary) do
311
+ @client.base.request_path(
312
+ Net::HTTP::Get,
313
+ ["v2", "#{object_name}s", @guid, "summary"],
314
+ :accept => :json)
315
+ end
316
+
317
+ define_method(:summarize!) do |*args|
318
+ body, _ = args
319
+
320
+ body ||= summary
321
+
322
+ body.each do |key, val|
323
+ if act = actions[key]
324
+ instance_exec(val, &act)
325
+
326
+ elsif self.class.attributes[key]
327
+ self.send(:"#{key}=", val)
328
+
329
+ elsif self.class.to_many_relations[key]
330
+ singular = key.to_s.sub(/s$/, "").to_sym
331
+
332
+ vals = val.collect do |sub|
333
+ obj = @client.send(singular, sub[:guid], true)
334
+ obj.summarize! sub
335
+ obj
336
+ end
337
+
338
+ self.send(:"#{key}=", vals)
339
+
340
+ elsif self.class.to_one_relations[key]
341
+ obj = @client.send(key, val[:guid], true)
342
+ obj.summarize! val
343
+
344
+ self.send(:"#{key}=", obj)
345
+ end
346
+ end
347
+
348
+ nil
349
+ end
350
+ end
351
+
352
+ def queryable_by(*names)
353
+ klass = self
354
+ singular = object_name
355
+ plural = :"#{singular}s"
356
+
357
+ query = QUERIES[singular]
358
+
359
+ query.module_eval do
360
+ names.each do |name|
361
+ define_method(:"#{singular}_by_#{name}") do |*args|
362
+ send(:"#{plural}_by_#{name}", *args).first
363
+ end
364
+
365
+ define_method(:"#{plural}_by_#{name}") do |val, *args|
366
+ options, _ = args
367
+ options ||= {}
368
+ options[:query] = [name, val]
369
+
370
+ query_target(klass).send(plural, options)
371
+ end
372
+ end
373
+ end
374
+
375
+ const_set(:Queries, query)
376
+
377
+ ClientMethods.module_eval do
378
+ include query
379
+ end
380
+ end
381
+
382
+ class << self
383
+ def value_matches?(val, type)
384
+ case type
385
+ when Class
386
+ val.is_a?(type)
387
+ when Regexp
388
+ val.is_a?(String) && val =~ type
389
+ when :url
390
+ value_matches?(val, URI::regexp(%w(http https)))
391
+ when :https_url
392
+ value_matches?(val, URI::regexp("https"))
393
+ when :boolean
394
+ val.is_a?(TrueClass) || val.is_a?(FalseClass)
395
+ when Array
396
+ val.all? do |x|
397
+ value_matches?(x, type.first)
398
+ end
399
+ when Hash
400
+ val.is_a?(Hash) &&
401
+ type.all? { |name, subtype|
402
+ val.key?(name) && value_matches?(val[name], subtype)
403
+ }
404
+ else
405
+ val.is_a?(Object.const_get(type.to_s.capitalize))
406
+ end
407
+ end
408
+
409
+ def validate_type(val, type)
410
+ unless value_matches?(val, type)
411
+ raise CFoundry::Mismatch.new(type, val)
412
+ end
413
+ end
414
+
415
+ def params_from(args)
416
+ options, _ = args
417
+ options ||= {}
418
+ options[:depth] ||= 1
419
+
420
+ params = {}
421
+ options.each do |k, v|
422
+ case k
423
+ when :depth
424
+ params[:"inline-relations-depth"] = v
425
+ when :query
426
+ params[:q] = v.join(":")
427
+ end
428
+ end
429
+
430
+ params
431
+ end
432
+ end
433
+ end
434
+ end