spire_io 1.0.0.alpha.5 → 1.0.0.beta.1

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.
@@ -0,0 +1,60 @@
1
+ class Spire
2
+ class API
3
+
4
+ class Account < Resource
5
+ def resource_name
6
+ "account"
7
+ end
8
+
9
+ define_request(:billing_subscription) do |info|
10
+ billing = properties["billing"]
11
+ {
12
+ :method => :put,
13
+ :url => billing["url"],
14
+ :body => info.to_json,
15
+ :headers => {
16
+ "Accept" => media_type, "Content-Type" => media_type,
17
+ "Authorization" => "Capability #{billing["capability"]}"
18
+ }
19
+ }
20
+ end
21
+
22
+ define_request(:billing_invoices) do
23
+ invoices = properties["billing"]["invoices"]
24
+ {
25
+ :method => :get,
26
+ :url => invoices["url"],
27
+ :headers => {
28
+ "Accept" => "application/json",
29
+ "Authorization" => "Capability #{invoices["capability"]}"
30
+ }
31
+ }
32
+ end
33
+
34
+ define_request(:billing_invoices_upcoming) do
35
+ upcoming = properties["billing"]["invoices"]["upcoming"]
36
+ {
37
+ :method => :get,
38
+ :url => upcoming["url"],
39
+ :headers => {
40
+ "Accept" => "application/json",
41
+ "Authorization" => "Capability #{upcoming["capability"]}"
42
+ }
43
+ }
44
+ end
45
+
46
+ # Updates and subscribe the account to a billing plan
47
+ # @param [Object] info data containing billing description
48
+ # @return [Account]
49
+ def billing_subscription(info)
50
+ response = request(:billing_subscription)
51
+ raise "Error attempting to update account billing: (#{response.status}) #{response.body}" if response.status != 200
52
+ properties = response.data
53
+ #@resources["account"] = JSON.parse(response.body)
54
+ self
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,34 @@
1
+ class Spire
2
+ class API
3
+
4
+ class Channel < Resource
5
+ def resource_name
6
+ "channel"
7
+ end
8
+
9
+ define_request(:publish) do |string|
10
+ {
11
+ :method => :post,
12
+ :url => @url,
13
+ :body => string,
14
+ :headers => {
15
+ "Authorization" => "Capability #{@capability}",
16
+ "Accept" => @spire.mediaType("message"),
17
+ "Content-Type" => @spire.mediaType("message")
18
+ }
19
+ }
20
+ end
21
+
22
+ def publish(content)
23
+ body = {:content => content}.to_json
24
+ response = request(:publish, body)
25
+ unless response.status == 201
26
+ raise "Error publishing to #{self.class.name}: (#{response.status}) #{response.body}"
27
+ end
28
+ message = response.data
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,103 @@
1
+ require "delegate"
2
+
3
+ class Spire
4
+ class API
5
+
6
+ module Requestable
7
+
8
+ def self.included(mod)
9
+ mod.module_eval do
10
+ extend(ClassMethods)
11
+ include(InstanceMethods)
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ def requests
17
+ @requests ||= {}
18
+ end
19
+
20
+ def get_request(name)
21
+ if req = requests[name]
22
+ req
23
+ elsif superclass.respond_to?(:get_request)
24
+ superclass.get_request(name)
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def define_request(name, &block)
31
+ requests[name] = block
32
+ end
33
+ end
34
+
35
+ module InstanceMethods
36
+ def prepare_request(name, *args)
37
+ if block = self.class.get_request(name)
38
+ options = self.instance_exec(*args, &block)
39
+ Request.new(@client, options)
40
+ else
41
+ raise ArgumentError, "No request has been defined for #{name.inspect}"
42
+ end
43
+ end
44
+
45
+ def request(name, *args)
46
+ prepare_request(name, *args).exec
47
+ end
48
+ end
49
+
50
+ class Request
51
+ attr_accessor :url
52
+ def initialize(client, options)
53
+ @client = client
54
+ @method = options.delete(:method)
55
+ @url = options.delete(:url)
56
+ @options = options
57
+ @options[:headers] = {
58
+ "User-Agent" => "Ruby spire.io client"
59
+ }.merge(@options[:headers] || {})
60
+ end
61
+
62
+ def headers
63
+ @options[:headers]
64
+ end
65
+
66
+ def body
67
+ @options[:body]
68
+ end
69
+
70
+ def body=(val)
71
+ @options[:body] = val
72
+ end
73
+
74
+ def query
75
+ @options[:query]
76
+ end
77
+
78
+ def exec
79
+ response = Response.new(@client.send(@method, @url, @options))
80
+ headers = response.headers
81
+ content_type = headers.values_at("Content-Type", "content-type").compact.first
82
+ if content_type =~ /json/ && [200, 201].include?(response.status)
83
+ # FIXME: detect appropriate response headers, rather than rescuing
84
+ begin
85
+ response.data = API.deserialize(response.body)
86
+ rescue
87
+ end
88
+ end
89
+ response
90
+ end
91
+
92
+ class Response < SimpleDelegator
93
+ attr_accessor :data
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+
100
+
101
+
102
+ end
103
+ end
@@ -0,0 +1,109 @@
1
+ class Spire
2
+ class API
3
+ class Resource
4
+ include Requestable
5
+
6
+ define_request(:get) do
7
+ {
8
+ :method => :get,
9
+ :url => @url,
10
+ :headers => {
11
+ "Authorization" => "Capability #{@capability}",
12
+ "Accept" => media_type
13
+ }
14
+ }
15
+ end
16
+
17
+ define_request(:update) do |properties|
18
+ {
19
+ :method => :put,
20
+ :url => @url,
21
+ :body => properties.to_json,
22
+ :headers => {
23
+ "Authorization" => "Capability #{@capability}",
24
+ "Accept" => media_type,
25
+ "Content-Type" => media_type
26
+ }
27
+ }
28
+ end
29
+
30
+ define_request(:delete) do
31
+ {
32
+ :method => :delete,
33
+ :url => @url,
34
+ :headers => {
35
+ "Authorization" => "Capability #{@capability}",
36
+ "Accept" => media_type,
37
+ "Content-Type" => media_type,
38
+ }
39
+ }
40
+ end
41
+
42
+ attr_reader :url, :capability, :properties
43
+
44
+ def initialize(spire, data)
45
+ @spire = spire
46
+ @client = spire.client
47
+ @url = data["url"]
48
+ @capability = data["capability"]
49
+ @properties = data
50
+ end
51
+
52
+ def key
53
+ properties["key"]
54
+ end
55
+
56
+ def method_missing(name, *args)
57
+ if description = schema["properties"][name.to_s]
58
+ properties[name.to_s]
59
+ else
60
+ super
61
+ end
62
+ end
63
+
64
+ def [](name)
65
+ properties[name]
66
+ end
67
+
68
+ def inspect
69
+ "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
70
+ end
71
+
72
+ def get
73
+ response = request(:get)
74
+ unless response.status == 200
75
+ raise "Error retrieving #{self.class.name}: (#{response.status}) #{response.body}"
76
+ end
77
+ @properties = response.data
78
+ self
79
+ end
80
+
81
+ def update(properties)
82
+ response = request(:update, properties)
83
+ unless response.status == 200
84
+ raise "Error updating #{self.class.name}: (#{response.status}) #{response.body}"
85
+ end
86
+ @properties = response.data
87
+ self
88
+ end
89
+
90
+ def delete
91
+ response = request(:delete)
92
+ unless response.status == 204
93
+ raise "Error deleting #{self.class.name}: (#{response.status}) #{response.body}"
94
+ end
95
+ true
96
+ end
97
+
98
+ def schema
99
+ @spire.schema[resource_name]
100
+ end
101
+
102
+ def media_type
103
+ schema["mediaType"]
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+
@@ -0,0 +1,166 @@
1
+ class Spire
2
+ class API
3
+
4
+ class Session
5
+ include Requestable
6
+
7
+ define_request(:account) do
8
+ resource = @resources["account"]
9
+ {
10
+ :method => :get,
11
+ :url => resource["url"],
12
+ :headers => {
13
+ "Authorization" => "Capability #{resource["capability"]}",
14
+ "Accept" => @spire.mediaType("account")
15
+ }
16
+ }
17
+ end
18
+
19
+ define_request(:channels) do
20
+ collection = @resources["channels"]
21
+ request = {
22
+ :method => :get,
23
+ :url => collection["url"],
24
+ :headers => {
25
+ "Authorization" => "Capability #{collection["capability"]}",
26
+ "Accept" => @spire.mediaType("channels"),
27
+ }
28
+ }
29
+ end
30
+
31
+ define_request(:channel_by_name) do |name|
32
+ collection = @resources["channels"]
33
+ request = {
34
+ :method => :get,
35
+ :url => collection["url"],
36
+ :query => {:name => name},
37
+ :headers => {
38
+ "Authorization" => "Capability #{collection["capability"]}",
39
+ "Accept" => @spire.mediaType("channels"),
40
+ }
41
+ }
42
+ end
43
+
44
+ define_request(:create_channel) do |name|
45
+ collection = @resources["channels"]
46
+ {
47
+ :method => :post,
48
+ :url => collection["url"],
49
+ :body => { :name => name }.to_json,
50
+ :headers => {
51
+ "Authorization" => "Capability #{collection["capability"]}",
52
+ "Accept" => @spire.mediaType("channel"),
53
+ "Content-Type" => @spire.mediaType("channel")
54
+ }
55
+ }
56
+ end
57
+
58
+ define_request(:create_subscription) do |subscription_name, channel_urls|
59
+ collection = @resources["subscriptions"]
60
+ {
61
+ :method => :post,
62
+ :url => collection["url"],
63
+ :body => {
64
+ :channels => channel_urls,
65
+ :name => subscription_name
66
+ }.to_json,
67
+ :headers => {
68
+ "Authorization" => "Capability #{collection["capability"]}",
69
+ "Accept" => @spire.mediaType("subscription"),
70
+ "Content-Type" => @spire.mediaType("subscription")
71
+ }
72
+ }
73
+ end
74
+
75
+ attr_reader :url, :resources, :schema, :capability
76
+
77
+ def initialize(spire, data)
78
+ @spire = spire
79
+ @client = spire.client
80
+ @schema = spire.schema["session"]
81
+ @url = data["url"]
82
+ @capability = data["capability"]
83
+ @resources = data["resources"]
84
+ end
85
+
86
+ def account
87
+ @account ||= account!
88
+ end
89
+
90
+ def account!
91
+ @account = API::Account.new(@spire, @resources["account"]).get
92
+ end
93
+
94
+ def create_channel(name)
95
+ response = request(:create_channel, name)
96
+ unless response.status == 201
97
+ raise "Error creating Channel: (#{response.status}) #{response.body}"
98
+ end
99
+ properties = response.data
100
+ channels[name] = API::Channel.new(@spire, properties)
101
+ end
102
+
103
+ def create_subscription(subscription_name, channel_names)
104
+ channel_urls = channel_names.flatten.map { |name| self.channels[name].url rescue nil }.compact
105
+ response = request(:create_subscription, subscription_name, channel_urls)
106
+ unless response.status == 201
107
+ raise "Error creating Subscription: (#{response.status}) #{response.body}"
108
+ end
109
+ data = response.data
110
+ subscriptions[data["name"]] = API::Subscription.new(@spire, data)
111
+ end
112
+
113
+ def channels!
114
+ response = request(:channels)
115
+ unless response.status == 200
116
+ raise "Error retrieving Channels: (#{response.status}) #{response.body}"
117
+ end
118
+ channels_data = response.data
119
+ @channels = {}
120
+ channels_data.each do |name, properties|
121
+ @channels[name] = API::Channel.new(@spire, properties)
122
+ end
123
+ @channels
124
+ end
125
+
126
+ def channels
127
+ @channels ||= channels!
128
+ end
129
+
130
+ # Not yet in Spire API
131
+ #define_request(:subscriptions) do
132
+ #{
133
+ #:method => :get,
134
+ #:url => @resources["subscriptions"]["url"],
135
+ #:headers => {
136
+ #"Authorization" => "Capability #{@resources["subscriptions"]["capability"]}",
137
+ #"Accept" => @spire.mediaType("subscription"),
138
+ #}
139
+ #}
140
+ #end
141
+
142
+ def subscriptions
143
+ if @subscriptions
144
+ @subscriptions
145
+ else
146
+ # TODO Fix this to use an API call once Spire supports it
147
+ @subscriptions = {}
148
+ channels.each do |name, channel|
149
+ if subs = channel.properties["subscriptions"]
150
+ subs.each do |key, sub|
151
+ @subscriptions[key] = API::Subscription.new(@spire, sub)
152
+ end
153
+ end
154
+ end
155
+ @subscriptions
156
+ end
157
+ end
158
+
159
+ def subscriptions!
160
+ raise "unimplemented"
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,79 @@
1
+ class Spire
2
+ class API
3
+
4
+ class Subscription < Resource
5
+
6
+ attr_reader :last
7
+ def resource_name
8
+ "subscription"
9
+ end
10
+
11
+ define_request(:messages) do |options|
12
+ {
13
+ :method => :get,
14
+ :url => @url,
15
+ :query => {
16
+ "timeout" => options[:timeout],
17
+ "last-message" => options[:last],
18
+ "order-by" => options[:order_by],
19
+ "delay" => options[:delay]
20
+ },
21
+ :headers => {
22
+ "Authorization" => "Capability #{@capability}",
23
+ "Accept" => @spire.mediaType("events")
24
+ }
25
+ }
26
+ end
27
+
28
+ def listeners
29
+ @listeners ||= []
30
+ end
31
+
32
+ def add_listener(&block)
33
+ listeners << block
34
+ block
35
+ end
36
+
37
+ def retrieve_messages(options={})
38
+ options[:last] ||= "0"
39
+ options[:delay] ||= 0
40
+ options[:order_by] ||= "desc"
41
+
42
+ response = request(:messages, options)
43
+ unless response.status == 200
44
+ raise "Error retrieving messages from #{self.class.name}: (#{response.status}) #{response.body}"
45
+ end
46
+ messages = response.data["messages"]
47
+ @last = messages.last["timestamp"] unless messages.empty?
48
+ messages.each do |message|
49
+ listeners.each do |listener|
50
+ listener.call(message)
51
+ end
52
+ end
53
+ messages
54
+ end
55
+
56
+ def poll(options={})
57
+ # timeout option of 0 means no long poll,
58
+ # so we force it here.
59
+ options[:timeout] = 0
60
+ options[:last] = @last
61
+ retrieve_messages(options)
62
+ end
63
+
64
+ def long_poll(options={})
65
+ options[:timeout] ||= 30
66
+ options[:last] = @last
67
+ retrieve_messages(options)
68
+ end
69
+
70
+ def listen(options={})
71
+ loop do
72
+ break unless yield(long_poll(options))
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
data/lib/spire/api.rb ADDED
@@ -0,0 +1,165 @@
1
+ require "rubygems"
2
+ gem "excon"
3
+ require "excon"
4
+ gem "json"
5
+ require "json"
6
+
7
+ require "spire/api/requestable"
8
+ require "spire/api/resource"
9
+ require "spire/api/session"
10
+ require "spire/api/account"
11
+ require "spire/api/channel"
12
+ require "spire/api/subscription"
13
+
14
+ class Spire
15
+
16
+ class API
17
+ include Requestable
18
+
19
+ def self.deserialize(string)
20
+ JSON.parse(string, :symbolize_names => false)
21
+ end
22
+
23
+ attr_reader :client, :description, :schema
24
+ def initialize(url="https://api.spire.io", options={})
25
+ @version = options[:version] || "1.0"
26
+ @client = Excon
27
+ @url = url
28
+ end
29
+
30
+ def inspect
31
+ "#<Spire::API:0x#{object_id.to_s(16)} @url=#{@url.dump}>"
32
+ end
33
+
34
+ define_request(:discover) do
35
+ {
36
+ :method => :get,
37
+ :url => @url,
38
+ :headers => {"Accept" => "application/json"}
39
+ }
40
+ end
41
+
42
+ define_request(:create_session) do |key|
43
+ {
44
+ :method => :post,
45
+ :url => @description["resources"]["sessions"]["url"],
46
+ :body => {:key => key}.to_json,
47
+ :headers => {
48
+ "Accept" => mediaType("session"),
49
+ "Content-Type" => mediaType("account")
50
+ }
51
+ }
52
+ end
53
+
54
+ define_request(:login) do |email, password|
55
+ {
56
+ :method => :post,
57
+ :url => @description["resources"]["sessions"]["url"],
58
+ :body => { :email => email, :password => password }.to_json,
59
+ :headers => {
60
+ "Accept" => mediaType("session"),
61
+ "Content-Type" => mediaType("account")
62
+ }
63
+ }
64
+ end
65
+
66
+ define_request(:create_account) do |info|
67
+ {
68
+ :method => :post,
69
+ :url => @description["resources"]["accounts"]["url"],
70
+ :body => {
71
+ :email => info[:email],
72
+ :password => info[:password],
73
+ :password_confirmation => info[:password_confirmation]
74
+ }.to_json,
75
+ :headers => {
76
+ "Accept" => mediaType("session"),
77
+ "Content-Type" => mediaType("account")
78
+ }
79
+ }
80
+ end
81
+
82
+ define_request(:password_reset) do |email|
83
+ {
84
+ :method => :post,
85
+ :url => @description["resources"]["accounts"]["url"],
86
+ :query => { :email => email },
87
+ :body => ""
88
+ }
89
+ end
90
+
91
+ define_request(:billing) do
92
+ {
93
+ :method => :get,
94
+ :url => @description["resources"]["billing"]["url"],
95
+ :headers => {
96
+ "Accept" => "application/json"
97
+ }
98
+ }
99
+ end
100
+
101
+
102
+ def discover
103
+ response = request(:discover)
104
+ raise "Error during discovery: #{response.status}" if response.status != 200
105
+ @description = response.data
106
+ @schema = @description["schema"][@version]
107
+ end
108
+
109
+ def mediaType(name)
110
+ schema[name]["mediaType"]
111
+ end
112
+
113
+ def create_session(key)
114
+ response = request(:create_session, key)
115
+ raise "Error starting a key-based session" if response.status != 201
116
+ session_data = response.data
117
+ API::Session.new(self, session_data)
118
+ end
119
+
120
+ # Authenticates a session using a login and password
121
+ def login(login, password)
122
+ response = request(:login, login, password)
123
+ raise "Error attemping to login: (#{response.status}) #{response.body}" if response.status != 201
124
+ session_data = response.data
125
+ API::Session.new(self, session_data)
126
+ end
127
+
128
+ # Register for a new spire account, and authenticates as the newly created account
129
+ # @param [String] :email Email address of new account
130
+ # @param [String] :password Password of new account
131
+ def create_account(info)
132
+ response = request(:create_account, info)
133
+ if response.status != 201
134
+ raise "Error attempting to register: (#{response.status}) #{response.body}"
135
+ end
136
+ session_data = response.data
137
+ API::Session.new(self, session_data)
138
+ end
139
+
140
+ def password_reset_request(email)
141
+ response = request(:password_reset)
142
+ unless response.status == 202
143
+ raise "Error requesting password reset: (#{response.status}) #{response.body}"
144
+ end
145
+ response
146
+ end
147
+
148
+ # Returns a billing object than contains a list of all the plans available
149
+ # @param [String] info optional object description
150
+ # @return [Billing]
151
+ def billing(info=nil)
152
+ response = request(:billing)
153
+ raise "Error getting billing plans: #{response.status}" if response.status != 200
154
+ API::Billing.new(self, response.data)
155
+ end
156
+
157
+ class Billing < Resource
158
+ def resource_name
159
+ "billing"
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ end
data/lib/spire_io.rb CHANGED
@@ -1,14 +1,11 @@
1
1
  require "delegate"
2
- gem "excon"
3
- require "excon"
4
- gem "json"
5
- require "json"
6
2
 
7
3
  require "spire/api"
8
4
 
9
5
  class Spire
10
6
 
11
- #How many times we will try to create a channel or subscription after getting a 409
7
+ # How many times we will try to fetch a channel or subscription after
8
+ # getting a 409 Conflict.
12
9
  RETRY_CREATION_LIMIT = 3
13
10
 
14
11
  attr_accessor :api, :session, :resources
@@ -16,19 +13,13 @@ class Spire
16
13
  def initialize(url="https://api.spire.io")
17
14
  @api = Spire::API.new(url)
18
15
  @url = url
19
- @channels = {}
20
- @subscriptions = {}
21
16
  @channel_error_counts = {}
22
17
  @subscription_error_counts = {}
23
18
  discover
24
19
  end
25
20
 
26
21
  def key
27
- @resources["account"]["key"]
28
- end
29
-
30
- def mediaType(name)
31
- @description["schema"]["1.0"][name]["mediaType"]
22
+ @session.resources["account"]["key"]
32
23
  end
33
24
 
34
25
  def discover
@@ -56,16 +47,8 @@ class Spire
56
47
  self
57
48
  end
58
49
 
59
- def key
60
- @session.resources["account"]["key"]
61
- end
62
-
63
50
  def password_reset_request(email)
64
- response = request(:password_reset)
65
- unless response.status == 202
66
- raise "Error requesting password reset: (#{response.status}) #{response.body}"
67
- end
68
- response
51
+ @api.password_reset_request(email)
69
52
  end
70
53
 
71
54
 
@@ -78,47 +61,8 @@ class Spire
78
61
  # See Spire docs for available settings
79
62
  def update(info)
80
63
  @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)
84
- self
85
- end
86
-
87
- def retrieve_session
88
- response = request(:session)
89
- cache_session(JSON.parse(response.body))
90
- raise "Error reloading session: #{response.status}" if response.status != 200
91
64
  self
92
- end
93
-
94
- def cache_session(data)
95
- @session = data
96
- @resources = @session["resources"]
97
- retrieve_channels
98
- end
99
-
100
- def retrieve_channels
101
- response = request(:channels)
102
- unless response.status == 200
103
- raise "Error retrieving channels: (#{response.status}) #{response.body}"
104
- end
105
- cache_channels(JSON.parse(response.body))
106
65
  end
107
-
108
- def cache_channels(data)
109
- @channels = {}
110
- data.each do |name, properties|
111
- @channels[name] = Channel.new(self, properties)
112
- cache_channel_subscriptions(properties["subscriptions"])
113
- end
114
- @channels
115
- end
116
-
117
- def cache_channel_subscriptions(data)
118
- data.each do |name, properties|
119
- @subscriptions[name] = Subscription.new(self, properties)
120
- end
121
- end
122
66
 
123
67
  # Returns a channel object for the named channel
124
68
  # @param [String] name Name of channel returned
@@ -131,6 +75,10 @@ class Spire
131
75
  @session.channels
132
76
  end
133
77
 
78
+ def channels!
79
+ @session.channels!
80
+ end
81
+
134
82
  # Creates a channel on spire. Returns a Channel object. Note that this will
135
83
  # fail with a 409 if a channel with the same name exists.
136
84
  def find_or_create_channel(name)
@@ -207,10 +155,7 @@ class Spire
207
155
  # @return [Account]
208
156
  def billing_subscription(info)
209
157
  @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
158
+ self
214
159
  end
215
160
 
216
161
 
@@ -278,11 +223,17 @@ class Spire
278
223
  __getobj__.add_listener(&listener)
279
224
  end
280
225
 
281
- def remove_listener(listener)
282
- if listener.is_a? String
283
- listener = listeners[listener]
226
+ def remove_listener(arg)
227
+ if arg.is_a? String
228
+ listener = listeners.delete(arg)
229
+ else
230
+ name, _listener = listeners.detect {|k,v| v == arg }
231
+ listener = listeners.delete(name)
232
+ end
233
+
234
+ if listener
235
+ __getobj__.listeners.delete(listener)
284
236
  end
285
- __getobj__.listeners.delete(listener)
286
237
  end
287
238
 
288
239
  def wrap_listener(&block)
@@ -321,25 +272,4 @@ class Spire
321
272
 
322
273
  end
323
274
 
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
336
-
337
- #def url
338
- #@properties["url"]
339
- #end
340
-
341
- #def plans
342
- #@properties["plans"]
343
- #end
344
- #end
345
275
  end
metadata CHANGED
@@ -1,24 +1,25 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spire_io
3
3
  version: !ruby/object:Gem::Version
4
- hash: -3702664330
4
+ hash: 62196353
5
5
  prerelease: true
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
- - alpha
11
- - 5
12
- version: 1.0.0.alpha.5
10
+ - beta
11
+ - 1
12
+ version: 1.0.0.beta.1
13
13
  platform: ruby
14
14
  authors:
15
15
  - Dan Yoder
16
16
  - Daniel Lockhart dlockhart@spire.io
17
+ - Matthew King mking@spire.io
17
18
  autorequire:
18
19
  bindir: bin
19
20
  cert_chain: []
20
21
 
21
- date: 2012-01-27 00:00:00 -08:00
22
+ date: 2012-02-01 00:00:00 -08:00
22
23
  default_executable:
23
24
  dependencies:
24
25
  - !ruby/object:Gem::Dependency
@@ -81,11 +82,28 @@ dependencies:
81
82
  version: "0.7"
82
83
  type: :development
83
84
  version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: redcarpet
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ hash: 11
94
+ segments:
95
+ - 2
96
+ - 1
97
+ - 0
98
+ version: 2.1.0
99
+ type: :development
100
+ version_requirements: *id005
84
101
  description: "\t\tThe spire_io gem allows you to quickly and easily use the spire.io service\n\
85
102
  \t\tusing Ruby. See http://www.spire.io/ for more.\n"
86
103
  email:
87
104
  - dan@spire.io
88
105
  -
106
+ -
89
107
  executables: []
90
108
 
91
109
  extensions: []
@@ -93,6 +111,13 @@ extensions: []
93
111
  extra_rdoc_files: []
94
112
 
95
113
  files:
114
+ - lib/spire/api/account.rb
115
+ - lib/spire/api/channel.rb
116
+ - lib/spire/api/requestable.rb
117
+ - lib/spire/api/resource.rb
118
+ - lib/spire/api/session.rb
119
+ - lib/spire/api/subscription.rb
120
+ - lib/spire/api.rb
96
121
  - lib/spire_io.rb
97
122
  has_rdoc: true
98
123
  homepage: https://github.com/spire-io/spire.io.rb