├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.markdown ├── Rakefile ├── broadcast.gemspec ├── lib ├── broadcast.rb └── broadcast │ ├── config.rb │ ├── media │ ├── campfire.rb │ ├── email.rb │ ├── facebook.rb │ ├── irc.rb │ ├── jabber.rb │ ├── log.rb │ ├── oauth.rb │ ├── sms.rb │ ├── tumblr.rb │ ├── twitter.rb │ └── yammer.rb │ ├── medium.rb │ ├── message.rb │ ├── publishable.rb │ ├── railtie.rb │ ├── simple.rb │ ├── tasks │ └── broadcast.rake │ └── version.rb └── spec ├── lib ├── broadcast │ ├── media │ │ ├── campfire_spec.rb │ │ ├── email_spec.rb │ │ ├── facebook_spec.rb │ │ ├── irc_spec.rb │ │ ├── jabber_spec.rb │ │ ├── log_spec.rb │ │ ├── oauth_spec.rb │ │ ├── sms_spec.rb │ │ ├── tumblr_spec.rb │ │ ├── twitter_spec.rb │ │ └── yammer_spec.rb │ ├── medium_spec.rb │ ├── message_spec.rb │ ├── publishable_spec.rb │ └── simple_spec.rb └── broadcast_spec.rb ├── spec_helper.rb └── support ├── config.rb └── examples.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | sandbox 6 | *.log 7 | coverage 8 | bin 9 | .rspec 10 | facebook_test/config.yml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: "bundle exec rspec spec" 2 | rvm: 3 | - 1.8.7 4 | - 1.9.2 5 | - ree 6 | - jruby 7 | - rbx -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | 5 | group :development, :test do 6 | gem 'rake', '0.8.7' 7 | gem 'rspec' 8 | 9 | platforms :mri_18 do 10 | gem 'rcov' 11 | gem "ruby-debug" 12 | end 13 | 14 | platforms :mri_19 do 15 | gem 'rcov' 16 | gem "ruby-debug19" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Marcin Bunsch, Future Simple Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Broadcast [![Build Status](http://travis-ci.org/futuresimple/broadcast.png)](http://travis-ci.org/futuresimple/broadcast) 2 | ========= 3 | 4 | A broadcasting microframework making publishing of messages to different services easy and DRY. 5 | 6 | Current version is 0.2.1. 7 | 8 | Use Cases 9 | ------------ 10 | 11 | Possible use cases include: 12 | 13 | - publishing a update on your product Twitter feed 14 | - notifying coworkers on Jabber of a deployment when it happens 15 | - sending update on company IRC when a signup in your startup app happens 16 | - publishing daily statistics to Yammer 17 | - sending an email and a Jabber update when a specific threshold is reached (like number of users) 18 | 19 | Installation 20 | ------------ 21 | 22 | You can install broadcast via Rubygems by typing: 23 | 24 | gem install broadcast 25 | 26 | It you use bundler, you can install it by adding the following line to your Gemfile: 27 | 28 | gem 'broadcast' 29 | 30 | and running 31 | 32 | bundle install 33 | 34 | Usage 35 | ----- 36 | 37 | Broadcast has 2 main classes: Medium and Message (hat tip to Marshall McLuhan). 38 | 39 | **Broadcast::Medium** is the service the message will be sent to, and **Broadcast::Message** is, well, the message. 40 | 41 | The first thing you need to do is to configure the desired Media. For example, to configure jabber, put something like this in some configuration file (e.g. a Rails initializer): 42 | 43 | ```ruby 44 | Broadcast.setup do |config| 45 | config.jabber { |jabber| 46 | jabber.username = 'foo@foo.com' 47 | jabber.password = 'mypass' 48 | jabber.recipients = 'mike@foo.com' 49 | } 50 | end 51 | ``` 52 | 53 | Now to send a message, you need to define Message class, like this: 54 | 55 | ```ruby 56 | class Poke < Broadcast::Message 57 | medium :jabber 58 | 59 | def body 60 | "Poke!" 61 | end 62 | end 63 | ``` 64 | 65 | When you're ready, just instantiate the Message class and call #publish: 66 | 67 | ```ruby 68 | Poke.new.publish 69 | ``` 70 | 71 | Broadcast::Message::Simple 72 | ------------ 73 | 74 | If you need to dynamically create a message or just want a oneliner to publish a message, Broadcast::Message::Simple is your friend! 75 | 76 | ```ruby 77 | Broadcast::Message::Simple.new(:body => 'Poke!').publish(:jabber) 78 | ``` 79 | 80 | Broadcast::Message::Simple accepts the following keys in the arguments hash 81 | 82 | * body 83 | * subject 84 | 85 | Broadcast::Message::Simple#publish accepts the name of the medium and optional override settings for that medium 86 | 87 | Delayed::Job 88 | ------------ 89 | 90 | Broadcast plays nicely with Delayed::Job. For example to publish a message in a delayed job, simply change the above example to: 91 | 92 | ```ruby 93 | Poke.new.delay.publish 94 | ``` 95 | 96 | 97 | Media 98 | ----- 99 | 100 | Broadcast currently ships with support for following Media: 101 | 102 | ### Jabber 103 | 104 | Broadcast::Medium::Jabber is based on the xmpp4r gem. 105 | 106 | #### Example setup 107 | 108 | ```ruby 109 | Broadcast.setup do |config| 110 | config.jabber { |jabber| 111 | jabber.username = 'myaccount@gmail.com' 112 | jabber.password = 'mypass' 113 | jabber.recipients = 'mike@foo.com' 114 | } 115 | end 116 | ``` 117 | 118 | ### Email 119 | 120 | Broadcast::Medium::Email is based on the mail gem. 121 | 122 | #### Example setup 123 | 124 | This is an example setup with smtp delivery method with Gmail 125 | 126 | ```ruby 127 | Broadcast.setup do |config| 128 | config.email { |email| 129 | email.recipients = ['foo@moo.com'] 130 | email.delivery_method = :smtp 131 | email.delivery_options = { 132 | :address => "smtp.gmail.com", 133 | :port => 587, 134 | :domain => 'your.host.name', 135 | :user_name => '', 136 | :password => '', 137 | :authentication => 'plain', 138 | :enable_starttls_auto => true 139 | } 140 | } 141 | end 142 | ``` 143 | 144 | ### Twitter 145 | 146 | Broadcast::Medium::Twitter is based on the oauth gem. 147 | In order to use it, you will need a application registered on Twitter. 148 | 149 | When you have it, run rake broadcast:authorize:twitter, which will help you get all the required keys and tokens. 150 | 151 | #### Example setup 152 | 153 | ```ruby 154 | Broadcast.setup do |config| 155 | config.twitter { |twitter| 156 | twitter.consumer_key = 'consumerkey' 157 | twitter.consumer_secret = 'consumersecret' 158 | twitter.access_token = 'accesstoken' 159 | twitter.access_secret = 'accesssecret' 160 | } 161 | end 162 | ``` 163 | 164 | ### Yammer 165 | 166 | Broadcast::Medium::Yammer is based on the oauth gem. 167 | In order to use it, you will need a application registered on Yammer. 168 | 169 | When you have it, run rake broadcast:authorize:yammer, which will help you get all the required keys and tokens. 170 | 171 | #### Example setup 172 | 173 | ```ruby 174 | Broadcast.setup do |config| 175 | config.yammer { |yammer| 176 | yammer.consumer_key = 'consumerkey' 177 | yammer.consumer_secret = 'consumersecret' 178 | yammer.access_token = 'accesstoken' 179 | yammer.access_secret = 'accesssecret' 180 | } 181 | end 182 | ``` 183 | 184 | ### Log 185 | 186 | Broadcast::Medium::Log is a simple writer to a log file 187 | 188 | #### Example setup 189 | 190 | ```ruby 191 | Broadcast.setup do |config| 192 | config.log.file = 'log/broadcast.log' 193 | end 194 | ``` 195 | 196 | ### Campfire 197 | 198 | Broadcast::Medium::Campfire is based on the broach gem. 199 | 200 | #### Example setup 201 | 202 | ```ruby 203 | Broadcast.setup do |config| 204 | config.campfire { |campfire| 205 | campfire.subdomain = 'myaccount' 206 | campfire.token = 'token' 207 | campfire.room = 'My Room' 208 | } 209 | end 210 | ``` 211 | 212 | ### Irc 213 | 214 | Broadcast::Medium::Irc employs the shout-bot gem. 215 | 216 | #### Example setup 217 | 218 | ```ruby 219 | Broadcast.setup do |config| 220 | config.irc { |irc| 221 | irc.username = 'myusername', 222 | irc.server = 'irc.freenode.net', 223 | irc.port = '6667', 224 | irc.channel = 'mychannel', 225 | } 226 | end 227 | ``` 228 | 229 | ### Facebook 230 | 231 | Broadcast::Medium::Facebook uses the koala gem. It is designed to publish messages to Facebook pages. 232 | It is based on the assumption that the user associated with the access token has publishing access to the page. 233 | 234 | #### Example setup 235 | 236 | ```ruby 237 | Broadcast.setup do |config| 238 | config.facebook { |facebook| 239 | facebook.token = 'facebook_access_token', 240 | facebook.page = 'Name of the page to publish to' 241 | } 242 | end 243 | ``` 244 | 245 | ### SMS 246 | 247 | Broadcast::Medium::SMS is based on the SMSified gem. 248 | You must create an account on http://smsified.com before sending SMS text messages (developer accounts are free). 249 | You will be given a phone number to use as your very own FROM sms number. This number, along with your username and password, 250 | must be added to your config during setup. The To address is the address of the mobile number that you would like to send the SMS message to. 251 | 252 | #### Example setup 253 | 254 | ```ruby 255 | Broadcast.setup do |config| 256 | config.sms { |sms| 257 | sms.username = 'myaccount' 258 | sms.password = 'mypass' 259 | sms.from = '16025551212' 260 | sms.to = '14801234567' 261 | } 262 | end 263 | ``` 264 | 265 | Copyright 266 | --------- 267 | 268 | Copyright (c) 2011 Marcin Bunsch, Future Simple Inc. See LICENSE for details. 269 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | 4 | require 'bundler' 5 | 6 | Bundler::GemHelper.install_tasks 7 | 8 | import "lib/broadcast/tasks/broadcast.rake" 9 | 10 | begin 11 | 12 | require 'rspec' 13 | require "rspec/core/rake_task" 14 | 15 | desc "Run all examples" 16 | RSpec::Core::RakeTask.new(:spec) do |t| 17 | t.rspec_path = 'bin/rspec' 18 | t.rspec_opts = %w[--color] 19 | t.verbose = false 20 | end 21 | 22 | task :default => [:spec] 23 | 24 | rescue 25 | puts 'Could not load Broadcast RSpec Rake tasks' 26 | end 27 | 28 | begin 29 | 30 | namespace :spec do 31 | 32 | task :cleanup do 33 | rm_rf 'coverage.data' 34 | end 35 | 36 | RSpec::Core::RakeTask.new :rcov do |t| 37 | t.rcov = true 38 | t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,features"] 39 | t.verbose = false 40 | end 41 | 42 | end 43 | 44 | rescue 45 | puts 'Could not load Broadcast RSpec Rcov Rake tasks' 46 | end 47 | -------------------------------------------------------------------------------- /broadcast.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "broadcast/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "broadcast" 7 | s.version = Broadcast::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Marcin Bunsch", "Antek Piechnik"] 10 | s.email = ["marcin@futuresimple.com"] 11 | s.homepage = "http://github.com/futuresimple/broadcast" 12 | s.summary = %q{A broadcasting microframework making publishing of messages to different services easy} 13 | s.description = %q{A broadcasting microframework making publishing of messages to different services easy} 14 | 15 | s.add_dependency 'hashie' 16 | 17 | # 'Externalable' dependencies 18 | s.add_dependency 'oauth' 19 | s.add_dependency 'xmpp4r' 20 | s.add_dependency 'mail' 21 | s.add_dependency 'broach' 22 | s.add_dependency 'shout-bot' 23 | s.add_dependency 'koala' 24 | s.add_dependency 'smsified' 25 | 26 | s.files = `git ls-files`.split("\n") 27 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 28 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 29 | s.require_paths = ["lib"] 30 | end 31 | -------------------------------------------------------------------------------- /lib/broadcast.rb: -------------------------------------------------------------------------------- 1 | require 'logger' 2 | require 'hashie' 3 | 4 | class Broadcast 5 | 6 | ROOT = File.dirname(__FILE__) 7 | 8 | class << self 9 | attr_accessor :logger 10 | attr_accessor :configuration 11 | end 12 | 13 | # Basic configuration object 14 | require 'broadcast/config' 15 | self.configuration = Broadcast::Config.new 16 | 17 | # Default 18 | self.logger = Logger.new($stdout) 19 | 20 | def self.publish(type, options = {}) 21 | name = type.to_s.strip.split("_").collect(&:capitalize).join('') 22 | message = Broadcast::Message.const_get(name).new 23 | message.publish 24 | message 25 | end 26 | 27 | def self.setup(&block) 28 | block.call(self.configuration) 29 | end 30 | 31 | end 32 | 33 | require 'broadcast/publishable' 34 | require 'broadcast/medium' 35 | require 'broadcast/message' 36 | 37 | -------------------------------------------------------------------------------- /lib/broadcast/config.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Config 2 | 3 | # Allow usage of namespaces in config 4 | def method_missing(meth, *args, &block) 5 | @namespaces ||= {} 6 | stringified = meth.to_s 7 | if stringified[-1].chr == '=' and args.first 8 | key = stringified[0..-2].to_sym 9 | @namespaces[key] = args.first 10 | elsif block 11 | key = stringified[0..-1].to_sym 12 | @namespaces[key] ||= Hashie::Mash.new 13 | block.call(@namespaces[key]) 14 | else 15 | key = stringified[0..-1].to_sym 16 | @namespaces[key] ||= Hashie::Mash.new 17 | end 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /lib/broadcast/media/campfire.rb: -------------------------------------------------------------------------------- 1 | require 'broach' 2 | 3 | class Broadcast::Medium::Campfire < Broadcast::Medium 4 | 5 | def publish(message) 6 | Broach.settings = { 'account' => options.subdomain, 'token' => options.token, 'use_ssl' => true } 7 | Broach.speak(options.room, message.body) 8 | end 9 | 10 | end 11 | -------------------------------------------------------------------------------- /lib/broadcast/media/email.rb: -------------------------------------------------------------------------------- 1 | require 'mail' 2 | 3 | class Broadcast::Medium::Email < Broadcast::Medium 4 | 5 | def publish(message) 6 | recipients = options.recipients.is_a?(Array) ? options.recipients : [options.recipients] 7 | options = self.options 8 | recipients.compact.each do |recipient| 9 | mail = Mail.new do 10 | from options.sender || message.class.to_s 11 | to recipient 12 | subject message.subject || message.class.to_s 13 | body message.body 14 | end 15 | if options.delivery_method 16 | # ensure the delivery options has symbolized keys 17 | # Addresses https://github.com/futuresimple/broadcast/issues/9 18 | delivery_options = options.delivery_options.inject({}) do |memo, setting| 19 | memo[setting[0].to_s.to_sym] = setting[1] 20 | memo 21 | end 22 | mail.delivery_method options.delivery_method, delivery_options || {} 23 | end 24 | mail.deliver 25 | end 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /lib/broadcast/media/facebook.rb: -------------------------------------------------------------------------------- 1 | require 'koala' 2 | 3 | class Broadcast::Medium::Facebook < Broadcast::Medium 4 | 5 | def publish(message) 6 | # We do not rescue any Koala exceptions to make them crash the sendout 7 | # This should make debugging easier i.e. when fb has privilege issues 8 | 9 | # Connect to facebook and get info about current user 10 | graph = Koala::Facebook::GraphAPI.new(options.token) 11 | me = graph.get_object('me') 12 | # Get the connections to retrieve the appropriate page 13 | connections = graph.get_connections(me['id'], 'accounts') 14 | raise "No pages available" if connections.size == 0 15 | 16 | # Find the page to post to 17 | page = connections.find { |connection| connection['name'] == options.page } 18 | raise 'Page not found' if !page 19 | 20 | # Create a new graph so that the page posts to itself 21 | page_graph = Koala::Facebook::GraphAPI.new(page['access_token']) 22 | page_graph.put_wall_post(message.body) 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/broadcast/media/irc.rb: -------------------------------------------------------------------------------- 1 | require 'shout-bot' 2 | 3 | class Broadcast::Medium::Irc < Broadcast::Medium 4 | def publish(message) 5 | uri = "irc://#{options.username}" 6 | 7 | uri += "@#{options.server}:#{options.port ? options.port : '6667'}" 8 | uri += "/##{options.channel.to_s.gsub("#","") }" 9 | 10 | ShoutBot.shout(uri) { |room| room.say message } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/broadcast/media/jabber.rb: -------------------------------------------------------------------------------- 1 | require 'xmpp4r' 2 | 3 | class Broadcast::Medium::Jabber < Broadcast::Medium 4 | 5 | class Client 6 | 7 | attr_accessor :client 8 | 9 | def initialize(username, password, server = nil, port = 5222) 10 | @jid = Jabber::JID::new(username) 11 | @client = Jabber::Client::new(@jid) 12 | client.connect(server, port) 13 | client.auth(password) 14 | end 15 | 16 | def deliver(recipient, body) 17 | client.send Jabber::Message::new(recipient, body) 18 | end 19 | 20 | end 21 | 22 | def jabber 23 | @jabber ||= Client.new(options.username, options.password, options.server) 24 | end 25 | 26 | def publish(message) 27 | recipients = options.recipients.is_a?(Array) ? options.recipients : [options.recipients] 28 | recipients.compact.each do |recipient| 29 | jabber.deliver(recipient, message.body) 30 | end 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /lib/broadcast/media/log.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Medium::Log < Broadcast::Medium 2 | 3 | def publish(message) 4 | Logger.new(options.file).info(message.body) 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /lib/broadcast/media/oauth.rb: -------------------------------------------------------------------------------- 1 | require 'oauth' 2 | 3 | class Broadcast::Medium::Oauth < Broadcast::Medium 4 | 5 | class << self 6 | attr_accessor :site 7 | end 8 | 9 | def consumer 10 | @consumer ||= OAuth::Consumer.new(options.consumer_key, options.consumer_secret, :site => self.class.site) 11 | end 12 | 13 | def token 14 | @access_token ||= OAuth::AccessToken.new(consumer, options.access_token, options.access_secret) 15 | end 16 | 17 | def authorize 18 | unless options.consumer_key 19 | print "Enter consumer key: " 20 | options.consumer_key = $stdin.gets.chomp 21 | end 22 | unless options.consumer_secret 23 | print "Enter consumer secret: " 24 | options.consumer_secret = $stdin.gets.chomp 25 | end 26 | request_token = consumer.get_request_token 27 | puts "\nGo to this url and click 'Authorize' to get the token:" 28 | puts request_token.authorize_url 29 | print "\nEnter token: " 30 | token = $stdin.gets.chomp 31 | 32 | access_token = request_token.get_access_token(:oauth_verifier => token) 33 | 34 | puts "\nAuthorization complete! Put the following in your Broadcast configuration file:\n\n" 35 | puts "Broadcast.setup do |config|\n\n" 36 | puts " config.#{namespace}.consumer_key = '#{consumer.key}'" 37 | puts " config.#{namespace}.consumer_secret = '#{consumer.secret}'" 38 | puts " config.#{namespace}.access_token = '#{access_token.token}'" 39 | puts " config.#{namespace}.access_secret = '#{access_token.secret}'" 40 | puts "\nend" 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /lib/broadcast/media/sms.rb: -------------------------------------------------------------------------------- 1 | require 'smsified' 2 | 3 | class Broadcast::Medium::Sms < Broadcast::Medium 4 | 5 | def publish(message) 6 | 7 | oneapi = Smsified::OneAPI.new :username => options.username, 8 | :password => options.password 9 | 10 | oneapi.send_sms :address => options.to, 11 | :message => message.body, 12 | :sender_address => options.from 13 | 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /lib/broadcast/media/tumblr.rb: -------------------------------------------------------------------------------- 1 | # This integration was originally prepared by https://github.com/hmaddocks 2 | require 'net/http' 3 | 4 | class Broadcast::Medium::Tumblr < Broadcast::Medium::Oauth 5 | 6 | self.site = "http://www.tumblr.com" 7 | 8 | def publish(message) 9 | @consumer = OAuth::Consumer.new(options.consumer_key, 10 | options.consumer_secret, 11 | :site => "http://api.tumblr.com") 12 | 13 | params = { 14 | "state" => "published", 15 | "title" => message.subject, 16 | "body" => message.body, 17 | } 18 | 19 | token.post "/v2/blog/#{options.hostname}/post", params 20 | end 21 | 22 | end -------------------------------------------------------------------------------- /lib/broadcast/media/twitter.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Medium::Twitter < Broadcast::Medium::Oauth 2 | 3 | self.site = "https://api.twitter.com" 4 | 5 | def publish(message) 6 | token.post '/1.1/statuses/update.json', { :status => message.body } 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/broadcast/media/yammer.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Medium::Yammer < Broadcast::Medium::Oauth 2 | 3 | self.site = "https://www.yammer.com" 4 | 5 | def publish(message) 6 | token.post '/api/v1/messages.json', { :body => message.body } 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/broadcast/medium.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Medium 2 | 3 | # Set up autoload for the media 4 | Dir.glob(File.join(Broadcast::ROOT, 'broadcast', 'media', '*')).each do |file| 5 | name = File.basename(file).split('.').first 6 | autoload name.capitalize.to_sym, file 7 | end 8 | 9 | def initialize(options = {}) 10 | # load in the configuration from Broadcast setup 11 | @options = Broadcast.configuration.send(namespace) || Hashie::Mash.new 12 | # Override the configuration using the supplied options 13 | @options = @options.merge(options) 14 | end 15 | 16 | def namespace 17 | @namespace ||= self.class.name.split('::').last.downcase.to_sym 18 | end 19 | 20 | def options 21 | @options 22 | end 23 | 24 | def publish(message) 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /lib/broadcast/message.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Message 2 | autoload "Simple", "broadcast/simple" 3 | include Broadcast::Publishable 4 | 5 | # Make the options Hashie::Mash a specific trait of Broadcast::Message 6 | attr_accessor :options 7 | 8 | def initialize(options = {}) 9 | @options = Hashie::Mash.new(options) 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /lib/broadcast/publishable.rb: -------------------------------------------------------------------------------- 1 | # Module which allows any class to be turned into a message 2 | module Broadcast::Publishable 3 | 4 | def self.included(base) 5 | base.extend ClassMethods 6 | end 7 | 8 | module ClassMethods 9 | 10 | attr_accessor :media 11 | 12 | def medium(name, options = {}) 13 | (self.media ||= []).push({ :name => name, :options => options }) 14 | end 15 | 16 | end 17 | 18 | def publish 19 | (self.class.media || []).each do |medium| 20 | begin 21 | Broadcast::Medium.const_get(medium[:name].to_s.downcase.capitalize).new(medium[:options]).publish(self) 22 | rescue 23 | Broadcast.logger.error "Publishing of #{self.class.name} to #{medium[:name]} failed:\n#{$!}" 24 | end 25 | end 26 | end 27 | 28 | def subject 29 | end 30 | 31 | def body 32 | "" 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /lib/broadcast/railtie.rb: -------------------------------------------------------------------------------- 1 | require 'rails/railtie' 2 | 3 | class Broadcast 4 | 5 | class Railtie < Rails::Railtie 6 | rake_tasks do 7 | load 'broadcast/tasks/broadcast.rake' 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /lib/broadcast/simple.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Message::Simple < Broadcast::Message 2 | 3 | attr_accessor :body, :subject 4 | 5 | def body 6 | @body || options.body 7 | end 8 | 9 | def subject 10 | @subject || options.subject 11 | end 12 | 13 | def publish(medium, medium_arguments = {}) 14 | begin 15 | Broadcast::Medium.const_get(medium.to_s.downcase.capitalize).new(medium_arguments).publish(self) 16 | rescue 17 | Broadcast.logger.error "Publishing of #{self.class.name} to #{medium} failed:\n#{$!}" 18 | end 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /lib/broadcast/tasks/broadcast.rake: -------------------------------------------------------------------------------- 1 | namespace "broadcast" do 2 | 3 | namespace "authorize" do 4 | 5 | desc "Authorize Broadcast with Yammer and get access token information" 6 | task "yammer" do 7 | require 'broadcast' 8 | Broadcast::Medium::Yammer.new.authorize 9 | end 10 | 11 | desc "Authorize Broadcast with Twitter and get access token information" 12 | task "twitter" do 13 | require 'broadcast' 14 | Broadcast::Medium::Twitter.new.authorize 15 | end 16 | 17 | desc "Authorize Broadcast with Tumblr and get access token information" 18 | task "tumblr" do 19 | require 'broadcast' 20 | Broadcast::Medium::Tumblr.new.authorize 21 | end 22 | 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/broadcast/version.rb: -------------------------------------------------------------------------------- 1 | class Broadcast 2 | 3 | VERSION = "0.3.0" 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/campfire_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Campfire do 4 | 5 | describe '#publish' do 6 | 7 | before do 8 | @medium = Broadcast::Medium::Campfire.new 9 | @message = Broadcast::Message::SpecWithContent.new 10 | end 11 | 12 | it "should send a post request to the campfire API with the message body" do 13 | Broach.should_receive(:speak).with("My Room", 'message') 14 | @medium.publish(@message) 15 | end 16 | 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/email_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Email do 4 | 5 | describe '#publish' do 6 | 7 | before { 8 | @medium = Broadcast::Medium::Email.new 9 | @message = Broadcast::Message::SpecWithContent.new 10 | Mail::TestMailer.deliveries = [] 11 | } 12 | 13 | it "should deliver the message to one recipient if options.recipients is a string" do 14 | @medium.publish(@message) 15 | Mail::TestMailer.deliveries.size.should == 1 16 | Mail::TestMailer.deliveries.first.to.should == ['foo@moo.com'] 17 | end 18 | 19 | it "should deliver the message to many recipients if options.recipients is a array" do 20 | @medium.options.recipients = ['mike@foo.com', 'tom@foo.com'] 21 | @medium.publish(@message) 22 | Mail::TestMailer.deliveries.size.should == 2 23 | Mail::TestMailer.deliveries.first.to.should == ['mike@foo.com'] 24 | Mail::TestMailer.deliveries.last.to.should == ['tom@foo.com'] 25 | end 26 | 27 | it "should properly get delivery_options and set delivery method" do 28 | @medium.options.delivery_method = :smtp 29 | mail = Mail.new 30 | # 'nueter' the mail instance 31 | def mail.deliver; end 32 | Mail.should_receive(:new).and_return(mail) 33 | @medium.publish(@message) 34 | mail.delivery_method.settings[:user_name].should == '' 35 | mail.delivery_method.settings[:password].should == '' 36 | mail.delivery_method.settings[:address].should == 'smtp.gmail.com' 37 | end 38 | 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/facebook_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Facebook do 4 | 5 | describe '.new' do 6 | 7 | it "should create a new instance with options provided in config" do 8 | medium = Broadcast::Medium::Facebook.new 9 | medium.options.token.should == 'fb_token' 10 | medium.options.page.should == 'My Page' 11 | end 12 | 13 | it "should prioritize options argument over options provided in config" do 14 | medium = Broadcast::Medium::Facebook.new(:page => 'Different Page') 15 | medium.options.token.should == 'fb_token' 16 | medium.options.page.should == 'Different Page' 17 | end 18 | 19 | end 20 | 21 | describe '#publish' do 22 | 23 | before do 24 | @medium = Broadcast::Medium::Facebook.new 25 | @message = Broadcast::Message::SpecWithChagingContent.new 26 | @me = {"name"=>"Your Name", "username"=>"yourname", "timezone"=>0, "gender"=>"male", "id"=>"1", "last_name"=>"Name", "updated_time"=>"2011-06-01T17:29:02+0000", "verified"=>true, "locale"=>"en_US", "hometown"=>{"name"=>"Palo Alto", "id"=>"1"}, "link"=>"http://www.facebook.com/yourname", "first_name"=>"Your"} 27 | @connections = [{"name"=>"My Page", "category"=>"Software", "id"=>"123", "access_token"=>"page_access_token"}] 28 | end 29 | 30 | it "should send the message to a Facebook page" do 31 | mock_graph = mock 32 | mock_page_graph = mock 33 | Koala::Facebook::GraphAPI.should_receive(:new).with('fb_token').and_return(mock_graph) 34 | Koala::Facebook::GraphAPI.should_receive(:new).with('page_access_token').and_return(mock_page_graph) 35 | mock_graph.should_receive(:get_object).with('me').and_return(@me) 36 | mock_graph.should_receive(:get_connections).with('1', 'accounts').and_return(@connections) 37 | 38 | mock_page_graph.should_receive(:put_wall_post).with(@message.body) 39 | @medium.publish(@message) 40 | end 41 | 42 | it "should raise an error when no pages are available" do 43 | mock_graph = mock 44 | mock_page_graph = mock 45 | Koala::Facebook::GraphAPI.should_receive(:new).with('fb_token').and_return(mock_graph) 46 | mock_graph.should_receive(:get_object).with('me').and_return(@me) 47 | mock_graph.should_receive(:get_connections).with('1', 'accounts').and_return([]) 48 | 49 | lambda { @medium.publish(@message) }.should raise_error('No pages available') 50 | end 51 | 52 | it "should raise an error when no page was not found" do 53 | mock_graph = mock 54 | mock_page_graph = mock 55 | Koala::Facebook::GraphAPI.should_receive(:new).with('fb_token').and_return(mock_graph) 56 | mock_graph.should_receive(:get_object).with('me').and_return(@me) 57 | 58 | @connections.first['name'] = 'Different name' 59 | mock_graph.should_receive(:get_connections).with('1', 'accounts').and_return(@connections) 60 | 61 | lambda { @medium.publish(@message) }.should raise_error('Page not found') 62 | end 63 | 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/irc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Irc do 4 | 5 | describe '.new' do 6 | 7 | it "should create a new instance with options provided in config" do 8 | medium = Broadcast::Medium::Irc.new 9 | medium.options.username.should == 'foo' 10 | medium.options.server.should == 'irc.freenode.net' 11 | medium.options.port.should == '6667' 12 | medium.options.channel.should == 'broadcast' 13 | end 14 | 15 | it "should prioritize options argument over options provided in config" do 16 | medium = Broadcast::Medium::Jabber.new(:username => 'someoneelse', :server => 'irc.otherfreenode.net', :port => '6666', :channel => 'newchannel') 17 | medium.options.username.should == 'someoneelse' 18 | medium.options.server.should == 'irc.otherfreenode.net' 19 | medium.options.port.should == '6666' 20 | medium.options.channel.should == 'newchannel' 21 | end 22 | 23 | end 24 | 25 | describe '#publish' do 26 | 27 | before do 28 | @medium = Broadcast::Medium::Irc.new 29 | @message = Broadcast::Message::SpecWithContent.new 30 | end 31 | 32 | it "should send the message to IRC channels with the message body" do 33 | ShoutBot.should_receive(:shout).with("irc://foo@irc.freenode.net:6667/#broadcast") 34 | @medium.publish(@message) 35 | end 36 | 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/jabber_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Jabber do 4 | 5 | # 'nueter' the Jabber::Client 6 | class Jabber::Client 7 | def connect(*args); end 8 | def auth(*args); end 9 | def send(*args); end 10 | end 11 | 12 | describe '::Client' do 13 | 14 | before { 15 | @client = Broadcast::Medium::Jabber::Client.new('foo@foo.com', '123') 16 | } 17 | 18 | describe '.new' do 19 | 20 | it "should create a new Jabber::Client and connect to jabber" do 21 | @client.client.should be_an_instance_of Jabber::Client 22 | end 23 | 24 | end 25 | 26 | describe 'deliver' do 27 | 28 | it "should use the client to send a message" do 29 | @client.client.should_receive(:send) 30 | @client.deliver('mike@foo.com', 'Hi') 31 | end 32 | 33 | end 34 | 35 | end 36 | 37 | describe '.new' do 38 | 39 | it "should create a new instance with options provided in config" do 40 | medium = Broadcast::Medium::Jabber.new 41 | medium.options.username.should == 'foo@foo.com' 42 | medium.options.password.should == 'mypass' 43 | end 44 | 45 | it "should prioritize options argument options provided in config" do 46 | medium = Broadcast::Medium::Jabber.new(:username => 'someoneelse@foo.com', :password => 'elsepass') 47 | medium.options.username.should == 'someoneelse@foo.com' 48 | medium.options.password.should == 'elsepass' 49 | end 50 | 51 | end 52 | 53 | describe '#jabber' do 54 | 55 | it "should instantiate a new Broadcast::Medium::Jabber::Client instance" do 56 | jabber = Broadcast::Medium::Jabber.new.jabber 57 | jabber.should be_an_instance_of(Broadcast::Medium::Jabber::Client) 58 | end 59 | 60 | it "should memoize the Broadcast::Medium::Jabber::Client instance" do 61 | medium = Broadcast::Medium::Jabber.new 62 | jabber = medium.jabber 63 | medium.jabber.object_id.should == jabber.object_id 64 | end 65 | 66 | end 67 | 68 | describe '#publish' do 69 | 70 | before { 71 | @medium = Broadcast::Medium::Jabber.new(:username => 'foo@foo.com', :password => 'passkey') 72 | @message = Broadcast::Message::SpecWithContent.new 73 | @jabber = mock 74 | @medium.stub!(:jabber).and_return(@jabber) 75 | } 76 | 77 | it "should deliver the message to one recipient if options.recipients is a string" do 78 | @jabber.should_receive(:deliver).with('mike@foo.com', "message") 79 | @medium.publish(@message) 80 | end 81 | 82 | it "should deliver the message to many recipients if options.recipients is a array" do 83 | @medium.options.recipients = ['mike@foo.com', 'tom@foo.com'] 84 | @jabber.should_receive(:deliver).with('mike@foo.com', "message") 85 | @jabber.should_receive(:deliver).with('tom@foo.com', "message") 86 | @medium.publish(@message) 87 | end 88 | 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/log_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Log do 4 | 5 | before do 6 | Broadcast.configuration.log.file = nil 7 | end 8 | 9 | describe '#publish' do 10 | 11 | it "should send message to logfile if it was defined on class level" do 12 | log = StringIO.new 13 | Broadcast.configuration.log.file = log 14 | message = Broadcast::Message::SpecWithContent.new 15 | Broadcast::Medium::Log.new.publish(message) 16 | log.rewind 17 | log.read.should match(message.body) 18 | end 19 | 20 | it "should send message to logfile if it was defined in options" do 21 | log = StringIO.new 22 | message = Broadcast::Message::SpecWithContent.new 23 | Broadcast::Medium::Log.new(:file => log).publish(message) 24 | log.rewind 25 | log.read.should match(message.body) 26 | end 27 | 28 | it "should look at options first before class when looking for file" do 29 | log_default = StringIO.new 30 | log_options = StringIO.new 31 | Broadcast.configuration.log.file = log_default 32 | 33 | message = Broadcast::Message::SpecWithContent.new 34 | Broadcast::Medium::Log.new(:file => log_options).publish(message) 35 | log_options.rewind 36 | log_options.read.should match(message.body) 37 | log_default.rewind 38 | log_default.read.should == '' 39 | end 40 | 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/oauth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Oauth do 4 | 5 | before do 6 | Broadcast::Medium::Oauth.site = nil 7 | end 8 | 9 | describe '.consumer' do 10 | 11 | before do 12 | Broadcast::Medium::Oauth.site = 'http://site.com' 13 | end 14 | 15 | it "should return consumer object with proper keys and site" do 16 | consumer = Broadcast::Medium::Oauth.new.consumer 17 | consumer.should be_an_instance_of(OAuth::Consumer) 18 | consumer.key.should == 'consumerkey' 19 | consumer.secret.should == 'consumersecret' 20 | end 21 | 22 | it "should memoize the consumer object" do 23 | medium = Broadcast::Medium::Oauth.new 24 | consumer = medium.consumer 25 | medium.consumer.object_id.should == consumer.object_id 26 | end 27 | 28 | end 29 | 30 | describe '#token' do 31 | 32 | before do 33 | Broadcast::Medium::Oauth.site = 'http://site.com' 34 | end 35 | 36 | it "should return access token object with proper access token keys" do 37 | token = Broadcast::Medium::Oauth.new.token 38 | token.should be_an_instance_of(OAuth::AccessToken) 39 | token.token.should == 'accesstoken' 40 | token.secret.should == 'accesssecret' 41 | end 42 | 43 | it "should memoize the access token" do 44 | medium = Broadcast::Medium::Oauth.new 45 | token = medium.token 46 | medium.token.object_id.should == token.object_id 47 | end 48 | 49 | it "should prioritize options argument over class level options" do 50 | token = Broadcast::Medium::Oauth.new(:access_token => 'overridetoken', :access_secret => 'overridesecret').token 51 | token.should be_an_instance_of(OAuth::AccessToken) 52 | token.token.should == 'overridetoken' 53 | token.secret.should == 'overridesecret' 54 | end 55 | 56 | end 57 | 58 | describe '.authorize' do 59 | 60 | before do 61 | Broadcast.configuration.oauth.consumer_key = nil 62 | Broadcast.configuration.oauth.consumer_secret = nil 63 | Broadcast::Medium::Oauth.site = 'http://site.com' 64 | 65 | medium = Broadcast::Medium::Oauth.new 66 | 67 | @request_token = mock 68 | @stdout = StringIO.new 69 | @old_stdout, $stdout = $stdout, @stdout 70 | 71 | $stdin.should_receive(:gets).and_return('consumerkey123') 72 | $stdin.should_receive(:gets).and_return('consumersecret123') 73 | $stdin.should_receive(:gets).and_return('12342') 74 | 75 | @request_token.should_receive(:authorize_url).and_return('http://foo.com/1234') 76 | medium.consumer.stub!(:get_request_token).and_return(@request_token) 77 | 78 | @access_token = mock(:token => '6789', :secret => '3456') 79 | @request_token.should_receive(:get_access_token).and_return(@access_token) 80 | 81 | medium.authorize 82 | 83 | medium.options.consumer_key.should == 'consumerkey123' 84 | medium.options.consumer_secret.should == 'consumersecret123' 85 | $stdout = @old_stdout 86 | @stdout.rewind 87 | end 88 | 89 | it "should use the request token to get the url the user goes to" do 90 | @stdout.read.should match('http://foo.com/1234') 91 | end 92 | 93 | it "should get the oauth_verifier from the user" do 94 | @stdout.read.should match('Enter token') 95 | end 96 | 97 | it "should print out the lines the user should put in the config file" do 98 | out = @stdout.read 99 | out.should match('Put the following in your Broadcast configuration file:') 100 | out.should match('config.oauth.consumer_key') 101 | out.should match('config.oauth.consumer_secret') 102 | out.should match('config.oauth.access_token') 103 | out.should match('config.oauth.access_secret') 104 | end 105 | 106 | end 107 | 108 | end 109 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/sms_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Sms do 4 | 5 | describe '.new' do 6 | 7 | it "should create a new instance with options provided in config" do 8 | medium = Broadcast::Medium::Sms.new 9 | medium.options.username.should == 'myaccount' 10 | medium.options.password.should == 'mypass' 11 | medium.options.to.should == '22222222222' 12 | end 13 | 14 | it "should prioritize options argument over options provided in config" do 15 | medium = Broadcast::Medium::Sms.new(:to => '33333333333') 16 | medium.options.username.should == 'myaccount' 17 | medium.options.password.should == 'mypass' 18 | medium.options.to.should == '33333333333' 19 | end 20 | 21 | end 22 | 23 | describe '#publish' do 24 | 25 | before do 26 | @mock_client = mock 27 | Smsified::OneAPI.should_receive(:new).with(:username => 'myaccount', :password => 'mypass').and_return(@mock_client) 28 | end 29 | 30 | it "should send the sms" do 31 | message = Broadcast::Message::SpecWithContent.new 32 | @mock_client.should_receive(:send_sms).with({:message=>message.body, :sender_address=>"11111111111", :address=>"22222222222"}) 33 | Broadcast::Medium::Sms.new.publish(message) 34 | end 35 | 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/tumblr_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Tumblr do 4 | 5 | describe '.site' do 6 | 7 | it "should be set to Tumblr OAuth endpoint" do 8 | Broadcast::Medium::Tumblr.site.should == "http://www.tumblr.com" 9 | end 10 | 11 | end 12 | 13 | describe '#publish' do 14 | 15 | it "should send a post to twitter with the message body" do 16 | message = Broadcast::Message::SpecWithContentAndSubject.new 17 | medium = Broadcast::Medium::Tumblr.new 18 | token = mock 19 | params = { 20 | "state" => "published", 21 | "title" => "title", 22 | "body" => "message", 23 | } 24 | token.should_receive(:post).with("/v2/blog/spec.tumblr.com/post", params) 25 | medium.should_receive(:token).and_return(token) 26 | medium.publish(message) 27 | end 28 | 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/twitter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Twitter do 4 | 5 | describe '.site' do 6 | 7 | it "should be set to TwitterO OAuth endpoint" do 8 | Broadcast::Medium::Twitter.site.should == 'http://api.twitter.com' 9 | end 10 | 11 | end 12 | 13 | describe '#publish' do 14 | 15 | it "should send a post to twitter with the message body" do 16 | message = Broadcast::Message::SpecWithContent.new 17 | medium = Broadcast::Medium::Twitter.new 18 | token = mock 19 | token.should_receive(:post).with("/1/statuses/update.json", {:status=>"message"}) 20 | medium.should_receive(:token).and_return(token) 21 | medium.publish(message) 22 | end 23 | 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/lib/broadcast/media/yammer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium::Yammer do 4 | 5 | describe '.site' do 6 | 7 | it "should be set to Yammer OAuth endpoint" do 8 | Broadcast::Medium::Yammer.site.should == 'https://www.yammer.com' 9 | end 10 | 11 | end 12 | 13 | describe '#publish' do 14 | 15 | it "should send a post to yammer with the message body" do 16 | message = Broadcast::Message::SpecWithContent.new 17 | medium = Broadcast::Medium::Yammer.new 18 | token = mock 19 | token.should_receive(:post).with("/api/v1/messages.json", { :body=>"message" }) 20 | medium.should_receive(:token).and_return(token) 21 | medium.publish(message) 22 | end 23 | 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/lib/broadcast/medium_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Medium do 4 | 5 | describe '#publish' do 6 | 7 | before do 8 | @medium = Broadcast::Medium::Spec.new 9 | @message = Broadcast::Message::Spec.new 10 | end 11 | 12 | it "should properly load options" do 13 | @medium.options.option.should == 1 14 | end 15 | 16 | it "should accept 1 argument" do 17 | lambda { 18 | @medium.publish(@message) 19 | }.should_not raise_error(ArgumentError) 20 | end 21 | 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /spec/lib/broadcast/message_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Message do 4 | 5 | before do 6 | Broadcast::Message::Spec.media = [] 7 | @log = StringIO.new 8 | Broadcast.logger = Logger.new(@log) 9 | end 10 | 11 | describe ".initialize" do 12 | 13 | it "should accept options" do 14 | msg = Broadcast::Message::Spec.new(:foo => 1) 15 | msg.options.foo.should == 1 16 | end 17 | 18 | end 19 | 20 | describe ".medium" do 21 | 22 | it "should add a medium to media" do 23 | Broadcast::Message::Spec.medium :spec 24 | Broadcast::Message::Spec.media.size.should == 1 25 | Broadcast::Message::Spec.media.first[:name].should == :spec 26 | end 27 | 28 | it "should allow adding of options" do 29 | Broadcast::Message::Spec.medium :spec, :option => 1 30 | Broadcast::Message::Spec.media.size.should == 1 31 | Broadcast::Message::Spec.media.first[:name].should == :spec 32 | Broadcast::Message::Spec.media.first[:options].should == { :option => 1 } 33 | end 34 | 35 | end 36 | 37 | describe "#body" do 38 | 39 | it "should be empty by default" do 40 | Broadcast::Message::Spec.new.body.should == '' 41 | end 42 | 43 | end 44 | 45 | describe '#publish' do 46 | 47 | it "should properly load all media of the message" do 48 | Broadcast::Message::Spec.medium :spec 49 | Broadcast::Message::Spec.new.publish 50 | end 51 | 52 | it "should properly instantiate all media of the message" do 53 | medium = mock 54 | medium.should_receive(:publish) 55 | Broadcast::Medium::Spec.should_receive(:new).once.and_return(medium) 56 | Broadcast::Message::Spec.medium :spec 57 | Broadcast::Message::Spec.new.publish 58 | end 59 | 60 | it "should send to logger if medium instantiation fails" do 61 | medium = mock 62 | medium.should_receive(:publish).and_raise 'Some Exception' 63 | Broadcast::Medium::Spec.should_receive(:new).once.and_return(medium) 64 | Broadcast::Message::Spec.medium :spec 65 | lambda { 66 | Broadcast::Message::Spec.new.publish 67 | }.should_not raise_error 68 | @log.rewind 69 | @log.read.should match('Publishing of Broadcast::Message::Spec to spec failed:\nSome Exception') 70 | end 71 | 72 | end 73 | 74 | end 75 | -------------------------------------------------------------------------------- /spec/lib/broadcast/publishable_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | class ClassToBecomeMessage 4 | include Broadcast::Publishable 5 | 6 | attr_accessor :something 7 | 8 | def initialize(somthng = nil) 9 | self.something = somthng 10 | end 11 | 12 | end 13 | 14 | describe Broadcast::Publishable do 15 | 16 | describe "in class scope" do 17 | 18 | it "should add the media accessor" do 19 | ClassToBecomeMessage.should respond_to(:media) 20 | ClassToBecomeMessage.should respond_to(:media=) 21 | end 22 | 23 | it "should add the medium method" do 24 | ClassToBecomeMessage.should respond_to(:medium) 25 | end 26 | 27 | end 28 | 29 | describe "in instance scope" do 30 | 31 | before { 32 | @instance = ClassToBecomeMessage.new(123) 33 | } 34 | it "should add the publish method" do 35 | @instance.should respond_to(:publish) 36 | end 37 | 38 | it "should add the subject method" do 39 | @instance.should respond_to(:subject) 40 | end 41 | 42 | it "should add the body method" do 43 | @instance.should respond_to(:body) 44 | end 45 | 46 | it "should not add the options accessor" do 47 | @instance.should_not respond_to(:options) 48 | @instance.should_not respond_to(:options=) 49 | end 50 | 51 | it "should not mess with the initializer" do 52 | ClassToBecomeMessage.new(123).something.should == 123 53 | end 54 | 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /spec/lib/broadcast/simple_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Broadcast::Message::Simple do 4 | 5 | before do 6 | @message = Broadcast::Message::Simple.new(:body => 'my body', :subject => 'OMG!') 7 | end 8 | 9 | describe ".initialize" do 10 | 11 | it "should accept options" do 12 | Broadcast::Message::Simple.new(:body => 'my body', :subject => 'OMG!') 13 | end 14 | 15 | end 16 | 17 | describe "#body and #subject accessors" do 18 | 19 | describe "#body" do 20 | 21 | it "should be the value sent to the initializer" do 22 | @message.body.should == 'my body' 23 | end 24 | 25 | end 26 | 27 | describe "#body=" do 28 | 29 | it "should allow changing the value of body dynamically" do 30 | @message.body = 'updated body' 31 | @message.body.should == 'updated body' 32 | end 33 | 34 | end 35 | 36 | describe "#subject" do 37 | 38 | it "should be the value sent to the initializer" do 39 | @message.subject.should == 'OMG!' 40 | end 41 | 42 | end 43 | 44 | describe "#subject=" do 45 | 46 | it "should be the value sent to the initializer" do 47 | @message.subject = 'LOL' 48 | @message.subject.should == 'LOL' 49 | end 50 | 51 | end 52 | 53 | end 54 | 55 | describe '#publish' do 56 | 57 | it "should explode when no media is supplied" do 58 | lambda { 59 | @message.publish 60 | }.should raise_error(ArgumentError) 61 | end 62 | 63 | it "should publish to the media passed as first argument" do 64 | mocked = mock 65 | mocked.should_receive(:publish).with(@message) 66 | Broadcast::Medium::Log.should_receive(:new).and_return(mocked) 67 | @message.publish :log 68 | end 69 | 70 | it "should override media settings if provided as second argument" do 71 | mocked = mock 72 | mocked.should_receive(:publish).with(@message) 73 | Broadcast::Medium::Log.should_receive(:new).with(:file => 'different.log').and_return(mocked) 74 | @message.publish :log, :file => 'different.log' 75 | end 76 | 77 | end 78 | 79 | end 80 | -------------------------------------------------------------------------------- /spec/lib/broadcast_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | ORIGINAL_CONFIG = Broadcast.configuration 4 | 5 | describe Broadcast do 6 | 7 | describe '.publish' do 8 | 9 | it "should properly load the message class and instantiate the message" do 10 | msg = mock(:publish => true) 11 | Broadcast::Message::Spec.should_receive(:new).once.and_return(msg) 12 | Broadcast.publish(:spec) 13 | end 14 | 15 | it "should properly load the message class if in camelcase and instantiate the message" do 16 | msg = mock(:publish => true) 17 | Broadcast::Message::SpecWithContent.should_receive(:new).once.and_return(msg) 18 | Broadcast.publish(:spec_with_content) 19 | end 20 | 21 | it "should call publish on the message" do 22 | msg = mock 23 | msg.should_receive(:publish) 24 | Broadcast::Message::Spec.should_receive(:new).once.and_return(msg) 25 | Broadcast.publish(:spec) 26 | end 27 | 28 | end 29 | 30 | describe '.setup' do 31 | 32 | before { 33 | Broadcast.configuration = ORIGINAL_CONFIG 34 | } 35 | 36 | it "should allow setting of single settings" do 37 | Broadcast.setup { |config| 38 | config.some_setting = 1 39 | } 40 | Broadcast.configuration.should be_an_instance_of(Broadcast::Config) 41 | Broadcast.configuration.some_setting.should == 1 42 | end 43 | 44 | it "should allow setting of namespaced settings" do 45 | Broadcast.setup { |config| 46 | config.log.some_setting = 1 47 | } 48 | Broadcast.configuration.log.should be_an_instance_of(Hashie::Mash) 49 | Broadcast.configuration.log.some_setting.should == 1 50 | end 51 | 52 | it "should allow setting of namespaced settings using a block" do 53 | Broadcast.setup { |config| 54 | config.log { |log| 55 | log.file = "foo.log" 56 | log.color = 'red' 57 | } 58 | } 59 | Broadcast.configuration.log.should be_an_instance_of(Hashie::Mash) 60 | Broadcast.configuration.log.file.should == 'foo.log' 61 | Broadcast.configuration.log.color.should == 'red' 62 | end 63 | 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../../lib", __FILE__) 2 | require 'broadcast' 3 | require 'rspec' 4 | 5 | $:.push File.expand_path("../..", __FILE__) 6 | Dir.glob('spec/support/*').each { |f| require f } 7 | -------------------------------------------------------------------------------- /spec/support/config.rb: -------------------------------------------------------------------------------- 1 | Broadcast.setup { |config| 2 | config.spec.option = 1 3 | 4 | config.oauth { |oauth| 5 | oauth.consumer_key = 'consumerkey' 6 | oauth.consumer_secret = 'consumersecret' 7 | oauth.access_token = 'accesstoken' 8 | oauth.access_secret = 'accesssecret' 9 | } 10 | 11 | config.jabber { |jabber| 12 | jabber.username = 'foo@foo.com' 13 | jabber.password = 'mypass' 14 | jabber.recipients = 'mike@foo.com' 15 | } 16 | 17 | config.email { |email| 18 | email.recipients = ['foo@moo.com'] 19 | email.delivery_method = :test 20 | email.delivery_options = { 21 | :address => "smtp.gmail.com", 22 | :port => 587, 23 | :domain => 'your.host.name', 24 | :user_name => '', 25 | :password => '', 26 | :authentication => 'plain', 27 | :enable_starttls_auto => true 28 | } 29 | } 30 | 31 | config.campfire { |campfire| 32 | campfire.subdomain = 'myaccount' 33 | campfire.token = 'token' 34 | campfire.room = 'My Room' 35 | } 36 | 37 | config.facebook { |facebook| 38 | facebook.token = 'fb_token' 39 | facebook.page = 'My Page' 40 | } 41 | 42 | config.irc { |irc| 43 | irc.username = 'foo' 44 | irc.server = 'irc.freenode.net' 45 | irc.port = '6667' 46 | irc.channel = 'broadcast' 47 | } 48 | 49 | config.sms { |sms| 50 | sms.username = 'myaccount' 51 | sms.password = 'mypass' 52 | sms.from = '11111111111' 53 | sms.to = '22222222222' 54 | } 55 | 56 | config.tumblr { |tumblr| 57 | 58 | tumblr.hostname = 'spec.tumblr.com' 59 | tumblr.consumer_key = 'consumerkey' 60 | tumblr.consumer_secret = 'consumersecret' 61 | tumblr.access_token = 'accesstoken' 62 | tumblr.access_secret = 'accesssecret' 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /spec/support/examples.rb: -------------------------------------------------------------------------------- 1 | class Broadcast::Message::Spec < Broadcast::Message 2 | end 3 | 4 | class Broadcast::Message::SpecWithContent < Broadcast::Message 5 | def body 6 | "message" 7 | end 8 | end 9 | 10 | class Broadcast::Message::SpecWithContentAndSubject < Broadcast::Message 11 | def subject 12 | "title" 13 | end 14 | def body 15 | "message" 16 | end 17 | end 18 | 19 | class Broadcast::Message::SpecWithChagingContent < Broadcast::Message 20 | def body 21 | "message | " + Time.now.to_s 22 | end 23 | end 24 | 25 | 26 | class Broadcast::Medium::Spec < Broadcast::Medium 27 | end 28 | --------------------------------------------------------------------------------