broach 0.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.
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Manfred Stienstra, Fingertips <manfred@fngtps.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,92 @@
1
+ require 'rubygems' rescue nil
2
+ require 'rest'
3
+ require 'json'
4
+
5
+ require 'broach/exceptions'
6
+
7
+ # === Settings
8
+ #
9
+ # Before you can do anything else you will need to provide credentials first, this includes the account name and
10
+ # authentication token. The +use_ssl+ parameter is optional and defaults to false.
11
+ #
12
+ # Broach.settings = { 'account' => 'example', 'token' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'use_ssl' => true }
13
+ #
14
+ # You can find the token for any Campfire account by logging into the web interface and clicking 'My Info' in the top-right
15
+ # corner.
16
+ #
17
+ # === Say someting in a room real quick
18
+ #
19
+ # If you just need to say something real quick in a room, you can use the speak class method.
20
+ #
21
+ # Broach.speak("Office", "Manfred just deployed a new version of the weblog (http://www.fngtps.com)")
22
+ #
23
+ # Note that this fetches a list of all rooms so it can figure out the ID for the room you specified.
24
+ #
25
+ # === Post a lot of stuff to a room
26
+ #
27
+ # If you want to post multiple lines to one room, it's a good idea to create a Room instance.
28
+ #
29
+ # room = Broach.rooms.find { |room| room.name == 'Office' }
30
+ # room.speak('Manfred just commited to the `weblog' repository')
31
+ # room.speak("commit 4578530113cb87e1e7dbd696c376181e97d429d7\n" +
32
+ # "Author: Manfred Stienstra <manfred@fngtps.com>\n" +
33
+ # "Date: Wed Dec 16 14:03:33 2009 +0100\n\n" +
34
+ # " Add a speak method to Broach to quickly say something in a room.", :type => :paste)
35
+ module Broach
36
+ autoload :Attributes, 'broach/attributes'
37
+ autoload :Session, 'broach/session'
38
+ autoload :User, 'broach/user'
39
+ autoload :Room, 'broach/room'
40
+
41
+ # Returns the current Broach settings
42
+ def self.settings
43
+ @settings
44
+ end
45
+
46
+ # Sets the broach settings
47
+ def self.settings=(settings)
48
+ @settings = settings
49
+ @session = nil
50
+ end
51
+
52
+ # Returns a session object with the current settings
53
+ def self.session
54
+ @session ||= Broach::Session.new(settings)
55
+ end
56
+
57
+ # Returns a User instance for the currently authenticated user
58
+ def self.me
59
+ Broach::User.me
60
+ end
61
+
62
+ # Returns a Room instance for all rooms accesible to the currently authenticated user
63
+ def self.rooms
64
+ Broach::Room.all
65
+ end
66
+
67
+ # Send a message to a room with a certain name.
68
+ #
69
+ # Note that you should only use this method if you're sending just one message. It fetches
70
+ # all rooms before sending the message to find the room with the name you're specifying.
71
+ #
72
+ # If you need to send multiple messages to the same room you should instantiate a room first.
73
+ #
74
+ # ==== Options
75
+ #
76
+ # +room+
77
+ # The name of the room, ie. 'Office'
78
+ # +content+
79
+ # The content of the message, see Broach::Room#speak for more information.
80
+ # +options+
81
+ # Options for the message, see Broach::Room#speak for more information.
82
+ #
83
+ # ==== Examples
84
+ #
85
+ # Broach.speak('Office', 'Manfred just deployed a new version of the weblog (http://www.fngtps.com)')
86
+ # Broach.speak('Office', 'crickets', :type => :sound)
87
+ def self.speak(room_name, content, options={})
88
+ if room = rooms.find { |room| room.name == room_name }
89
+ room.speak(content, options)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,18 @@
1
+ module Broach
2
+ # Makes a very simple attribute driven model from the class when included.
3
+ module Attributes
4
+ def initialize(attributes)
5
+ @attributes = attributes
6
+ end
7
+
8
+ def id; @attributes['id']; end
9
+
10
+ def method_missing(method, *arguments, &block)
11
+ if value = @attributes[method.to_s]
12
+ value
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module Broach
2
+ # Raised when something unexpected happened during communication with Campfire
3
+ class APIError < RuntimeError
4
+ attr_accessor :response
5
+ end
6
+
7
+ # Raised when the credentials were incorrect
8
+ class AuthenticationError < APIError; end
9
+
10
+ # Raised when the credentials were correct, but the resource could not be accessed
11
+ class AuthorizationError < APIError; end
12
+ end
@@ -0,0 +1,51 @@
1
+ module Broach
2
+ # Represents a chat room on the server
3
+ class Room
4
+ TYPE_MAP = {
5
+ :text => 'TextMessage',
6
+ :paste => 'PasteMessage',
7
+ :sound => 'SoundMessage'
8
+ }
9
+
10
+ include Broach::Attributes
11
+
12
+ # Send a message to the room
13
+ #
14
+ # ==== Parameters and options
15
+ #
16
+ # [+content+]
17
+ # Content to send. For a normal text message this is the content of the message. For a paste
18
+ # it's the content of the paste. For a sound it's the name of the sound.
19
+ #
20
+ # [<tt>:type</tt>]
21
+ # The type of message to send, this is :text by default for normal text messages.
22
+ # You can also use :paste and :sound. Valid sound messages are 'rimshot', 'crickets',
23
+ # or 'trombone'.
24
+ #
25
+ # ==== Examples
26
+ #
27
+ # room = Broach::Room.all.first
28
+ # room.speak("Let's review these figures.")
29
+ # room.speak("<code>$stderr.write('-')</code>", :type => :paste)
30
+ # room.speak("rimshot", :type => :sound)
31
+ def speak(content, options={})
32
+ options[:type] ||= :text
33
+ Broach.session.post("room/#{id}/speak", 'message' => {
34
+ 'type' => TYPE_MAP[options[:type]],
35
+ 'body' => content
36
+ })['message']
37
+ end
38
+
39
+ # Returns a Room instance for all rooms accessible to the authenticated user
40
+ def self.all
41
+ Broach.session.get('rooms')['rooms'].map do |attributes|
42
+ Broach::Room.new(attributes)
43
+ end
44
+ end
45
+
46
+ # Returns a Room instance for a room with a specific ID
47
+ def self.find(id)
48
+ new(Broach.session.get("room/#{id.to_i}")['room'])
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,73 @@
1
+ module Broach
2
+ # Represents a session with Campfire
3
+ class Session
4
+ include Broach::Attributes
5
+
6
+ # Returns true when the connection should use SSL and false otherwise.
7
+ def use_ssl?
8
+ @attributes['use_ssl'] || false
9
+ end
10
+
11
+ # Returns either http or https depending on whether we should use SSL or not.
12
+ def scheme
13
+ use_ssl? ? 'https' : 'http'
14
+ end
15
+
16
+ # Returns the full URL for a certain path
17
+ #
18
+ # session.url_for('rooms') #=> "http://example.campfirenow.com/rooms"
19
+ def url_for(path)
20
+ ["#{scheme}:/", "#{account}.campfirenow.com", path].join('/')
21
+ end
22
+
23
+ # Returns the headers to send for a specific HTTP method
24
+ #
25
+ # session.headers_for(:get) #=> { 'Accept' => 'application/json' }
26
+ def headers_for(method)
27
+ headers = { 'Accept' => 'application/json', 'User-Agent' => 'Broach' }
28
+ headers['Content-type'] = 'application/json' if method == :post
29
+ headers
30
+ end
31
+
32
+ # Returns the credentials to authenticate the current user
33
+ def credentials
34
+ { :username => token, :password => 'x' }
35
+ end
36
+
37
+ # Gets a resource with a certain path on the server. When the GET is succesful
38
+ # the parsed body is returned, otherwise an exception is raised.
39
+ def get(path)
40
+ response = REST.get(url_for(path), headers_for(:get), credentials)
41
+ if response.ok?
42
+ return JSON.parse(response.body)
43
+ else
44
+ handle_response(:get, path, response)
45
+ end
46
+ end
47
+
48
+ # Posts a resource to a certain path on the server. When the POST is successful
49
+ # the parsed body is returned, otherwise an exception is raised.
50
+ def post(path, payload)
51
+ response = REST.post(url_for(path), JSON.dump(payload), headers_for(:post), credentials)
52
+ if response.created?
53
+ return JSON.parse(response.body)
54
+ else
55
+ handle_response(:post, path, response)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def handle_response(method, path, response)
62
+ exception = if response.unauthorized?
63
+ Broach::AuthenticationError.new("Couldn't authenticate with the supplied credentials for the account `#{account}'")
64
+ elsif response.forbidden?
65
+ Broach::AuthorizationError.new("Couldn't #{method.to_s.upcase} the resource `#{path}' on the account `#{account}'")
66
+ else
67
+ Broach::APIError.new("Response from the server was unexpected (#{response.status_code})")
68
+ end
69
+ exception.response = response
70
+ raise exception
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,16 @@
1
+ module Broach
2
+ # Represents a user on the server
3
+ class User
4
+ include Broach::Attributes
5
+
6
+ # Returns a User instance for the currently authenticated user
7
+ def self.me
8
+ new(Broach.session.get('users/me')['user'])
9
+ end
10
+
11
+ # Returns a User instance for a user with a specific ID
12
+ def self.find(id)
13
+ new(Broach.session.get("users/#{id.to_i}")['user'])
14
+ end
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: broach
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Manfred Stienstra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-16 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: " Ruby implementation of 37signal's Campfire API.\n"
17
+ email: manfred@fngtps.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ files:
25
+ - LICENSE
26
+ - lib/broach/attributes.rb
27
+ - lib/broach/exceptions.rb
28
+ - lib/broach/room.rb
29
+ - lib/broach/session.rb
30
+ - lib/broach/user.rb
31
+ - lib/broach.rb
32
+ has_rdoc: true
33
+ homepage:
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --charset=utf-8
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Ruby implementation of 37signal's Campfire API.
60
+ test_files: []
61
+