spire_io 1.0.0.alpha.2 → 1.0.0.alpha.5

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 (3) hide show
  1. data/lib/spire_io.rb +149 -485
  2. metadata +4 -5
  3. data/lib/requestable.rb +0 -70
data/lib/spire_io.rb CHANGED
@@ -1,205 +1,25 @@
1
+ require "delegate"
1
2
  gem "excon"
2
3
  require "excon"
3
4
  gem "json"
4
5
  require "json"
5
6
 
6
- require "requestable"
7
+ require "spire/api"
7
8
 
8
9
  class Spire
9
10
 
10
11
  #How many times we will try to create a channel or subscription after getting a 409
11
12
  RETRY_CREATION_LIMIT = 3
12
13
 
13
- include Requestable
14
-
15
- define_request(:discover) do
16
- {
17
- :method => :get,
18
- :url => @url,
19
- :headers => {"Accept" => "application/json"}
20
- }
21
- end
22
-
23
- define_request(:start) do |key|
24
- {
25
- :method => :post,
26
- :url => @description["resources"]["sessions"]["url"],
27
- :body => {:key => key}.to_json,
28
- :headers => {
29
- "Accept" => mediaType("session"),
30
- "Content-Type" => mediaType("account")
31
- }
32
- }
33
- end
34
-
35
- define_request(:login) do |email, password|
36
- {
37
- :method => :post,
38
- :url => @description["resources"]["sessions"]["url"],
39
- :body => { :email => email, :password => password }.to_json,
40
- :headers => {
41
- "Accept" => mediaType("session"),
42
- "Content-Type" => mediaType("account")
43
- }
44
- }
45
- end
46
-
47
- define_request(:register) do |info|
48
- {
49
- :method => :post,
50
- :url => @description["resources"]["accounts"]["url"],
51
- :body => {
52
- :email => info[:email],
53
- :password => info[:password],
54
- :password_confirmation => info[:password_confirmation]
55
- }.to_json,
56
- :headers => {
57
- "Accept" => mediaType("session"),
58
- "Content-Type" => mediaType("account")
59
- }
60
- }
61
- end
62
-
63
- define_request(:session) do
64
- {
65
- :method => :get,
66
- :url => @session["url"],
67
- :headers => {
68
- "Accept" => mediaType("session"),
69
- "Authorization" => "Capability #{@session["capability"]}"
70
- }
71
- }
72
- end
73
-
74
- define_request(:password_reset) do |email|
75
- {
76
- :method => :post,
77
- :url => @description["resources"]["accounts"]["url"],
78
- :body => ""
79
- }
80
- end
81
-
82
- define_request(:delete_account) do
83
- {
84
- :method => :delete,
85
- :url => @resources["account"]["url"],
86
- :headers => {
87
- "Accept" => mediaType("account"),"Content-Type" => mediaType("account"),
88
- "Authorization" =>
89
- "Capability #{@resources["account"]["capability"]}"
90
- }
91
- }
92
- end
93
-
94
- define_request(:update_account) do |info|
95
- {
96
- :method => :put,
97
- :url => @resources["account"]["url"],
98
- :body => info.to_json,
99
- :headers => {
100
- "Accept" => mediaType("account"),"Content-Type" => mediaType("account"),
101
- "Authorization" => "Capability #{@resources["account"]["capability"]}"
102
- }
103
- }
104
- end
105
-
106
- define_request(:create_channel) do |name|
107
- {
108
- :method => :post,
109
- :url => @resources["channels"]["url"],
110
- :body => { :name => name }.to_json,
111
- :headers => {
112
- "Authorization" =>
113
- "Capability #{@resources["channels"]["capability"]}",
114
- "Accept" => mediaType("channel"),
115
- "Content-Type" => mediaType("channel")
116
- }
117
- }
118
- end
119
-
120
- define_request(:channels) do
121
- {
122
- :method => :get,
123
- :url => @resources["channels"]["url"],
124
- :headers => {
125
- "Authorization" =>
126
- "Capability #{@resources["channels"]["capability"]}",
127
- "Accept" => mediaType("channels"),
128
- }
129
- }
130
- end
131
-
132
- define_request(:subscribe) do |subscription_name, channels|
133
- {
134
- :method => :post,
135
- :url => @resources["subscriptions"]["url"],
136
- :body => {
137
- :channels => channels.flatten.map { |name| self[name].url },
138
- :name => subscription_name
139
- }.to_json,
140
- :headers => {
141
- "Authorization" => "Capability #{@resources["subscriptions"]["capability"]}",
142
- "Accept" => mediaType("subscription"),
143
- "Content-Type" => mediaType("subscription")
144
- }
145
- }
146
- end
147
-
148
- define_request(:billing) do
149
- {
150
- :method => :get,
151
- :url => @description["resources"]["billing"]["url"],
152
- :headers => {
153
- "Accept" => "application/json"
154
- }
155
- }
156
- end
157
-
158
- define_request(:billing_subscription) do |info|
159
- {
160
- :method => :put,
161
- :url => @resources["account"]["billing"]["url"],
162
- :body => info.to_json,
163
- :headers => {
164
- "Accept" => mediaType("account"),"Content-Type" => mediaType("account"),
165
- "Authorization" => "Capability #{@resources["account"]["billing"]["capability"]}"
166
- }
167
- }
168
- end
169
-
170
- define_request(:billing_invoices) do
171
- {
172
- :method => :get,
173
- :url => @resources["account"]["billing"]["invoices"]["url"],
174
- :headers => {
175
- "Accept" => "application/json",
176
- "Authorization" => "Capability #{@resources["account"]["billing"]["invoices"]["capability"]}"
177
- }
178
- }
179
- end
180
-
181
- define_request(:billing_invoices_upcoming) do
182
- {
183
- :method => :get,
184
- :url => @resources["account"]["billing"]["invoices"]["upcoming"]["url"],
185
- :headers => {
186
- "Accept" => "application/json",
187
- "Authorization" => "Capability #{@resources["account"]["billing"]["invoices"]["upcoming"]["capability"]}"
188
- }
189
- }
190
- end
191
-
192
- attr_accessor :client, :channels, :session, :resources
14
+ attr_accessor :api, :session, :resources
193
15
 
194
16
  def initialize(url="https://api.spire.io")
195
- @client = Excon
17
+ @api = Spire::API.new(url)
196
18
  @url = url
197
19
  @channels = {}
198
20
  @subscriptions = {}
199
21
  @channel_error_counts = {}
200
22
  @subscription_error_counts = {}
201
- # @headers = { "User-Agent" => "Ruby spire.io client" }
202
- # @timeout = 1
203
23
  discover
204
24
  end
205
25
 
@@ -212,25 +32,18 @@ class Spire
212
32
  end
213
33
 
214
34
  def discover
215
- response = request(:discover)
216
- raise "Error during discovery: #{response.status}" if response.status != 200
217
- @description = JSON.parse(response.body)
218
- #pp @description["schema"]["1.0"]
35
+ @api.discover
219
36
  self
220
37
  end
221
38
 
222
39
  def start(key)
223
- response = request(:start, key)
224
- raise "Error starting a key-based session" if response.status != 201
225
- cache_session(JSON.parse(response.body))
40
+ @session = @api.create_session(key)
226
41
  self
227
42
  end
228
43
 
229
44
  # Authenticates a session using a login and password
230
45
  def login(login, password)
231
- response = request(:login, login, password)
232
- raise "Error attemping to login: (#{response.status}) #{response.body}" if response.status != 201
233
- cache_session(JSON.parse(response.body))
46
+ @session = @api.login(login, password)
234
47
  self
235
48
  end
236
49
 
@@ -239,12 +52,14 @@ class Spire
239
52
  # @param [String] :password Password of new account
240
53
  # @param [String] :password_confirmation Password confirmation (optional)
241
54
  def register(info)
242
- response = request(:register, info)
243
- raise "Error attempting to register: (#{response.status}) #{response.body}" if response.status != 201
244
- cache_session(JSON.parse(response.body))
55
+ @session = @api.create_account(info)
245
56
  self
246
57
  end
247
58
 
59
+ def key
60
+ @session.resources["account"]["key"]
61
+ end
62
+
248
63
  def password_reset_request(email)
249
64
  response = request(:password_reset)
250
65
  unless response.status == 202
@@ -256,15 +71,16 @@ class Spire
256
71
 
257
72
  # Deletes the currently authenticated account
258
73
  def delete_account
259
- request(:delete_account)
74
+ @session.account.delete
260
75
  end
261
76
 
262
77
  # Updates the current account with the new account information
263
78
  # See Spire docs for available settings
264
79
  def update(info)
265
- response = request(:update_account, info)
266
- raise "Error attempting to update account: (#{response.status}) #{response.body}" if response.status != 200
267
- @resources["account"] = JSON.parse(response.body)
80
+ @session.account.update(info)
81
+ #response = request(:update_account, info)
82
+ #raise "Error attempting to update account: (#{response.status}) #{response.body}" if response.status != 200
83
+ #@resources["account"] = JSON.parse(response.body)
268
84
  self
269
85
  end
270
86
 
@@ -308,152 +124,120 @@ class Spire
308
124
  # @param [String] name Name of channel returned
309
125
  # @return [Channel]
310
126
  def [](name)
311
- return @channels[name] if @channels[name]
312
- create_channel(name)
127
+ Channel.new(self, channels[name] || find_or_create_channel(name))
128
+ end
129
+
130
+ def channels
131
+ @session.channels
313
132
  end
314
133
 
315
134
  # Creates a channel on spire. Returns a Channel object. Note that this will
316
135
  # fail with a 409 if a channel with the same name exists.
317
- def create_channel(name)
136
+ def find_or_create_channel(name)
318
137
  @channel_error_counts[name] ||= 0
319
- response = request(:create_channel, name)
320
- return find_existing_channel(name) if response.status == 409 and @channel_error_counts[name] < RETRY_CREATION_LIMIT
321
- if !(response.status == 201 || response.status == 200)
322
- raise "Error creating or accessing a channel: (#{response.status}) #{response.body}"
138
+
139
+ begin
140
+ return @session.create_channel(name)
141
+ # TODO custom error class for Conflict, which we can
142
+ # then match here, instead of testing for error message
143
+ rescue => error
144
+ if error.message =~ /409/
145
+
146
+ # Dear retry, I love you. Affectionately, Matthew.
147
+ if channel = @session.channels![name]
148
+ return channel
149
+ else
150
+ @channel_error_counts[name] += 1
151
+ retry unless @channel_error_counts >= RETRY_CREATION_LIMIT
152
+ end
153
+
154
+ else
155
+ raise error
156
+ end
323
157
  end
324
- new_channel = Channel.new(self,JSON.parse(response.body))
325
- @channels[name] = new_channel
326
- new_channel
327
158
  end
328
159
 
329
- def find_existing_channel(name)
330
- @channel_error_counts[name] += 1
331
- retrieve_session
332
- self[name]
333
- end
334
-
335
160
  # Returns a subscription object for the given channels
336
161
  # @param [String] subscription_name Name for the subscription
337
162
  # @param [String] channels One or more channel names for the subscription to listen on
338
163
  # @return [Subscription]
339
- def subscribe(subscription_name, *channels)
164
+ def subscribe(name, *channels)
165
+ channels.each { |channel| self.find_or_create_channel(channel) }
166
+ Subscription.new(
167
+ @session.subscriptions[name] || find_or_create_subscription(name, *channels)
168
+ )
169
+ end
170
+
171
+ def find_or_create_subscription(subscription_name, *channels)
340
172
  @subscription_error_counts[subscription_name] ||= 0
341
- return @subscriptions[subscription_name] if subscription_name and @subscriptions[subscription_name]
342
- response = request(:subscribe, subscription_name, channels)
343
- return find_existing_subscription(subscription_name, channels) if response.status == 409 and
344
- @subscription_error_counts[subscription_name] < RETRY_CREATION_LIMIT
345
- raise "Error creating a subscription: (#{response.status}) #{response.body}" if !(response.status == 201 || response.status == 200)
346
- s = Subscription.new(self,JSON.parse(response.body))
347
- @subscriptions[s.name] = s
348
- s
173
+ begin
174
+ return @session.create_subscription(subscription_name, channels)
175
+ rescue => error
176
+ if error.message =~ /409/
177
+
178
+ if subscription = @session.subscriptions![subscription_name]
179
+ return subscription
180
+ else
181
+ retry unless @subscription_error_counts >= RETRY_CREATION_LIMIT
182
+ end
183
+
184
+ else
185
+ raise error
186
+ end
187
+ end
349
188
  end
189
+
350
190
  alias :subscription :subscribe #For compatibility with other clients
351
191
 
352
- def find_existing_subscription(name, channels)
353
- @subscription_error_counts[name] += 1
354
- retrieve_session
355
- self.subscribe(name, *channels)
192
+ #Returns an array of subscription objects for all of this account's subscriptions
193
+ #@return [Array]
194
+ def subscriptions
195
+ @session.subscriptions.values
356
196
  end
357
197
 
358
198
  # Returns a billing object than contains a list of all the plans available
359
199
  # @param [String] info optional object description
360
200
  # @return [Billing]
361
- def billing(info=nil)
362
- response = request(:billing)
363
- raise "Error getting billing plans: #{response.status}" if response.status != 200
364
- Billing.new(self,JSON.parse(response.body))
201
+ def billing
202
+ @api.billing
365
203
  end
366
204
 
367
205
  # Updates and subscribe the account to a billing plan
368
206
  # @param [Object] info data containing billing description
369
207
  # @return [Account]
370
208
  def billing_subscription(info)
371
- response = request(:billing_subscription)
372
- raise "Error attempting to update account billing: (#{response.status}) #{response.body}" if response.status != 200
373
- @resources["account"] = JSON.parse(response.body)
374
- self
209
+ @session.account.billing_subscription(info)
210
+ #response = request(:billing_subscription)
211
+ #raise "Error attempting to update account billing: (#{response.status}) #{response.body}" if response.status != 200
212
+ #@resources["account"] = JSON.parse(response.body)
213
+ #self
375
214
  end
376
215
 
377
-
216
+
378
217
  # Object representing a Spire channel
379
218
  #
380
219
  # You can get a channel object by calling [] on a Spire object
381
220
  # * spire = Spire.new
382
221
  # * spire.start("your api key")
383
222
  # * channel = spire["channel name"]
384
- class Channel
385
- include Requestable
386
-
387
- define_request(:publish) do |body|
388
- {
389
- :method => :post,
390
- :url => url,
391
- :body => body,
392
- :headers => {
393
- "Authorization" => "Capability #{@properties["capability"]}",
394
- "Accept" => mediaType("message"),
395
- "Content-Type" => mediaType("message")
396
- }
397
- }
398
- end
399
-
400
- define_request(:delete) do
401
- {
402
- :method => :delete,
403
- :url => url,
404
- :headers => {
405
- "Authorization" => "Capability #{capability}"
406
- }
407
- }
408
- end
409
-
410
- def initialize(spire, properties)
223
+ class Channel < SimpleDelegator
224
+ def initialize(spire, channel)
225
+ super(channel)
411
226
  @spire = spire
412
- @client = spire.client
413
- @properties = properties
414
- end
415
-
416
- def url
417
- @properties["url"]
418
- end
419
-
420
- def key
421
- @properties["key"]
422
- end
423
-
424
- def name
425
- @properties["name"]
426
- end
427
-
428
- def capability
429
- @properties["capability"]
430
- end
431
-
432
- def delete
433
- response = request(:delete)
434
- raise "Error deleting a channel" if response.status != 204
435
227
  end
436
-
437
228
  # Obtain a subscription for the channel
438
229
  # @param [String] subscription_name Name of the subscription
439
230
  # @return [Subscription]
440
231
  def subscribe(subscription_name = nil)
441
- @spire.subscribe(subscription_name, self.name)
442
- end
443
-
444
- #Publishes a message to the channel
445
- # @param [String] message Message to be posted
446
- # @return [Hash] response from the server
447
- def publish(message)
448
- response = request(:publish, {:content => message}.to_json)
449
- raise "Error publishing a message: (#{response.status}) #{response.body}" if response.status != 201
450
- JSON.parse(response.body)
232
+ @spire.subscribe(subscription_name, properties["name"])
451
233
  end
452
234
 
453
- def mediaType(name)
454
- @spire.mediaType(name)
235
+ # this is required because Delegator's method_missing relies
236
+ # on the object having a method defined, but in this case
237
+ # the API::Channel is also using method_missing
238
+ def name
239
+ __getobj__.name
455
240
  end
456
-
457
241
  end
458
242
 
459
243
  # The subscription class represents a read connection to a Spire channel
@@ -468,214 +252,94 @@ class Spire
468
252
  # *OR*
469
253
  # * channel = spire["channel name"]
470
254
  # * subscription = channel.subscribe("subscription name")
471
- class Subscription
472
- include Requestable
473
-
474
- define_request(:listen) do |options|
475
- timeout = options[:timeout]||30
476
- delay = options[:delay]||0
477
- order_by = options[:order_by]||'desc'
478
- {
479
- :method => :get,
480
- :url => @properties["url"],
481
- :query => {
482
- "timeout" => timeout,
483
- "last-message" => @last||'0',
484
- "order-by" => order_by,
485
- "delay" => delay
486
- },
487
- :headers => {
488
- "Authorization" => "Capability #{@properties["capability"]}",
489
- "Accept" => mediaType("events")
490
- }
491
- }
492
- end
493
-
494
- define_request(:delete) do
495
- {
496
- :method => :delete,
497
- :url => url,
498
- :headers => {
499
- "Authorization" => "Capability #{capability}"
500
- }
501
- }
502
- end
503
-
504
- attr_accessor :messages, :last
505
-
506
- def initialize(spire,properties)
507
- @spire = spire
508
- @client = spire.client
509
- @properties = properties
510
- @messages = []
511
- @listening_thread = nil
512
- @listeners = {}
513
- @listening_threads = {}
514
- @listener_mutex = Mutex.new
515
- @listener_thread_mutex = Mutex.new
516
- end
517
-
518
- def key
519
- @properties["key"]
520
- end
255
+ class Subscription < SimpleDelegator
521
256
 
257
+ # this is required because Delegator's method_missing relies
258
+ # on the object having a method defined, but in this case
259
+ # the API::Subscription is also using method_missing
522
260
  def name
523
- @properties["name"]
524
- end
525
-
526
- def capability
527
- @properties["capability"]
261
+ __getobj__.name
528
262
  end
529
263
 
530
- def url
531
- @properties["url"]
532
- end
533
-
534
- def delete
535
- response = request(:delete)
536
- raise "Error deleting a subscription" if response.status != 204
264
+ # misnamed method, here for backompat. Should be something like #get_messages,
265
+ # because it only makes one request.
266
+ def listen(options={})
267
+ long_poll(options).map {|message| message["content"] }
537
268
  end
538
269
 
539
- # Adds a listener (ruby block) to be called each time a message is received on the channel
540
- #
541
- # You must call #start_listening to actually start listening for messages
542
- # @note Listeners are executed in their own thread, so practice proper thread safety!
543
- # @param [String] name Name for the listener. One will be generated if not provided
544
- # @return [String] Name of the listener
545
- def add_listener(listener_name = nil, &block)
546
- @listener_mutex.synchronize do
547
- while !listener_name
548
- new_name = "Listener-#{rand(9999999)}"
549
- listener_name = new_name unless @listeners.has_key?(new_name)
550
- end
551
- @listeners[listener_name] = block
552
- end
553
- listener_name
270
+ # wraps the underlying Subscription#add_listener to
271
+ # provided named listeners, threading, and a
272
+ # stop_listening method.
273
+ def add_listener(name=nil, &block)
274
+ raise ArgumentError unless block_given?
275
+ name ||= generate_listener_name
276
+ listener = wrap_listener(&block)
277
+ listeners[name] = listener
278
+ __getobj__.add_listener(&listener)
554
279
  end
555
280
 
556
- # Removes a listener by name
557
- #
558
- # @param [String] name Name of the listener to remove
559
- # @param [Boolean] kill_current_threads Kill any currently running threads of the removed listener
560
- # @return [Proc] Listener that was removed
561
- def remove_listener(name, kill_current_threads = true)
562
- l = nil #scope
563
- @listener_mutex.synchronize do
564
- l = @listeners.delete(name)
281
+ def remove_listener(listener)
282
+ if listener.is_a? String
283
+ listener = listeners[listener]
565
284
  end
566
- kill_listening_threads(name) if kill_current_threads
567
- l
285
+ __getobj__.listeners.delete(listener)
568
286
  end
569
287
 
570
- # Removes all current listeners
571
- # @param [Boolean] kill_current_threads Kill any currently running threads of the removed listener.
572
- def remove_all_listeners(kill_current_threads = true)
573
- @listener_mutex.synchronize do
574
- @listeners = {}
288
+ def wrap_listener(&block)
289
+ lambda do |message|
290
+ Thread.new do
291
+ # Messages received after a call to stop_listening
292
+ # will not be processed.
293
+ yield message["content"] if @listening
294
+ end
575
295
  end
576
- kill_listening_threads if kill_current_threads
577
- true
578
296
  end
579
297
 
580
- # Starts the listening thread. This must be called to enable any listeners you have added.
581
- #
582
- # You can continue to add more listeners after starting the listening process
583
- # @note Will raise an exception if listening has already been started
584
- def start_listening
585
- raise "Already listening" if @listening_thread
586
- @listening_thread = Thread.new {
587
- while true
588
- new_messages = self.listen
589
- next unless new_messages.size > 0
590
- current_listeners.each do |name, listener|
591
- new_messages.each do |m|
592
- thread = Thread.new {
593
- begin
594
- listener.call(m)
595
- rescue
596
- puts "Error while running listener #{name}: #{$!.inspect}"
597
- puts $!.backtrace.join("\n")
598
- end
599
- }
600
- @listener_thread_mutex.synchronize do
601
- @listening_threads[name] ||= []
602
- @listening_threads[name] << thread
603
- end
604
- end
605
- end
606
- end
607
- }
298
+ def listeners
299
+ @listeners ||= {}
608
300
  end
609
301
 
610
- # Stops the listening process
611
- # @param [Boolean] kill_current_threads Kills any currently running listener threads
612
- def stop_listening(kill_current_threads = true)
613
- @listener_thread_mutex.synchronize do
614
- @listening_thread.kill if @listening_thread
615
- @listening_thread = nil
616
- end
617
- kill_listening_threads if kill_current_threads
618
- end
619
-
620
- # Kills any currently executing listeners
621
- # @param [String] name_to_kill Kill only currently executing listeners that have this name
622
- def kill_listening_threads(name_to_kill = nil)
623
- @listener_thread_mutex.synchronize do
624
- @listening_threads.each do |name, threads|
625
- next if name_to_kill and name_to_kill != name
626
- threads.each {|t| t.kill }
627
- @listening_threads[name] = []
628
- end
302
+ def generate_listener_name
303
+ listener_name = nil
304
+ while !listener_name
305
+ new_name = "Listener-#{rand(9999999)}"
306
+ listener_name = new_name unless listeners.has_key?(new_name)
629
307
  end
308
+ listener_name
630
309
  end
631
310
 
632
- # Listen (and block) for any new incoming messages.
633
- # @params [Hash] A hash of containing:
634
- # [Integer] timeout Max time to wait for a new message before returning
635
- # [String] order_by Either "desc" or "asc"
636
- # @return [Array] An array of messages received
637
- def listen(options={})
638
- response = request(:listen, options)
639
- raise "Error listening for messages: (#{response.status}) #{response.body}" if response.status != 200
640
- new_messages = JSON.parse(response.body)["messages"]
641
- @listener_mutex.synchronize do
642
- @last = new_messages.last["timestamp"] unless new_messages.empty?
643
- new_messages.map! { |m| m["content"] }
644
- @messages += new_messages
311
+ def start_listening(options={})
312
+ @listening = true
313
+ Thread.new do
314
+ long_poll(options) while @listening
645
315
  end
646
- new_messages
647
316
  end
648
317
 
649
- def mediaType(name)
650
- @spire.mediaType(name)
318
+ def stop_listening
319
+ @listening = false
651
320
  end
652
321
 
653
- private
654
- def current_listeners
655
- @listener_mutex.synchronize do #To prevent synch problems adding a new listener while looping
656
- @listeners.dup
657
- end
658
- end
659
322
  end
660
323
 
661
- # Object representing a Spire billing
662
- #
663
- # You can get all the billing plans by calling the method billing in Spire object
664
- # * spire = Spire.new
665
- # * billing = spire.billing()
666
- # * plans = billing.plans
667
- class Billing
668
- def initialize(spire,properties)
669
- @spire = spire
670
- @properties = properties
671
- end
324
+
325
+ ## Object representing a Spire billing
326
+ ##
327
+ ## You can get all the billing plans by calling the method billing in Spire object
328
+ ## * spire = Spire.new
329
+ ## * billing = spire.billing()
330
+ ## * plans = billing.plans
331
+ #class Billing
332
+ #def initialize(spire,properties)
333
+ #@spire = spire
334
+ #@properties = properties
335
+ #end
672
336
 
673
- def url
674
- @properties["url"]
675
- end
337
+ #def url
338
+ #@properties["url"]
339
+ #end
676
340
 
677
- def plans
678
- @properties["plans"]
679
- end
680
- end
341
+ #def plans
342
+ #@properties["plans"]
343
+ #end
344
+ #end
681
345
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spire_io
3
3
  version: !ruby/object:Gem::Version
4
- hash: -3702664328
4
+ hash: -3702664330
5
5
  prerelease: true
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - alpha
11
- - 2
12
- version: 1.0.0.alpha.2
11
+ - 5
12
+ version: 1.0.0.alpha.5
13
13
  platform: ruby
14
14
  authors:
15
15
  - Dan Yoder
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2012-01-23 00:00:00 -08:00
21
+ date: 2012-01-27 00:00:00 -08:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -93,7 +93,6 @@ extensions: []
93
93
  extra_rdoc_files: []
94
94
 
95
95
  files:
96
- - lib/requestable.rb
97
96
  - lib/spire_io.rb
98
97
  has_rdoc: true
99
98
  homepage: https://github.com/spire-io/spire.io.rb
data/lib/requestable.rb DELETED
@@ -1,70 +0,0 @@
1
- module Requestable
2
-
3
- def self.included(mod)
4
- mod.module_eval do
5
- extend(ClassMethods)
6
- include(InstanceMethods)
7
- end
8
- end
9
-
10
- module ClassMethods
11
- def requests
12
- @requests ||= {}
13
- end
14
-
15
- def define_request(name, &block)
16
- requests[name] = block
17
- end
18
- end
19
-
20
- module InstanceMethods
21
- def prepare_request(name, *args)
22
- if block = self.class.requests[name]
23
- options = self.instance_exec(*args, &block)
24
- Request.new(@client, options)
25
- else
26
- raise ArgumentError, "No request has been defined for #{name.inspect}"
27
- end
28
- end
29
-
30
- def request(name, *args)
31
- prepare_request(name, *args).exec
32
- end
33
- end
34
-
35
- class Request
36
- attr_accessor :url
37
- def initialize(client, options)
38
- @client = client
39
- @method = options.delete(:method)
40
- @url = options.delete(:url)
41
- @options = options
42
- @options[:headers] = {
43
- "User-Agent" => "Ruby spire.io client"
44
- }.merge(@options[:headers])
45
- end
46
-
47
- def headers
48
- @options[:headers]
49
- end
50
-
51
- def body
52
- @options[:body]
53
- end
54
-
55
- def body=(val)
56
- @options[:body] = val
57
- end
58
-
59
- def query
60
- @options[:query]
61
- end
62
-
63
- def exec
64
- @client.send(@method, @url, @options)
65
- end
66
- end
67
-
68
- end
69
-
70
-