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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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