cfoundry 0.3.61 → 0.4.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.
@@ -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